Added a command-line option -keepLineBreaksICS true/false to control line joining.
[xboard.git] / winboard / winboard.c
index b1aa04b..884c85c 100644 (file)
@@ -1,9 +1,13 @@
-/* \r
+/*\r
  * WinBoard.c -- Windows NT front end to XBoard\r
- * $Id$\r
  *\r
- * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts.\r
- * Enhancements Copyright 1992-2001 Free Software Foundation, Inc.\r
+ * Copyright 1991 by Digital Equipment Corporation, Maynard,\r
+ * Massachusetts. \r
+ *\r
+ * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,\r
+ * 2007, 2008, 2009 Free Software Foundation, Inc.\r
+ *\r
+ * Enhancements Copyright 2005 Alessandro Scotti\r
  *\r
  * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,\r
  * which was written and is copyrighted by Wayne Christopher.\r
  * SOFTWARE.\r
  * ------------------------------------------------------------------------\r
  *\r
- * The following terms apply to the enhanced version of XBoard distributed\r
- * by the Free Software Foundation:\r
+ * The following terms apply to the enhanced version of XBoard\r
+ * distributed by the Free Software Foundation:\r
  * ------------------------------------------------------------------------\r
- * This program is free software; you can redistribute it and/or modify\r
+ *\r
+ * GNU XBoard is free software: you can redistribute it and/or modify\r
  * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation; either version 2 of the License, or\r
- * (at your option) any later version.\r
+ * the Free Software Foundation, either version 3 of the License, or (at\r
+ * your option) any later version.\r
  *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
- * GNU General Public License for more details.\r
+ * GNU XBoard is distributed in the hope that it will be useful, but\r
+ * WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+ * General Public License for more details.\r
  *\r
  * You should have received a copy of the GNU General Public License\r
- * along with this program; if not, write to the Free Software\r
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
- * ------------------------------------------------------------------------\r
- */\r
+ * along with this program. If not, see http://www.gnu.org/licenses/.  *\r
+ *\r
+ *------------------------------------------------------------------------\r
+ ** See the file ChangeLog for a revision history.  */\r
 \r
 #include "config.h"\r
 \r
 #include <windows.h>\r
 #include <winuser.h>\r
 #include <winsock.h>\r
+#include <commctrl.h>\r
 \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
@@ -65,6 +72,7 @@
 #include <dlgs.h>\r
 #include <richedit.h>\r
 #include <mmsystem.h>\r
+#include <ctype.h>\r
 \r
 #if __GNUC__\r
 #include <errno.h>\r
 #include "woptions.h"\r
 #include "wsockerr.h"\r
 #include "defaults.h"\r
-\r
+#include "help.h"\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
+extern HANDLE chatHandle[];\r
+extern int ics_type;\r
+\r
+void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);\r
+VOID NewVariantPopup(HWND hwnd);\r
+int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,\r
+                  /*char*/int promoChar));\r
+void AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames);\r
+void DisplayMove P((int moveNumber));\r
+Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen));\r
+void ChatPopUp P(());\r
 typedef struct {\r
   ChessSquare piece;  \r
   POINT pos;      /* window coordinates of current pos */\r
@@ -109,13 +137,19 @@ typedef struct {
 static HighlightInfo highlightInfo        = { {{-1, -1}, {-1, -1}} };\r
 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };\r
 \r
+typedef struct { // [HGM] atomic\r
+  int fromX, fromY, toX, toY, radius;\r
+} ExplodeInfo;\r
+\r
+static ExplodeInfo explodeInfo;\r
+\r
 /* Window class names */\r
 char szAppName[] = "WinBoard";\r
 char szConsoleName[] = "WBConsole";\r
 \r
 /* Title bar text */\r
 char szTitle[] = "WinBoard";\r
-char szConsoleTitle[] = "ICS Interaction";\r
+char szConsoleTitle[] = "I C S Interaction";\r
 \r
 char *programName;\r
 char *settingsFileName;\r
@@ -124,10 +158,12 @@ char installDir[MSG_SIZ];
 \r
 BoardSize boardSize;\r
 BOOLEAN chessProgram;\r
-static int boardX, boardY, consoleX, consoleY, consoleW, consoleH;\r
-static int squareSize, lineGap;\r
-static int winWidth, winHeight;\r
-static RECT messageRect, whiteRect, blackRect;\r
+static int boardX, boardY;\r
+int  minX, minY; // [HGM] placement: volatile limits on upper-left corner\r
+static int squareSize, lineGap, minorSize;\r
+static int winWidth, winHeight, winW, winH;\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 +176,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,9 +192,11 @@ 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
-  whitePieceBrush, blackPieceBrush, iconBkgndBrush, outlineBrush;\r
+  blackSquareBrush, /* [HGM] for band between board and holdings */\r
+  explodeBrush,     /* [HGM] atomic */\r
+  whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;\r
 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];\r
 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];\r
 static HPEN gridPen = NULL;\r
@@ -170,11 +208,28 @@ static HICON iconWhite, iconBlack, iconCurrent;
 static int doingSizing = FALSE;\r
 static int lastSizing = 0;\r
 static int prevStderrPort;\r
+static HBITMAP userLogo;\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
+#if defined(_winmajor)\r
 #define oldDialog (_winmajor < 4)\r
+#else\r
+#define oldDialog 0\r
+#endif\r
 #endif\r
 \r
 char *defaultTextAttribs[] = \r
@@ -216,63 +271,27 @@ SizeInfo sizeInfo[] =
   { NULL, 0, 0, 0, 0, 0, 0 }\r
 };\r
 \r
-#define MF(x) {x, {0, }, {0, }, 0}\r
+#define MF(x) {x, {{0,}, 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
@@ -297,7 +316,7 @@ MyButtonDesc buttonDesc[N_BUTTONS] =
 };\r
 \r
 int tinyLayout = 0, smallLayout = 0;\r
-#define MENU_BAR_ITEMS 6\r
+#define MENU_BAR_ITEMS 7\r
 char *menuBarText[2][MENU_BAR_ITEMS+1] = {\r
   { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },\r
   { "&F", "&M", "&A", "&S", "&O", "&H", NULL },\r
@@ -398,8 +417,48 @@ 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
+WindowPlacement wpGameList;\r
+WindowPlacement wpConsole;\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 EngineOptionsPopup(); // [HGM] settings\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
@@ -435,6 +494,26 @@ void ThawUI()
   DrawMenuBar(hwndMain);\r
 }\r
 \r
+/*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them\r
+\r
+/* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */\r
+#ifdef JAWS\r
+#include "jaws.c"\r
+#else\r
+#define JAWS_INIT\r
+#define JAWS_ARGS\r
+#define JAWS_ALT_INTERCEPT\r
+#define JAWS_KB_NAVIGATION\r
+#define JAWS_MENU_ITEMS\r
+#define JAWS_SILENCE\r
+#define JAWS_REPLAY\r
+#define JAWS_ACCEL\r
+#define JAWS_COPYRIGHT\r
+#define JAWS_DELETE(X) X\r
+#define SAYMACHINEMOVE()\r
+#define SAY(X)\r
+#endif\r
+\r
 /*---------------------------------------------------------------------------*\\r
  *\r
  * WinMain\r
@@ -446,7 +525,8 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
        LPSTR lpCmdLine, int nCmdShow)\r
 {\r
   MSG msg;\r
-  HANDLE hAccelMain, hAccelNoAlt;\r
+  HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;\r
+//  INITCOMMONCONTROLSEX ex;\r
 \r
   debugFP = stderr;\r
 \r
@@ -460,8 +540,14 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
     return (FALSE);\r
   }\r
 \r
+  JAWS_INIT\r
+\r
+//  InitCommonControlsEx(&ex);\r
+  InitCommonControls();\r
+\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
@@ -470,12 +556,93 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    0,    /* lowest message to examine */\r
                    0))   /* highest message to examine */\r
     {\r
+\r
+      if(msg.message == WM_CHAR && msg.wParam == '\t') {\r
+       // [HGM] navigate: switch between all windows with tab\r
+       HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;\r
+       int i, currentElement = 0;\r
+\r
+       // first determine what element of the chain we come from (if any)\r
+       if(appData.icsActive) {\r
+           hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);\r
+           hText  = GetDlgItem(hwndConsole, OPT_ConsoleText);\r
+       }\r
+       if(engineOutputDialog && EngineOutputIsUp()) {\r
+           e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);\r
+           e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);\r
+       }\r
+       if(moveHistoryDialog && MoveHistoryIsUp()) {\r
+           mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);\r
+       }\r
+       if(msg.hwnd == hwndMain) currentElement = 7 ; else\r
+       if(msg.hwnd == engineOutputDialog) currentElement = 2; else\r
+       if(msg.hwnd == e1)                 currentElement = 2; else\r
+       if(msg.hwnd == e2)                 currentElement = 3; else\r
+       if(msg.hwnd == moveHistoryDialog) currentElement = 4; else\r
+       if(msg.hwnd == mh)                currentElement = 4; else\r
+       if(msg.hwnd == evalGraphDialog)    currentElement = 6; else\r
+       if(msg.hwnd == hText)  currentElement = 5; else\r
+       if(msg.hwnd == hInput) currentElement = 6; else\r
+       for (i = 0; i < N_BUTTONS; i++) {\r
+           if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }\r
+       }\r
+\r
+       // determine where to go to\r
+       if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;\r
+         do {\r
+           currentElement = (currentElement + direction) % 7;\r
+           switch(currentElement) {\r
+               case 0:\r
+                 h = hwndMain; break; // passing this case always makes the loop exit\r
+               case 1:\r
+                 h = buttonDesc[0].hwnd; break; // could be NULL\r
+               case 2:\r
+                 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows\r
+                 h = e1; break;\r
+               case 3:\r
+                 if(!EngineOutputIsUp()) continue;\r
+                 h = e2; break;\r
+               case 4:\r
+                 if(!MoveHistoryIsUp()) continue;\r
+                 h = mh; break;\r
+//             case 6: // input to eval graph does not seem to get here!\r
+//               if(!EvalGraphIsUp()) continue;\r
+//               h = evalGraphDialog; break;\r
+               case 5:\r
+                 if(!appData.icsActive) continue;\r
+                 SAY("display");\r
+                 h = hText; break;\r
+               case 6:\r
+                 if(!appData.icsActive) continue;\r
+                 SAY("input");\r
+                 h = hInput; break;\r
+           }\r
+         } while(h == 0);\r
+\r
+         if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);\r
+         if(currentElement < 5 && IsIconic(hwndMain))    ShowWindow(hwndMain, SW_RESTORE); // all open together\r
+         SetFocus(h);\r
+\r
+         continue; // this message now has been processed\r
+       }\r
+      }\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
+         !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL\r
+          !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&\r
          !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {\r
+       int done = 0, i; // [HGM] chat: dispatch cat-box messages\r
+       for(i=0; i<MAX_CHAT; i++) \r
+           if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {\r
+               done = 1; break;\r
+       }\r
+       if(done) continue; // [HGM] chat: end patch\r
        TranslateMessage(&msg); /* Translates virtual key codes */\r
        DispatchMessage(&msg);  /* Dispatches message to window */\r
       }\r
@@ -491,6 +658,21 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  *\r
 \*---------------------------------------------------------------------------*/\r
 \r
+void\r
+SetUserLogo()\r
+{   // update user logo if necessary\r
+    static char oldUserName[MSG_SIZ], *curName;\r
+\r
+    if(appData.autoLogo) {\r
+         curName = UserName();\r
+         if(strcmp(curName, oldUserName)) {\r
+               sprintf(oldUserName, "logos\\%s.bmp", curName);\r
+               userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );    \r
+               strcpy(oldUserName, curName);\r
+         }\r
+    }\r
+}\r
+\r
 BOOL\r
 InitApplication(HINSTANCE hInstance)\r
 {\r
@@ -533,11 +715,14 @@ InitApplication(HINSTANCE hInstance)
 int screenHeight, screenWidth;\r
 \r
 void\r
-EnsureOnScreen(int *x, int *y)\r
+EnsureOnScreen(int *x, int *y, int minX, int minY)\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 < minX) *x = minX;\r
+  if (*y < minY) *y = minY;\r
 }\r
 \r
 BOOL\r
@@ -555,14 +740,19 @@ 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
+  screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData\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 +765,41 @@ 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
+      char buf[MSG_SIZ];\r
+      if(appData.icsActive) { // [HGM] logo: in ICS mode second can be used for ICS\r
+       sprintf(buf, "logos\\%s.bmp", appData.icsHost);\r
+       second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );\r
+      } else\r
+      if(appData.secondDirectory && appData.secondDirectory[0]) {\r
+       sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);\r
+       second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );  \r
+      }\r
+  }\r
+\r
+  SetUserLogo();\r
+\r
   iconWhite = LoadIcon(hInstance, "icon_white");\r
   iconBlack = LoadIcon(hInstance, "icon_black");\r
   iconCurrent = iconWhite;\r
@@ -584,20 +809,59 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
   for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {\r
     /* Compute window size for each board size, and use the largest\r
        size that fits on this screen as the default. */\r
-    InitDrawingSizes((BoardSize)ibs, 0);\r
+    InitDrawingSizes((BoardSize)(ibs+1000), 0);\r
     if (boardSize == (BoardSize)-1 &&\r
-       winHeight <= screenHeight && winWidth <= screenWidth) {\r
+        winH <= screenHeight\r
+           - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10\r
+        && winW <= 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
-  EnsureOnScreen(&boardX, &boardY);\r
+  EnsureOnScreen(&boardX, &boardY, minX, minY);\r
   wp.length = sizeof(WINDOWPLACEMENT);\r
   wp.flags = 0;\r
   wp.showCmd = nCmdShow;\r
@@ -608,8 +872,9 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
   wp.rcNormalPosition.bottom = boardY + winHeight;\r
   SetWindowPlacement(hwndMain, &wp);\r
 \r
-  SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,\r
-              0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);\r
+  if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,\r
+               0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);\r
+\r
   if (hwndConsole) {\r
 #if AOT_CONSOLE\r
     SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,\r
@@ -617,7 +882,8 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
 #endif\r
     ShowWindow(hwndConsole, nCmdShow);\r
   }\r
-  UpdateWindow(hwnd);\r
+  if(!appData.noGUI)   UpdateWindow(hwnd);  else ShowWindow(hwnd, SW_MINIMIZE);\r
+  if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file\r
 \r
   return TRUE;\r
 \r
@@ -627,7 +893,8 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
 typedef enum {\r
   ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone, \r
   ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,\r
-  ArgSettingsFilename\r
+  ArgSettingsFilename,\r
+  ArgX, ArgY, ArgZ // [HGM] placement: for window-placement options stored relative to main window\r
 } ArgType;\r
 \r
 typedef struct {\r
@@ -658,6 +925,7 @@ ArgDescriptor argDescriptors[] = {
   { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },\r
   { "", ArgNone, NULL },\r
   /* keyword arguments */\r
+  JAWS_ARGS\r
   { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },\r
   { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },\r
   { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },\r
@@ -803,6 +1071,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
@@ -836,10 +1105,6 @@ ArgDescriptor argDescriptors[] = {
   { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },\r
   { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },\r
   { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },\r
-#if 0\r
-  { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },\r
-  { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },\r
-#endif\r
   { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },\r
   { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },\r
   { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },\r
@@ -962,28 +1227,6 @@ ArgDescriptor argDescriptors[] = {
   { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },\r
   { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },\r
   { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },\r
-  { "x", ArgInt, (LPVOID) &boardX, TRUE },\r
-  { "y", ArgInt, (LPVOID) &boardY, TRUE },\r
-  { "icsX", ArgInt, (LPVOID) &consoleX, TRUE },\r
-  { "icsY", ArgInt, (LPVOID) &consoleY, TRUE },\r
-  { "icsW", ArgInt, (LPVOID) &consoleW, TRUE },\r
-  { "icsH", ArgInt, (LPVOID) &consoleH, TRUE },\r
-  { "analysisX", ArgInt, (LPVOID) &analysisX, TRUE },\r
-  { "analysisY", ArgInt, (LPVOID) &analysisY, TRUE },\r
-  { "analysisW", ArgInt, (LPVOID) &analysisW, TRUE },\r
-  { "analysisH", ArgInt, (LPVOID) &analysisH, TRUE },\r
-  { "commentX", ArgInt, (LPVOID) &commentX, TRUE },\r
-  { "commentY", ArgInt, (LPVOID) &commentY, TRUE },\r
-  { "commentW", ArgInt, (LPVOID) &commentW, TRUE },\r
-  { "commentH", ArgInt, (LPVOID) &commentH, TRUE },\r
-  { "tagsX", ArgInt, (LPVOID) &editTagsX, TRUE },\r
-  { "tagsY", ArgInt, (LPVOID) &editTagsY, TRUE },\r
-  { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },\r
-  { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },\r
-  { "gameListX", ArgInt, (LPVOID) &gameListX, TRUE },\r
-  { "gameListY", ArgInt, (LPVOID) &gameListY, TRUE },\r
-  { "gameListW", ArgInt, (LPVOID) &gameListW, TRUE },\r
-  { "gameListH", ArgInt, (LPVOID) &gameListH, TRUE },\r
   { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },\r
   { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },\r
   { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },\r
@@ -1000,14 +1243,100 @@ 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
+  { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },\r
+  { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },\r
+  { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },\r
+  { "secondXBook", 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
+  /* [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
+  { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE },\r
+  { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE },\r
+  { "firstNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride1, FALSE },\r
+  { "secondNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride2, FALSE },\r
+  { "keepAlive", ArgInt, (LPVOID) &appData.keepAlive, FALSE },\r
+  { "icstype", ArgInt, (LPVOID) &ics_type, FALSE },\r
+  { "forceIllegalMoves", ArgTrue, (LPVOID) &appData.forceIllegal, FALSE },\r
+\r
 #ifdef ZIPPY\r
   { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },\r
   { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },\r
@@ -1047,9 +1376,70 @@ ArgDescriptor argDescriptors[] = {
   { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },\r
   { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },\r
   { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },\r
+  { "zippyShortGame", ArgInt, (LPVOID)&appData.zippyShortGame, FALSE },\r
   /* 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
+  { "keepLineBreaksICS", ArgBoolean, (LPVOID) &appData.noJoin, TRUE },\r
+\r
+  // [HGM] placement: put all window layouts last in ini file, but man X,Y before all others\r
+  { "minX", ArgZ, (LPVOID) &minX, FALSE }, // [HGM] placement: to make suer auxialary windows can be placed\r
+  { "minY", ArgZ, (LPVOID) &minY, FALSE },\r
+  { "winWidth",  ArgInt, (LPVOID) &winWidth,  TRUE }, // [HGM] placement: dummies to remember right & bottom\r
+  { "winHeight", ArgInt, (LPVOID) &winHeight, TRUE }, //       for attaching auxiliary windows to them\r
+  { "x", ArgInt, (LPVOID) &boardX, TRUE },\r
+  { "y", ArgInt, (LPVOID) &boardY, TRUE },\r
+  { "icsX", ArgX,   (LPVOID) &wpConsole.x, TRUE },\r
+  { "icsY", ArgY,   (LPVOID) &wpConsole.y, TRUE },\r
+  { "icsW", ArgInt, (LPVOID) &wpConsole.width, TRUE },\r
+  { "icsH", ArgInt, (LPVOID) &wpConsole.height, TRUE },\r
+  { "analysisX", ArgX,   (LPVOID) &analysisX, FALSE }, // [HGM] placement: analysis window no longer exists\r
+  { "analysisY", ArgY,   (LPVOID) &analysisY, FALSE }, //       provided for compatibility with old ini files\r
+  { "analysisW", ArgInt, (LPVOID) &analysisW, FALSE },\r
+  { "analysisH", ArgInt, (LPVOID) &analysisH, FALSE },\r
+  { "commentX", ArgX,   (LPVOID) &commentX, TRUE },\r
+  { "commentY", ArgY,   (LPVOID) &commentY, TRUE },\r
+  { "commentW", ArgInt, (LPVOID) &commentW, TRUE },\r
+  { "commentH", ArgInt, (LPVOID) &commentH, TRUE },\r
+  { "tagsX", ArgX,   (LPVOID) &editTagsX, TRUE },\r
+  { "tagsY", ArgY,   (LPVOID) &editTagsY, TRUE },\r
+  { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },\r
+  { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },\r
+  { "gameListX", ArgX,   (LPVOID) &wpGameList.x, TRUE },\r
+  { "gameListY", ArgY,   (LPVOID) &wpGameList.y, TRUE },\r
+  { "gameListW", ArgInt, (LPVOID) &wpGameList.width, TRUE },\r
+  { "gameListH", ArgInt, (LPVOID) &wpGameList.height, TRUE },\r
+  /* [AS] Layout stuff */\r
+  { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },\r
+  { "moveHistoryX", ArgX,   (LPVOID) &wpMoveHistory.x, TRUE },\r
+  { "moveHistoryY", ArgY,   (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", ArgX,   (LPVOID) &wpEvalGraph.x, TRUE },\r
+  { "evalGraphY", ArgY,   (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", ArgX,   (LPVOID) &wpEngineOutput.x, TRUE },\r
+  { "engineOutputY", ArgY,   (LPVOID) &wpEngineOutput.y, TRUE },\r
+  { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },\r
+  { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },\r
+\r
   { NULL, ArgNone, NULL, FALSE }\r
 };\r
 \r
@@ -1174,6 +1564,7 @@ FileGet(void *getClosure)
   FILE* f = (FILE*) getClosure;\r
 \r
   c = getc(f);\r
+  if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely\r
   if (c == EOF)\r
     return NULLCHAR;\r
   else\r
@@ -1187,8 +1578,14 @@ ParseSettingsFile(char *name, char fullname[MSG_SIZ])
 {\r
   char *dummy;\r
   FILE *f;\r
+  int ok; char buf[MSG_SIZ];\r
 \r
-  if (SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy)) {\r
+  ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);\r
+  if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed\r
+    sprintf(buf, "%s.ini", name);\r
+    ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);\r
+  }\r
+  if (ok) {\r
     f = fopen(fullname, "r");\r
     if (f != NULL) {\r
       ParseArgs(FileGet, f);\r
@@ -1373,6 +1770,19 @@ ParseArgs(GetFunc get, void *cl)
       *(int *) ad->argLoc = atoi(argValue);\r
       break;\r
 \r
+    case ArgX:\r
+      *(int *) ad->argLoc = atoi(argValue) + boardX; // [HGM] placement: translate stored relative to absolute \r
+      break;\r
+\r
+    case ArgY:\r
+      *(int *) ad->argLoc = atoi(argValue) + boardY; // (this is really kludgey, it should be done where used...)\r
+      break;\r
+\r
+    case ArgZ:\r
+      *(int *) ad->argLoc = atoi(argValue);\r
+      EnsureOnScreen(&boardX, &boardY, minX, minY); \r
+      break;\r
+\r
     case ArgFloat:\r
       *(float *) ad->argLoc = (float) atof(argValue);\r
       break;\r
@@ -1439,6 +1849,8 @@ ParseArgs(GetFunc get, void *cl)
     case ArgNone:\r
       ExitArgError("Unrecognized argument", argValue);\r
       break;\r
+    case ArgTrue:\r
+    case ArgFalse: ;\r
     }\r
   }\r
 }\r
@@ -1611,6 +2023,8 @@ InitAppData(LPSTR lpCmdLine)
   appData.reuseFirst = TRUE;\r
   appData.reuseSecond = TRUE;\r
   appData.blindfold = FALSE;\r
+  appData.icsEngineAnalyze = FALSE;\r
+  memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +\r
   dcb.DCBlength = sizeof(DCB);\r
   dcb.BaudRate = 9600;\r
   dcb.fBinary = TRUE;\r
@@ -1625,7 +2039,6 @@ InitAppData(LPSTR lpCmdLine)
   dcb.fNull = FALSE;\r
   dcb.fRtsControl = RTS_CONTROL_ENABLE;\r
   dcb.fAbortOnError = FALSE;\r
-  dcb.wReserved = 0;\r
   dcb.ByteSize = 7;\r
   dcb.Parity = SPACEPARITY;\r
   dcb.StopBits = ONESTOPBIT;\r
@@ -1633,10 +2046,6 @@ InitAppData(LPSTR lpCmdLine)
   saveSettingsOnExit = TRUE;\r
   boardX = CW_USEDEFAULT;\r
   boardY = CW_USEDEFAULT;\r
-  consoleX = CW_USEDEFAULT; \r
-  consoleY = CW_USEDEFAULT; \r
-  consoleW = CW_USEDEFAULT;\r
-  consoleH = CW_USEDEFAULT;\r
   analysisX = CW_USEDEFAULT; \r
   analysisY = CW_USEDEFAULT; \r
   analysisW = CW_USEDEFAULT;\r
@@ -1649,10 +2058,6 @@ InitAppData(LPSTR lpCmdLine)
   editTagsY = CW_USEDEFAULT; \r
   editTagsW = CW_USEDEFAULT;\r
   editTagsH = CW_USEDEFAULT;\r
-  gameListX = CW_USEDEFAULT; \r
-  gameListY = CW_USEDEFAULT; \r
-  gameListW = CW_USEDEFAULT;\r
-  gameListH = CW_USEDEFAULT;\r
   icsTextMenuString = ICS_TEXT_MENU_DEFAULT;\r
   icsNames = ICS_NAMES;\r
   firstChessProgramNames = FCP_NAMES;\r
@@ -1662,6 +2067,87 @@ 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
+  appData.firstOptions = "";\r
+  appData.secondOptions = "";\r
+\r
+  InitWindowPlacement( &wpGameList );\r
+  InitWindowPlacement( &wpMoveHistory );\r
+  InitWindowPlacement( &wpEvalGraph );\r
+  InitWindowPlacement( &wpEngineOutput );\r
+  InitWindowPlacement( &wpConsole );\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 +2186,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
@@ -1798,7 +2318,7 @@ SaveSettings(char* name)
     return;\r
   }\r
   fprintf(f, ";\n");\r
-  fprintf(f, "; %s %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);\r
+  fprintf(f, "; %s Save Settings file\n", PACKAGE_STRING);\r
   fprintf(f, ";\n");\r
   fprintf(f, "; You can edit the values of options that are already set in this file,\n");\r
   fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");\r
@@ -1812,10 +2332,10 @@ SaveSettings(char* name)
 \r
   if (hwndConsole) {\r
     GetWindowPlacement(hwndConsole, &wp);\r
-    consoleX = wp.rcNormalPosition.left;\r
-    consoleY = wp.rcNormalPosition.top;\r
-    consoleW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
-    consoleH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
+    wpConsole.x = wp.rcNormalPosition.left;\r
+    wpConsole.y = wp.rcNormalPosition.top;\r
+    wpConsole.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
+    wpConsole.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
   }\r
 \r
   if (analysisDialog) {\r
@@ -1844,10 +2364,43 @@ SaveSettings(char* name)
 \r
   if (gameListDialog) {\r
     GetWindowPlacement(gameListDialog, &wp);\r
-    gameListX = wp.rcNormalPosition.left;\r
-    gameListY = wp.rcNormalPosition.top;\r
-    gameListW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
-    gameListH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
+    wpGameList.x = wp.rcNormalPosition.left;\r
+    wpGameList.y = wp.rcNormalPosition.top;\r
+    wpGameList.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
+    wpGameList.height = 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
@@ -1880,8 +2433,15 @@ SaveSettings(char* name)
       }\r
       break;\r
     case ArgInt:\r
+    case ArgZ:\r
       fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);\r
       break;\r
+    case ArgX:\r
+      fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardX); // [HGM] placement: stor relative value\r
+      break;\r
+    case ArgY:\r
+      fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardY);\r
+      break;\r
     case ArgFloat:\r
       fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);\r
       break;\r
@@ -1898,14 +2458,14 @@ SaveSettings(char* name)
     case ArgColor:\r
       {\r
        COLORREF color = *(COLORREF *)ad->argLoc;\r
-       fprintf(f, "/%s=#%02x%02x%02x\n", ad->argName, \r
+       fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName, \r
          color&0xff, (color>>8)&0xff, (color>>16)&0xff);\r
       }\r
       break;\r
     case ArgAttribs:\r
       {\r
        MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];\r
-       fprintf(f, "/%s=\"%s%s%s%s%s#%02x%02x%02x\"\n", ad->argName,\r
+       fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,\r
           (ta->effects & CFE_BOLD) ? "b" : "",\r
           (ta->effects & CFE_ITALIC) ? "i" : "",\r
           (ta->effects & CFE_UNDERLINE) ? "u" : "",\r
@@ -1943,6 +2503,8 @@ SaveSettings(char* name)
       break;\r
     case ArgCommSettings:\r
       PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);\r
+    case ArgNone:\r
+    case ArgSettingsFilename: ;\r
     }\r
   }\r
   fclose(f);\r
@@ -1956,6 +2518,544 @@ 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
+           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
+\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 +3123,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
+  explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic\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 +3158,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+1000, 0); // [HGM] kludge to update sizeInfo without visible effects\r
+       if(newSizeX >= sizeInfo[newSize].cliWidth &&\r
+          newSizeY >= sizeInfo[newSize].cliHeight) break;\r
     newSize--;\r
   } \r
   boardSize = newSize;\r
@@ -2061,7 +3174,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
@@ -2070,14 +3183,30 @@ InitDrawingSizes(BoardSize boardSize, int flags)
   char buf[MSG_SIZ];\r
   char *str;\r
   HMENU hmenu = GetMenu(hwndMain);\r
-  RECT crect, wrect;\r
+  RECT crect, wrect, oldRect;\r
   int offby;\r
   LOGBRUSH logbrush;\r
 \r
+  int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only\r
+  if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }\r
+\r
+  /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */\r
+  if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;\r
+\r
+  oldRect.left = boardX; //[HGM] placement: remember previous window params\r
+  oldRect.top = boardY;\r
+  oldRect.right = boardX + winWidth;\r
+  oldRect.bottom = boardY + winHeight;\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 +3227,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,39 +3246,77 @@ 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) && !tinyLayout) {\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
+    whiteRect.left = leftLogoRect.right;\r
+    whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;\r
+    whiteRect.top = OUTER_MARGIN;\r
+    whiteRect.bottom = whiteRect.top + logoHeight;\r
+\r
+    blackRect.right = rightLogoRect.left;\r
+    blackRect.left = whiteRect.right + INNER_MARGIN;\r
+    blackRect.top = whiteRect.top;\r
+    blackRect.bottom = whiteRect.bottom;\r
+  } else {\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
 \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
-  winWidth = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;\r
-  winHeight = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +\r
+  oldBoardSize = boardSize;\r
+  oldTinyLayout = tinyLayout;\r
+  winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;\r
+  winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +\r
     GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;\r
+  if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only\r
+  winWidth = winW;  // [HGM] placement: set through temporary which can used by initial sizing choice\r
+  winHeight = winH; //       without disturbing window attachments\r
   GetWindowRect(hwndMain, &wrect);\r
   SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,\r
               SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);\r
+\r
+  // [HGM] placement: let attached windows follow size change.\r
+  ReattachAfterSize( &oldRect, winWidth, winHeight, moveHistoryDialog, &wpMoveHistory );\r
+  ReattachAfterSize( &oldRect, winWidth, winHeight, evalGraphDialog, &wpEvalGraph );\r
+  ReattachAfterSize( &oldRect, winWidth, winHeight, engineOutputDialog, &wpEngineOutput );\r
+  ReattachAfterSize( &oldRect, winWidth, winHeight, gameListDialog, &wpGameList );\r
+  ReattachAfterSize( &oldRect, winWidth, winHeight, hwndConsole, &wpConsole );\r
+\r
   /* compensate if menu bar wrapped */\r
   GetClientRect(hwndMain, &crect);\r
   offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;\r
@@ -2227,55 +3395,240 @@ 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
+      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_SIZE*2 + 2].y =\r
-       boardRect.top + BOARD_SIZE * (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
-  oldBoardSize = boardSize;\r
-  oldTinyLayout = tinyLayout;\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
 \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 +3653,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 +3674,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 +3682,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 +3713,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 +3729,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,73 +3777,503 @@ 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 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
-#else\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
       /* 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
-#endif\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
     } else {\r
-#if 0\r
-      /* Use white piece color for details of black pieces */\r
-      /* Requires filled-in solid bitmaps (BLACK_PIECE class); the\r
-        WHITE_PIECE ones aren't always the right shape. */\r
-      /* Not sure this looks really good (though xboard does it).\r
-        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
-      SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));\r
-      SelectObject(hdc, blackPieceBrush);\r
-      BitBlt(hdc, x, y, squareSize, squareSize, 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
-#endif\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
     }\r
     SelectObject(hdc, oldBrush);\r
     SelectObject(tmphdc, oldBitmap);\r
   }\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
-  for (row = 0; row < BOARD_SIZE; row++) {\r
-    for (column = 0; column < BOARD_SIZE; column++) {\r
+      texture_hdc = CreateCompatibleDC( hdc );\r
+  }\r
+\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 +4281,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 +4313,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, HBITMAP logo)\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(logo == 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, logo);\r
+  if( GetObject( logo, 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 +4382,10 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
    */\r
   Boolean fullrepaint = repaint;\r
 \r
+  if( DrawPositionNeedsFullRepaint() ) {\r
+      fullrepaint = TRUE;\r
+  }\r
+\r
   if (board == NULL) {\r
     if (!lastReqValid) {\r
       return;\r
@@ -2565,46 +4415,33 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
     releaseDC = FALSE;\r
   }\r
 \r
-#if 0\r
-  fprintf(debugFP, "*******************************\n"\r
-                   "repaint = %s\n"\r
-                   "dragInfo.from (%d,%d)\n"\r
-                   "dragInfo.start (%d,%d)\n"\r
-                   "dragInfo.pos (%d,%d)\n"\r
-                   "dragInfo.lastpos (%d,%d)\n", \r
-                    repaint ? "TRUE" : "FALSE",\r
-                    dragInfo.from.x, dragInfo.from.y, \r
-                    dragInfo.start.x, dragInfo.start.y,\r
-                    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
-      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
-      fprintf(debugFP, "%d ", board[row][column]);\r
-    }\r
-  }\r
-  fprintf(debugFP, "\n");\r
-  fflush(debugFP);\r
-#endif\r
-\r
   /* Create some work-DCs */\r
   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 +4528,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
@@ -2716,7 +4547,7 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
         atomic, where the piece moves to an empty square and then\r
         explodes.  The old and new positions both had an empty square\r
         at the destination, but animation has drawn a piece there and\r
-        we have to remember to erase it. */\r
+        we have to remember to erase it. [HGM] moved until after setting lastDrawn */\r
       lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;\r
     }\r
   }\r
@@ -2735,13 +4566,81 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
   }\r
 \r
   /* Do all the drawing to the memory DC */\r
-  DrawGridOnDC(hdcmem);\r
-  DrawHighlightsOnDC(hdcmem);\r
-  DrawBoardOnDC(hdcmem, board, tmphdc);\r
+  if(explodeInfo.radius) { // [HGM] atomic\r
+       HBRUSH oldBrush;\r
+       int x, y, r=(explodeInfo.radius * squareSize)/100;\r
+        board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer\r
+       SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);\r
+       x += squareSize/2;\r
+       y += squareSize/2;\r
+        if(!fullrepaint) {\r
+         clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);\r
+         ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);\r
+       }\r
+       DrawGridOnDC(hdcmem);\r
+       DrawHighlightsOnDC(hdcmem);\r
+       DrawBoardOnDC(hdcmem, board, tmphdc);\r
+       oldBrush = SelectObject(hdcmem, explodeBrush);\r
+       Ellipse(hdcmem, x-r, y-r, x+r, y+r);\r
+       SelectObject(hdcmem, oldBrush);\r
+  } else {\r
+    DrawGridOnDC(hdcmem);\r
+    DrawHighlightsOnDC(hdcmem);\r
+    DrawBoardOnDC(hdcmem, board, tmphdc);\r
+  }\r
+  if(logoHeight) {\r
+       HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;\r
+       if(appData.autoLogo) {\r
+         \r
+         switch(gameMode) { // pick logos based on game mode\r
+           case IcsObserving:\r
+               whiteLogo = second.programLogo; // ICS logo\r
+               blackLogo = second.programLogo;\r
+           default:\r
+               break;\r
+           case IcsPlayingWhite:\r
+               if(!appData.zippyPlay) whiteLogo = userLogo;\r
+               blackLogo = second.programLogo; // ICS logo\r
+               break;\r
+           case IcsPlayingBlack:\r
+               whiteLogo = second.programLogo; // ICS logo\r
+               blackLogo = appData.zippyPlay ? first.programLogo : userLogo;\r
+               break;\r
+           case TwoMachinesPlay:\r
+               if(first.twoMachinesColor[0] == 'b') {\r
+                   whiteLogo = second.programLogo;\r
+                   blackLogo = first.programLogo;\r
+               }\r
+               break;\r
+           case MachinePlaysWhite:\r
+               blackLogo = userLogo;\r
+               break;\r
+           case MachinePlaysBlack:\r
+               whiteLogo = userLogo;\r
+               blackLogo = first.programLogo;\r
+         }\r
+       }\r
+       DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);\r
+       DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);\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 +4682,78 @@ 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=0, 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
+       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
+     }\r
+  }\r
+\r
   SelectObject(tmphdc, oldBitmap);\r
 \r
   /* Massive cleanup */\r
@@ -2802,13 +4773,29 @@ 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
+    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
@@ -2822,7 +4809,7 @@ PaintProc(HWND hwnd)
   PAINTSTRUCT ps;\r
   HFONT       oldFont;\r
 \r
-  if(hdc = BeginPaint(hwnd, &ps)) {\r
+  if((hdc = BeginPaint(hwnd, &ps))) {\r
     if (IsIconic(hwnd)) {\r
       DrawIcon(hdc, 2, 2, iconCurrent);\r
     } else {\r
@@ -2905,8 +4892,6 @@ SetupDropMenu(HMENU hmenu)
   }\r
 }\r
 \r
-static int fromX = -1, fromY = -1, toX, toY;\r
-\r
 /* Event handler for mouse messages */\r
 VOID\r
 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)\r
@@ -2915,8 +4900,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 +4923,147 @@ 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(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(!flipClock, -1);\r
        }\r
       }\r
       if (!appData.highlightLastMove) {\r
         ClearHighlights();\r
-       DrawPosition(FALSE, NULL);\r
+       DrawPosition((int) (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
-      }\r
-      ClearHighlights();\r
-      DrawPosition(FALSE, NULL);\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, FALSE);\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 && moveType != Comment) {\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, without promoting 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
+                   DisplayMessage("Select piece from holdings", "");\r
+                 } else\r
+                  PromotionPopup(hwnd);\r
+                 goto noClear;\r
+          } else { // not a promotion. Move can be illegal if testLegality off, and should be made then.\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
+             if (appData.animate && !appData.highlightLastMove) {\r
+                  ClearHighlights();\r
+                  DrawPosition(forceFullRepaint || FALSE, NULL);\r
+             }\r
+          }\r
+          fromX = fromY = -1;\r
+       noClear:\r
+         break;\r
+        }\r
+        if (gotPremove && moveType != Comment) {\r
+           SetPremoveHighlights(fromX, fromY, toX, toY);\r
+//            DrawPosition(forceFullRepaint || FALSE, NULL);\r
+       } else ClearHighlights();\r
+        fromX = fromY = -1;\r
+        DrawPosition(forceFullRepaint || FALSE, NULL);\r
+       if(moveType != Comment) break;\r
     }\r
     /* First downclick, or restart on a square with same color piece */\r
     if (!frozen && OKToStartUserMove(x, y)) {\r
@@ -3035,6 +5078,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 +5097,60 @@ 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, TRUE);\r
+      if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */\r
+               fromX = fromY = -1; \r
+               ClearHighlights();\r
+               DrawPosition(FALSE, boards[currentMove]);\r
+               appData.animate = saveAnimate;\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
+                   appData.animate = saveAnimate;\r
+                   DisplayMessage("Select piece from holdings", "");\r
+                   break;\r
+                 } else\r
+               PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */\r
+          } else {\r
+           if(saveAnimate /* ^$!%@#$!$ */  && gameInfo.variant == VariantAtomic \r
+                         && (boards[currentMove][toY][toX] != EmptySquare || \r
+                                       moveType == WhiteCapturesEnPassant || \r
+                                       moveType == BlackCapturesEnPassant   ) )\r
+               AnimateAtomicCapture(fromX, fromY, toX, toY, 20);\r
+           FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);\r
+         }\r
       }\r
       if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);\r
       appData.animate = saveAnimate;\r
@@ -3082,7 +5160,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 +5170,42 @@ 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
+    {  static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events\r
+       /* Mouse Wheel is being rolled forward\r
+        * Play moves forward\r
+        */\r
+       if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove) \r
+               { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction\r
+       /* Mouse Wheel is being rolled backward\r
+        * Play moves backward\r
+        */\r
+       if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove) \r
+               { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }\r
+    }\r
+    break;\r
+\r
   case WM_MBUTTONDOWN:\r
   case WM_RBUTTONDOWN:\r
     ErrorPopDown();\r
@@ -3128,6 +5218,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(flipClock, 1);\r
+      } else if (PtInRect((LPRECT) &blackRect, pt)) {\r
+          if (gameMode == EditGame) AdjustClock(!flipClock, 1);\r
+      }\r
+    }\r
     DrawPosition(TRUE, NULL);\r
 \r
     switch (gameMode) {\r
@@ -3143,21 +5241,13 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
        else\r
          MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);\r
       } else { /* message == WM_RBUTTONDOWN */\r
-#if 0\r
-       if (buttonCount == 3) {\r
-         if (wParam & MK_SHIFT) \r
-           MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);\r
-         else\r
-           MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);\r
-       } else {\r
-         MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);\r
-       }\r
-#else\r
        /* 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
-#endif\r
+        if(gameInfo.variant != VariantShogi)\r
+            MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);\r
+        else\r
+            MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);\r
       }\r
       break;\r
     case IcsPlayingWhite:\r
@@ -3210,24 +5300,9 @@ ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     case '\r':\r
       SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);\r
       return TRUE;\r
-    case '\t':\r
-      if (appData.icsActive) {\r
-       if (GetKeyState(VK_SHIFT) < 0) {\r
-         /* shifted */\r
-         HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);\r
-         if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);\r
-         SetFocus(h);\r
-       } else {\r
-         /* unshifted */\r
-         HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);\r
-         if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);\r
-         SetFocus(h);\r
-       }\r
-       return TRUE;\r
-      }\r
-      break;\r
     default:\r
-      if (appData.icsActive) {\r
+      if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {\r
+       // [HGM] movenum: only letters or leading zero should go to ICS input\r
         HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);\r
        if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);\r
        SetFocus(h);\r
@@ -3255,7 +5330,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 +5371,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 +5425,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 +5435,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
@@ -3342,6 +5457,36 @@ LoadGameDialog(HWND hwnd, char* title)
   }\r
 }\r
 \r
+void UpdateICSWidth(HWND hText)\r
+{\r
+       HDC hdc;\r
+       TEXTMETRIC tm;\r
+       RECT rc;\r
+       HFONT hfont, hold_font;\r
+       LONG old_width, new_width;\r
+       \r
+       // get the text metrics\r
+       hdc = GetDC(hText);\r
+       hfont = CreateFontIndirect(&font[boardSize][CONSOLE_FONT]->lf);\r
+       hold_font = SelectObject(hdc, hfont);\r
+       GetTextMetrics(hdc, &tm);\r
+       SelectObject(hdc, hold_font);\r
+       DeleteObject(hfont);\r
+       ReleaseDC(hText, hdc);\r
+\r
+       // get the rectangle\r
+       SendMessage(hText, EM_GETRECT, 0, (LPARAM)&rc);\r
+\r
+       // update the width\r
+       new_width = (rc.right-rc.left) / tm.tmAveCharWidth;\r
+       old_width = GetWindowLong(hText, GWL_USERDATA);\r
+       if (new_width != old_width)\r
+       {\r
+               ics_update_width(new_width);\r
+               SetWindowLong(hText, GWL_USERDATA, new_width);\r
+       }\r
+}\r
+\r
 VOID\r
 ChangedConsoleFont()\r
 {\r
@@ -3381,6 +5526,7 @@ ChangedConsoleFont()
   paraf.dxOffset = WRAP_INDENT;\r
   SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) &paraf);\r
   SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);\r
+  UpdateICSWidth(hText);\r
 }\r
 \r
 /*---------------------------------------------------------------------------*\\r
@@ -3399,6 +5545,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
@@ -3426,30 +5574,25 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     MouseEvent(hwnd, message, wParam, lParam);\r
     break;\r
 \r
+  JAWS_KB_NAVIGATION\r
+\r
   case WM_CHAR:\r
     \r
-    if (appData.icsActive) {\r
-      if (wParam == '\t') {\r
-       if (GetKeyState(VK_SHIFT) < 0) {\r
-         /* shifted */\r
-         HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);\r
-         if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);\r
-         SetFocus(h);\r
-       } else {\r
-         /* unshifted */\r
-         HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);\r
-         if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);\r
-         SetFocus(h);\r
-       }\r
-      } else {\r
+    JAWS_ALT_INTERCEPT\r
+\r
+    if (appData.icsActive && (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9')) { \r
+       // [HGM] movenum: for non-zero digits we always do type-in dialog\r
        HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);\r
        if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);\r
        SetFocus(h);\r
        SendMessage(h, message, wParam, lParam);\r
-      }\r
-    } else if (isalpha((char)wParam) || isdigit((char)wParam)) {\r
-      PopUpMoveDialog((char)wParam);\r
+    } else if(lParam != KF_REPEAT) {\r
+       if (isalpha((char)wParam) || isdigit((char)wParam)) {\r
+               PopUpMoveDialog((char)wParam);\r
+       } else if((char)wParam == 003) CopyGameToClipboard();\r
+        else if((char)wParam == 026) PasteGameOrFENFromClipboard();\r
     }\r
+\r
     break;\r
 \r
   case WM_PALETTECHANGED:\r
@@ -3460,11 +5603,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       nnew = RealizePalette(hdc);\r
       if (nnew > 0) {\r
        paletteChanged = TRUE;\r
-#if 0\r
-        UpdateColors(hdc);\r
-#else\r
-        InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/\r
-#endif\r
+        InvalidateRect(hwnd, &boardRect, FALSE);\r
       }\r
       ReleaseDC(hwnd, hdc);\r
     }\r
@@ -3493,6 +5632,18 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     case IDM_NewGame:\r
       ResetGameEvent();\r
       AnalysisPopDown();\r
+      SAY("new game enter a move to play against the computer with white");\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
@@ -3516,7 +5667,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 +5690,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 +5701,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 +5710,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 +5729,68 @@ 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
+           SetFocus(hwndMain);\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_NewChat:\r
+      ChatPopUp();\r
+      break;\r
+\r
     case IDM_CopyPosition:\r
       CopyFENToClipboard();\r
       break;\r
@@ -3603,6 +5827,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
          TagsPopUp(tags, CmailMsg());\r
          free(tags);\r
       }\r
+      SAY("computer starts playing white");\r
       break;\r
 \r
     case IDM_MachineBlack:\r
@@ -3616,6 +5841,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
          TagsPopUp(tags, CmailMsg());\r
          free(tags);\r
       }\r
+      SAY("computer starts playing black");\r
       break;\r
 \r
     case IDM_TwoMachines:\r
@@ -3629,14 +5855,40 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
          TagsPopUp(tags, CmailMsg());\r
          free(tags);\r
       }\r
+      SAY("programs start playing each other");\r
       break;\r
 \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
+       SAY("analyzing current position");\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
@@ -3661,10 +5913,12 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 \r
     case IDM_EditGame:\r
       EditGameEvent();\r
+      SAY("edit game");\r
       break;\r
 \r
     case IDM_EditPosition:\r
       EditPositionEvent();\r
+      SAY("to set up a position type a FEN");\r
       break;\r
 \r
     case IDM_Training:\r
@@ -3735,11 +5989,17 @@ 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
       break;\r
 \r
+    JAWS_MENU_ITEMS\r
+\r
     case IDM_Forward:\r
       ForwardEvent();\r
       SetFocus(hwndMain);\r
@@ -3776,14 +6036,43 @@ 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
+      DrawPosition(FALSE, NULL);\r
+      break;\r
+\r
+    case IDM_MuteSounds:\r
+      mute = !mute; // [HGM] mute: keep track of global muting variable\r
+      CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds, \r
+                               MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));\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_Engine1Options:\r
+      EngineOptionsPopup(hwnd, &first);\r
+      break;\r
+\r
+    case IDM_Engine2Options:\r
+      EngineOptionsPopup(hwnd, &second);\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 +6130,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
@@ -3851,15 +6140,17 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       break;\r
 \r
     case IDM_HELPCONTENTS:\r
-      if (!WinHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {\r
-       MessageBox (GetFocus(),\r
+      if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&\r
+         !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {\r
+         MessageBox (GetFocus(),\r
                    "Unable to activate help",\r
                    szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);\r
       }\r
       break;\r
 \r
     case IDM_HELPSEARCH:\r
-      if (!WinHelp(hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) {\r
+        if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&\r
+           !HtmlHelp(hwnd, "winboard.chm", 0, 0)       ) {\r
        MessageBox (GetFocus(),\r
                    "Unable to activate help",\r
                    szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);\r
@@ -3916,6 +6207,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 +6267,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 +6322,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 +6375,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 +6395,56 @@ 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
+\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 ); //[HGM] sticky: in XP this returned new position, not old\r
+           rcMain.left   = boardX;           //              replace by these 4 lines to reconstruct old rect\r
+           rcMain.right  = boardX + winWidth;\r
+           rcMain.top    = boardY;\r
+           rcMain.bottom = boardY + winHeight;\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
+            ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );\r
+            ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );\r
+           boardX = lpwp->x;\r
+            boardY = lpwp->y;\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 +6452,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
@@ -4207,8 +6606,11 @@ BOOLEAN
 MyPlaySound(MySound *ms)\r
 {\r
   BOOLEAN ok = FALSE;\r
+\r
+  if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted\r
   switch (ms->name[0]) {\r
   case NULLCHAR:\r
+       if(appData.debugMode) fprintf(debugFP, "silence\n");\r
     /* Silence */\r
     ok = TRUE;\r
     break;\r
@@ -4238,13 +6640,6 @@ MyPlaySound(MySound *ms)
   /* Don't print an error: this can happen innocently if the sound driver\r
      is busy; for instance, if another instance of WinBoard is playing\r
      a sound at about the same time. */\r
-#if 0\r
-  if (!ok) {\r
-    char buf[MSG_SIZ];\r
-    sprintf(buf, "Error playing sound %s", ms->name);\r
-    DisplayError(buf, GetLastError());\r
-  }\r
-#endif\r
   return ok;\r
 }\r
 \r
@@ -4301,7 +6696,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 +6728,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 +6739,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 +6843,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 +6875,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 +6893,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
@@ -4545,7 +6951,7 @@ SetStartupDialogEnables(HWND hDlg)
 {\r
   EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),\r
     IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||\r
-    appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer));\r
+    (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));\r
   EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),\r
     IsDlgButtonChecked(hDlg, OPT_ChessEngine));\r
   EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),\r
@@ -4628,13 +7034,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
@@ -4715,6 +7125,7 @@ About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
     /* Center the dialog over the application window */\r
     CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));\r
     SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);\r
+    JAWS_COPYRIGHT\r
     return (TRUE);\r
 \r
   case WM_COMMAND: /* message: received a command */\r
@@ -4772,7 +7183,7 @@ CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
       if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&\r
          commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {\r
        WINDOWPLACEMENT wp;\r
-       EnsureOnScreen(&commentX, &commentY);\r
+       EnsureOnScreen(&commentX, &commentY, 0, 0);\r
        wp.length = sizeof(WINDOWPLACEMENT);\r
        wp.flags = 0;\r
        wp.showCmd = SW_SHOW;\r
@@ -4909,7 +7320,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
@@ -4919,12 +7330,35 @@ TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
   case WM_COMMAND:\r
     switch (LOWORD(wParam)) {\r
     case IDOK:\r
+      GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));\r
+      { int n; Board board;\r
+       // [HGM] FENedit\r
+       if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {\r
+               EditPositionPasteFEN(move);\r
+               EndDialog(hDlg, TRUE);\r
+               return TRUE;\r
+       }\r
+       // [HGM] movenum: allow move number to be typed in any mode\r
+       if(sscanf(move, "%d", &n) == 1 && n != 0 ) {\r
+         currentMove = 2*n-1;\r
+         if(currentMove > forwardMostMove)  currentMove = forwardMostMove;\r
+         if(currentMove < backwardMostMove) currentMove = backwardMostMove;\r
+         EndDialog(hDlg, TRUE);\r
+         DrawPosition(TRUE, boards[currentMove]);\r
+         if(currentMove > backwardMostMove) DisplayMove(currentMove - 1);\r
+         else DisplayMessage("", "");\r
+         return TRUE;\r
+       }\r
+      }\r
       if (gameMode != EditGame && currentMove != forwardMostMove && \r
        gameMode != Training) {\r
        DisplayMoveError("Displayed move is not current");\r
       } else {\r
-       GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));\r
-       if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove, \r
+//     GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream\r
+       int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove, \r
+         &moveType, &fromX, &fromY, &toX, &toY, &promoChar);\r
+       if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized\r
+       if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove, \r
          &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {\r
          if (gameMode != Training)\r
              forwardMostMove = currentMove;\r
@@ -4956,6 +7390,9 @@ PopUpMoveDialog(char firstchar)
        gameMode == AnalyzeMode || gameMode == EditGame || \r
        gameMode == EditPosition || gameMode == IcsExamining ||\r
        gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||\r
+       isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes\r
+               ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||\r
+                 gameMode == IcsObserving || gameMode == TwoMachinesPlay    ) ||\r
        gameMode == Training) {\r
       lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);\r
       DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),\r
@@ -4966,6 +7403,60 @@ 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
+      SetUserLogo();\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 +7519,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 +7556,74 @@ 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
+  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
@@ -5114,7 +7685,7 @@ IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
 void\r
 ParseIcsTextMenu(char *icsTextMenuString)\r
 {\r
-  int flags = 0;\r
+//  int flags = 0;\r
   IcsTextMenuEntry *e = icsTextMenuEntry;\r
   char *p = icsTextMenuString;\r
   while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {\r
@@ -5287,6 +7858,7 @@ ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     }\r
     break;\r
   case WM_CHAR:\r
+   if(wParam != '\022') {\r
     if (wParam == '\t') {\r
       if (GetKeyState(VK_SHIFT) < 0) {\r
        /* shifted */\r
@@ -5302,10 +7874,31 @@ ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       }\r
     } else {\r
       hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);\r
-      SetFocus(hInput);\r
+      JAWS_DELETE( SetFocus(hInput); )\r
       SendMessage(hInput, message, wParam, lParam);\r
     }\r
     return 0;\r
+   } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu\r
+  case WM_RBUTTONUP:\r
+    if (GetKeyState(VK_SHIFT) & ~1) {\r
+      SendDlgItemMessage(hwndConsole, OPT_ConsoleText, \r
+        WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);\r
+    } else {\r
+      POINT pt;\r
+      HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);\r
+      SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);\r
+      if (sel.cpMin == sel.cpMax) {\r
+        EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);\r
+        EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);\r
+      }\r
+      if (!IsClipboardFormatAvailable(CF_TEXT)) {\r
+        EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);\r
+      }\r
+      pt.x = LOWORD(lParam);\r
+      pt.y = HIWORD(lParam);\r
+      MenuPopup(hwnd, pt, hmenu, -1);\r
+    }\r
+    return 0;\r
   case WM_PASTE:\r
     hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);\r
     SetFocus(hInput);\r
@@ -5327,26 +7920,6 @@ ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);\r
     }\r
     return 0;\r
-  case WM_RBUTTONUP:\r
-    if (GetKeyState(VK_SHIFT) & ~1) {\r
-      SendDlgItemMessage(hwndConsole, OPT_ConsoleText, \r
-        WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);\r
-    } else {\r
-      POINT pt;\r
-      HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);\r
-      SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);\r
-      if (sel.cpMin == sel.cpMax) {\r
-        EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);\r
-        EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);\r
-      }\r
-      if (!IsClipboardFormatAvailable(CF_TEXT)) {\r
-        EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);\r
-      }\r
-      pt.x = LOWORD(lParam);\r
-      pt.y = HIWORD(lParam);\r
-      MenuPopup(hwnd, pt, hmenu, -1);\r
-    }\r
-    return 0;\r
   case WM_COMMAND:\r
     switch (LOWORD(wParam)) {\r
     case IDM_QuickPaste:\r
@@ -5463,6 +8036,7 @@ ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     case '\021': /* Ctrl+Q */\r
       quoteNextChar = TRUE;\r
       return 0;\r
+    JAWS_REPLAY\r
     default:\r
       break;\r
     }\r
@@ -5556,18 +8130,36 @@ ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 LRESULT CALLBACK\r
 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
 {\r
-  static HWND hText, hInput, hFocus;\r
-  InputSource *is = consoleInputSource;\r
+  static SnapData sd;\r
+  HWND hText, hInput;\r
   RECT rect;\r
   static int sizeX, sizeY;\r
   int newSizeX, newSizeY;\r
   MINMAXINFO *mmi;\r
+  WORD wMask;\r
+\r
+  hText = GetDlgItem(hDlg, OPT_ConsoleText);\r
+  hInput = GetDlgItem(hDlg, OPT_ConsoleInput);\r
 \r
   switch (message) {\r
+  case WM_NOTIFY:\r
+    if (((NMHDR*)lParam)->code == EN_LINK)\r
+    {\r
+      ENLINK *pLink = (ENLINK*)lParam;\r
+      if (pLink->msg == WM_LBUTTONUP)\r
+      {\r
+        TEXTRANGE tr;\r
+\r
+        tr.chrg = pLink->chrg;\r
+        tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);\r
+        SendMessage(hText, EM_GETTEXTRANGE, 0, (LPARAM)&tr);\r
+        ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);\r
+        free(tr.lpstrText);\r
+      }\r
+    }\r
+    break;\r
   case WM_INITDIALOG: /* message: initialize dialog box */\r
     hwndConsole = hDlg;\r
-    hText = GetDlgItem(hDlg, OPT_ConsoleText);\r
-    hInput = GetDlgItem(hDlg, OPT_ConsoleInput);\r
     SetFocus(hInput);\r
     consoleTextWindowProc = (WNDPROC)\r
       SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);\r
@@ -5581,20 +8173,46 @@ ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
     GetClientRect(hDlg, &rect);\r
     sizeX = rect.right;\r
     sizeY = rect.bottom;\r
-    if (consoleX != CW_USEDEFAULT && consoleY != CW_USEDEFAULT &&\r
-       consoleW != CW_USEDEFAULT && consoleH != CW_USEDEFAULT) {\r
+    if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&\r
+       wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {\r
       WINDOWPLACEMENT wp;\r
-      EnsureOnScreen(&consoleX, &consoleY);\r
+      EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);\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
+      wp.rcNormalPosition.left = wpConsole.x;\r
+      wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;\r
+      wp.rcNormalPosition.top = wpConsole.y;\r
+      wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;\r
       SetWindowPlacement(hDlg, &wp);\r
     }\r
+\r
+   // [HGM] Chessknight's change 2004-07-13\r
+   else { /* Determine Defaults */\r
+       WINDOWPLACEMENT wp;\r
+       wpConsole.x = winWidth + 1;\r
+       wpConsole.y = boardY;\r
+       wpConsole.width = screenWidth -  winWidth;\r
+       wpConsole.height = winHeight;\r
+       EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);\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 = wpConsole.x;\r
+       wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;\r
+       wp.rcNormalPosition.top = wpConsole.y;\r
+       wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;\r
+       SetWindowPlacement(hDlg, &wp);\r
+    }\r
+\r
+   // Allow hText to highlight URLs and send notifications on them\r
+   wMask = SendMessage(hText, EM_GETEVENTMASK, 0, 0L);\r
+   SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);\r
+   SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);\r
+   SetWindowLong(hText, GWL_USERDATA, 79); // initialize the text window's width\r
+\r
     return FALSE;\r
 \r
   case WM_SETFOCUS:\r
@@ -5642,7 +8260,22 @@ 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
+       UpdateICSWidth(hText);\r
+    return OnExitSizeMove( &sd, hDlg, wParam, lParam );\r
   }\r
+\r
   return DefWindowProc(hDlg, message, wParam, lParam);\r
 }\r
 \r
@@ -5750,8 +8383,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 +8424,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:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);\r
     str = buf;\r
   } else {\r
     str = color;\r
@@ -5777,10 +8441,22 @@ DisplayAClock(HDC hdc, int timeRemaining, int highlight,
   }\r
   oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);\r
 \r
+  JAWS_SILENCE\r
+\r
   ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,\r
             rect->top, ETO_CLIPPED|ETO_OPAQUE,\r
             rect, str, strlen(str), NULL);\r
-\r
+  if(logoHeight > 0 && appData.clockMode) {\r
+      RECT r;\r
+      sprintf(buf, "%s %s", buf+7, flagFell);\r
+      r.top = rect->top + logoHeight/2;\r
+      r.left = rect->left;\r
+      r.right = rect->right;\r
+      r.bottom = rect->bottom;\r
+      ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,\r
+                r.top, ETO_CLIPPED|ETO_OPAQUE,\r
+                &r, str, strlen(str), NULL);\r
+  }\r
   (void) SetTextColor(hdc, oldFg);\r
   (void) SetBkColor(hdc, oldBg);\r
   (void) SelectObject(hdc, oldFont);\r
@@ -5793,6 +8469,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 +8520,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=%lu)\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 +8564,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=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );\r
+  }\r
+\r
   return 0;\r
 }\r
 \r
@@ -5913,7 +8634,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 +8667,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 +8691,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 +8751,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 +8946,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 +8969,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
@@ -6350,7 +9096,10 @@ DisplayMessage(char *str1, char *str2)
   }\r
   messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;\r
 \r
-  if (IsIconic(hwndMain)) return;\r
+  if (hwndMain == NULL || IsIconic(hwndMain)) return;\r
+\r
+  SAYMACHINEMOVE();\r
+\r
   hdc = GetDC(hwndMain);\r
   oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);\r
   ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,\r
@@ -6364,7 +9113,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 +9260,273 @@ 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
+    { GLT_RESULT_COMMENT, "Result Comment" }, // [HGM] rescom\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
@@ -6527,6 +9543,11 @@ DrawPosition(int fullRedraw, Board board)
   HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board); \r
 }\r
 \r
+void NotifyFrontendLogin()\r
+{\r
+       if (hwndConsole)\r
+               UpdateICSWidth(GetDlgItem(hwndConsole, OPT_ConsoleText));\r
+}\r
 \r
 VOID\r
 ResetFrontEnd()\r
@@ -6549,6 +9570,7 @@ CommentPopUp(char *title, char *str)
 {\r
   HWND hwnd = GetActiveWindow();\r
   EitherCommentPopUp(0, title, str, FALSE);\r
+  SAY(str);\r
   SetActiveWindow(hwnd);\r
 }\r
 \r
@@ -6644,6 +9666,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 +9716,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
+                       flipClock ? &blackRect : &whiteRect, "White", flag);\r
   }\r
   if (highlight && iconCurrent == iconBlack) {\r
     iconCurrent = iconWhite;\r
@@ -6711,9 +9740,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
+                       flipClock ? &whiteRect : &blackRect, "Black", flag);\r
   }\r
   if (highlight && iconCurrent == iconWhite) {\r
     iconCurrent = iconBlack;\r
@@ -6758,7 +9791,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
@@ -6773,11 +9806,12 @@ void
 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)\r
 {\r
   if (delayedTimerEvent != 0) {\r
-    if (appData.debugMode) {\r
+    if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug\r
       fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");\r
     }\r
     KillTimer(hwndMain, delayedTimerEvent);\r
     delayedTimerEvent = 0;\r
+    if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it\r
     delayedTimerCallback();\r
   }\r
   delayedTimerCallback = cb;\r
@@ -6804,6 +9838,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 +9970,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 +10005,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 +10020,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 %lu, 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 %lu 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 +10428,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 +10442,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 +10461,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 +10480,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
@@ -7542,7 +10634,7 @@ AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
       if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&\r
          analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {\r
        WINDOWPLACEMENT wp;\r
-       EnsureOnScreen(&analysisX, &analysisY);\r
+       EnsureOnScreen(&analysisX, &analysisY, 0, 0);\r
        wp.length = sizeof(WINDOWPLACEMENT);\r
        wp.flags = 0;\r
        wp.showCmd = SW_SHOW;\r
@@ -7567,6 +10659,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 +10695,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
@@ -7689,6 +10790,24 @@ static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
      POINT frames[], int * nFrames);\r
 \r
 \r
+void\r
+AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)\r
+{      // [HGM] atomic: animate blast wave\r
+       int i;\r
+if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);\r
+       explodeInfo.fromX = fromX;\r
+       explodeInfo.fromY = fromY;\r
+       explodeInfo.toX = toX;\r
+       explodeInfo.toY = toY;\r
+       for(i=1; i<nFrames; i++) {\r
+           explodeInfo.radius = (i*180)/(nFrames-1);\r
+           DrawPosition(FALSE, NULL);\r
+           Sleep(appData.animSpeed);\r
+       }\r
+       explodeInfo.radius = 0;\r
+       DrawPosition(TRUE, NULL);\r
+}\r
+\r
 #define kFactor 4\r
 \r
 void\r
@@ -7749,6 +10868,9 @@ AnimateMove(board, fromX, fromY, toX, toY)
   animInfo.pos = finish;\r
   DrawPosition(FALSE, NULL);\r
   animInfo.piece = EmptySquare;\r
+  if(gameInfo.variant == VariantAtomic && \r
+     (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )\r
+       AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);\r
 }\r
 \r
 /*      Convert board position to corner of screen rect and color       */\r
@@ -7758,11 +10880,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 +10932,14 @@ 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
-}\r
+    MoveHistorySet( movelist, first, last, current, pvInfoList );\r
 \r
+    EvalGraphSet( first, last, current, pvInfoList );\r
+}\r
 \r
+void SetProgramStats( FrontEndProgramStats * stats )\r
+{\r
+    EngineOutputUpdate( stats );\r
+}\r