Give WinBoard Game List its own font
[xboard.git] / winboard / winboard.c
index 751e67e..e2ba141 100644 (file)
@@ -1,9 +1,13 @@
-/* \r
+/*\r
  * WinBoard.c -- Windows NT front end to XBoard\r
- * $Id: winboard.c,v 2.3 2003/11/25 05:25:20 mann Exp $
  *\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, 2010, 2011 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>
+#include <time.h>\r
 #include <malloc.h>\r
 #include <sys/stat.h>\r
 #include <fcntl.h>\r
@@ -66,6 +72,8 @@
 #include <dlgs.h>\r
 #include <richedit.h>\r
 #include <mmsystem.h>\r
+#include <ctype.h>\r
+#include <io.h>\r
 \r
 #if __GNUC__\r
 #include <errno.h>\r
 #endif\r
 \r
 #include "common.h"\r
-#include "winboard.h"\r
 #include "frontend.h"\r
 #include "backend.h"\r
+#include "winboard.h"\r
 #include "moves.h"\r
 #include "wclipbrd.h"\r
-#include "wgamelist.h"\r
-#include "wedittags.h"\r
 #include "woptions.h"\r
 #include "wsockerr.h"\r
 #include "defaults.h"\r
-\r
-int myrandom(void);
-void mysrandom(unsigned int seed);
-
+#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 DisplayMove P((int moveNumber));\r
+Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen));\r
+void ChatPopUp P((char *s));\r
 typedef struct {\r
   ChessSquare piece;  \r
   POINT pos;      /* window coordinates of current pos */\r
@@ -102,9 +124,10 @@ typedef struct {
   POINT pos;      /* window coordinates of current pos */\r
   POINT lastpos;  /* window coordinates of last pos - used for clipping */\r
   POINT from;     /* board coordinates of the piece's orig pos */\r
+  ChessSquare piece;\r
 } DragInfo;\r
 \r
-static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };\r
+static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, EmptySquare };\r
 \r
 typedef struct {\r
   POINT sq[2];   /* board coordinates of from, to squares */\r
@@ -112,6 +135,14 @@ typedef struct {
 \r
 static HighlightInfo highlightInfo        = { {{-1, -1}, {-1, -1}} };\r
 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };\r
+static HighlightInfo partnerHighlightInfo = { {{-1, -1}, {-1, -1}} };\r
+static HighlightInfo oldPartnerHighlight  = { {{-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
@@ -119,19 +150,22 @@ char szConsoleName[] = "WBConsole";
 \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
-BOOLEAN saveSettingsOnExit;\r
+Boolean saveSettingsOnExit;\r
 char installDir[MSG_SIZ];\r
+int errorExitStatus;\r
 \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
+Boolean chessProgram;\r
+//static int boardX, boardY;\r
+int  minX, minY; // [HGM] placement: volatile limits on upper-left corner\r
+int squareSize, lineGap, minorSize;\r
+static int 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
@@ -144,27 +178,27 @@ char *icsNames;
 char *firstChessProgramNames;\r
 char *secondChessProgramNames;\r
 \r
-#define ARG_MAX 64*1024 /* [AS] For Roger Brown's very long list! */
-\r
 #define PALETTESIZE 256\r
 \r
 HINSTANCE hInst;          /* current instance */\r
-HWND hwndMain = NULL;        /* root window*/\r
-HWND hwndConsole = NULL;\r
-BOOLEAN alwaysOnTop = FALSE;\r
+Boolean alwaysOnTop = FALSE;\r
 RECT boardRect;\r
 COLORREF lightSquareColor, darkSquareColor, whitePieceColor, \r
   blackPieceColor, highlightSquareColor, premoveHighlightColor;\r
 HPALETTE hPal;\r
 ColorClass currentColorClass;\r
 \r
+static HWND savedHwnd;\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
-static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];\r
-static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];\r
+  blackSquareBrush, /* [HGM] for band between board and holdings */\r
+  explodeBrush,     /* [HGM] atomic */\r
+  markerBrush,      /* [HGM] markers */\r
+  whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;\r
+static POINT gridEndpoints[(BOARD_RANKS + BOARD_FILES + 2) * 2];\r
+static DWORD gridVertexCounts[BOARD_RANKS + BOARD_FILES + 2];\r
 static HPEN gridPen = NULL;\r
 static HPEN highlightPen = NULL;\r
 static HPEN premovePen = NULL;\r
@@ -174,32 +208,284 @@ static HICON iconWhite, iconBlack, iconCurrent;
 static int doingSizing = FALSE;\r
 static int lastSizing = 0;\r
 static int prevStderrPort;\r
+static HBITMAP userLogo;\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_RANKS][BOARD_FILES];\r
 \r
-/* [AS] Support for background textures */
-#define BACK_TEXTURE_MODE_DISABLED      0
-#define BACK_TEXTURE_MODE_PLAIN         1
-#define BACK_TEXTURE_MODE_FULL_RANDOM   2
-
-static HBITMAP liteBackTexture = NULL;
-static HBITMAP darkBackTexture = NULL;
-static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
-static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
-static int backTextureSquareSize = 0;
-static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];
-
 #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
-{\r
-  COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,\r
-  COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,\r
-  COLOR_NONE\r
+#define INTERNATIONAL\r
+\r
+#ifdef INTERNATIONAL\r
+#  define _(s) T_(s)\r
+#  define N_(s) s\r
+#else\r
+#  define _(s) s\r
+#  define N_(s) s\r
+#  define T_(s) s\r
+#  define Translate(x, y)\r
+#  define LoadLanguageFile(s)\r
+#endif\r
+\r
+#ifdef INTERNATIONAL\r
+\r
+Boolean barbaric; // flag indicating if translation is needed\r
+\r
+// list of item numbers used in each dialog (used to alter language at run time)\r
+\r
+#define ABOUTBOX -1  /* not sure why these are needed */\r
+#define ABOUTBOX2 -1\r
+\r
+int dialogItems[][40] = {\r
+{ ABOUTBOX, IDOK, OPT_MESS, 400 }, \r
+{ DLG_TimeControl, IDC_Babble, OPT_TCUseMoves, OPT_TCUseInc, OPT_TCUseFixed, \r
+  OPT_TCtext1, OPT_TCtext2, OPT_TCitext1, OPT_TCitext2, OPT_TCftext, GPB_Factors,   IDC_Factor1, IDC_Factor2, IDOK, IDCANCEL }, \r
+{ DLG_LoadOptions, OPT_Autostep, OPT_AStext1, IDOK, IDCANCEL }, \r
+{ DLG_SaveOptions, OPT_Autosave, OPT_AVPrompt, OPT_AVToFile, OPT_AVBrowse,\r
+  801, OPT_PGN, OPT_Old, OPT_OutOfBookInfo, IDOK, IDCANCEL }, \r
+{ 1536, 1090, IDC_Directories, 1089, 1091, IDOK, IDCANCEL, 1038, IDC_IndexNr, 1037 }, \r
+{ DLG_CommPort, IDOK, IDCANCEL, IDC_Port, IDC_Rate, IDC_Bits, IDC_Parity,\r
+  IDC_Stop, IDC_Flow, OPT_SerialHelp }, \r
+{ DLG_EditComment, IDOK, OPT_CancelComment, OPT_ClearComment, OPT_EditComment }, \r
+{ DLG_PromotionKing, PB_Chancellor, PB_Archbishop, PB_Queen, PB_Rook, \r
+  PB_Bishop, PB_Knight, PB_King, IDCANCEL, IDC_Yes, IDC_No, IDC_Centaur }, \r
+{ ABOUTBOX2, IDC_ChessBoard }, \r
+{ DLG_GameList, OPT_GameListLoad, OPT_GameListPrev, OPT_GameListNext, \r
+  OPT_GameListClose, IDC_GameListDoFilter }, \r
+{ DLG_EditTags, IDOK, OPT_TagsCancel, OPT_EditTags }, \r
+{ DLG_Error, IDOK }, \r
+{ DLG_Colorize, IDOK, IDCANCEL, OPT_ChooseColor, OPT_Bold, OPT_Italic,\r
+  OPT_Underline, OPT_Strikeout, OPT_Sample }, \r
+{ DLG_Question, IDOK, IDCANCEL, OPT_QuestionText }, \r
+{ DLG_Startup, IDC_Welcome, OPT_ChessEngine, OPT_ChessServer, OPT_View,\r
+  IDC_SPECIFY_ENG_STATIC, IDC_SPECIFY_SERVER_STATIC, OPT_AnyAdditional,\r
+  IDOK, IDCANCEL, IDM_HELPCONTENTS }, \r
+{ DLG_IndexNumber, IDC_Index }, \r
+{ DLG_TypeInMove, IDOK, IDCANCEL }, \r
+{ DLG_TypeInName, IDOK, IDCANCEL }, \r
+{ DLG_Sound, IDC_Event, OPT_NoSound, OPT_DefaultBeep, OPT_BuiltInSound,\r
+  OPT_WavFile, OPT_BrowseSound, OPT_DefaultSounds, IDOK, IDCANCEL, OPT_PlaySound }, \r
+{ DLG_GeneralOptions, IDOK, IDCANCEL, OPT_AlwaysOnTop, OPT_HighlightLastMove,\r
+  OPT_AlwaysQueen, OPT_PeriodicUpdates, OPT_AnimateDragging, OPT_PonderNextMove,\r
+  OPT_AnimateMoving, OPT_PopupExitMessage, OPT_AutoFlag, OPT_PopupMoveErrors,\r
+  OPT_AutoFlipView, OPT_ShowButtonBar, OPT_AutoRaiseBoard, OPT_ShowCoordinates,\r
+  OPT_Blindfold, OPT_ShowThinking, OPT_HighlightDragging, OPT_TestLegality,\r
+  OPT_SaveExtPGN, OPT_HideThinkFromHuman, OPT_ExtraInfoInMoveHistory,\r
+  OPT_HighlightMoveArrow, OPT_AutoLogo ,OPT_SmartMove }, \r
+{ DLG_IcsOptions, IDOK, IDCANCEL, OPT_AutoComment, OPT_AutoKibitz, OPT_AutoObserve,\r
+  OPT_GetMoveList, OPT_LocalLineEditing, OPT_QuietPlay, OPT_SeekGraph, OPT_AutoRefresh,\r
+  OPT_BgObserve, OPT_DualBoard, OPT_Premove, OPT_PremoveWhite, OPT_PremoveBlack,\r
+  OPT_SmartMove, OPT_IcsAlarm, IDC_Sec, OPT_ChooseShoutColor, OPT_ChooseSShoutColor,\r
+  OPT_ChooseChannel1Color, OPT_ChooseChannelColor, OPT_ChooseKibitzColor,\r
+  OPT_ChooseTellColor, OPT_ChooseChallengeColor, OPT_ChooseRequestColor,\r
+  OPT_ChooseSeekColor, OPT_ChooseNormalColor, OPT_ChooseBackgroundColor,\r
+  OPT_DefaultColors, OPT_DontColorize, IDC_Boxes, GPB_Colors, GPB_Premove,\r
+  GPB_General, GPB_Alarm }, \r
+{ DLG_BoardOptions, IDOK, IDCANCEL, OPT_SizeTiny, OPT_SizeTeeny, OPT_SizeDinky,\r
+  OPT_SizePetite, OPT_SizeSlim, OPT_SizeSmall, OPT_SizeMediocre, OPT_SizeMiddling,\r
+  OPT_SizeAverage, OPT_SizeModerate, OPT_SizeMedium, OPT_SizeBulky, OPT_SizeLarge,\r
+  OPT_SizeBig, OPT_SizeHuge, OPT_SizeGiant, OPT_SizeColossal, OPT_SizeTitanic,\r
+  OPT_ChooseLightSquareColor, OPT_ChooseDarkSquareColor, OPT_ChooseWhitePieceColor,\r
+  OPT_ChooseBlackPieceColor, OPT_ChooseHighlightSquareColor, OPT_ChoosePremoveHighlightColor,\r
+  OPT_Monochrome, OPT_AllWhite, OPT_UpsideDown, OPT_DefaultBoardColors, GPB_Colors,\r
+  IDC_Light, IDC_Dark, IDC_White, IDC_Black, IDC_High, IDC_PreHigh, GPB_Size }, \r
+{ DLG_NewVariant, IDOK, IDCANCEL, OPT_VariantNormal, OPT_VariantFRC, OPT_VariantWildcastle,\r
+  OPT_VariantNocastle, OPT_VariantLosers, OPT_VariantGiveaway, OPT_VariantSuicide,\r
+  OPT_Variant3Check, OPT_VariantTwoKings, OPT_VariantAtomic, OPT_VariantCrazyhouse,\r
+  OPT_VariantBughouse, OPT_VariantTwilight, OPT_VariantShogi, OPT_VariantSuper,\r
+  OPT_VariantKnightmate, OPT_VariantBerolina, OPT_VariantCylinder, OPT_VariantFairy,\r
+  OPT_VariantMakruk, OPT_VariantGothic, OPT_VariantCapablanca, OPT_VariantJanus,\r
+  OPT_VariantCRC, OPT_VariantFalcon, OPT_VariantCourier, OPT_VariantGreat, OPT_VariantSChess,\r
+  OPT_VariantShatranj, OPT_VariantXiangqi, GPB_Variant, GPB_Board, IDC_Height,\r
+  IDC_Width, IDC_Hand, IDC_Pieces, IDC_Def }, \r
+{ DLG_Fonts, IDOK, IDCANCEL, OPT_ChooseClockFont, OPT_ChooseMessageFont,\r
+  OPT_ChooseCoordFont, OPT_ChooseTagFont, OPT_ChooseCommentsFont,  OPT_ChooseConsoleFont, OPT_ChooseMoveHistoryFont, OPT_DefaultFonts,\r
+  OPT_ClockFont, OPT_MessageFont, OPT_CoordFont, OPT_EditTagsFont,\r
+  OPT_SampleGameListFont, OPT_ChooseGameListFont, OPT_MessageFont7, \r
+  OPT_CommentsFont, OPT_MessageFont5, GPB_Current, GPB_All, OPT_MessageFont6 }, \r
+{ DLG_NewGameFRC, IDC_NFG_Label, IDC_NFG_Random, IDOK, IDCANCEL }, \r
+{ DLG_GameListOptions, IDC_GLT, IDC_GLT_Up, IDC_GLT_Down, IDC_GLT_Restore,\r
+  IDC_GLT_Default, IDOK, IDCANCEL, IDC_GLT_RestoreTo }, \r
+{ DLG_MoveHistory }, \r
+{ DLG_EvalGraph }, \r
+{ DLG_EngineOutput, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineLabel2, IDC_Engine2_NPS }, \r
+{ DLG_Chat, IDC_Partner, IDC_Clear, IDC_Send,  }, \r
+{ DLG_EnginePlayOptions, IDC_EpPonder, IDC_EpShowThinking, IDC_EpHideThinkingHuman,\r
+  IDC_EpPeriodicUpdates, GPB_Adjudications, IDC_Draw, IDC_Moves, IDC_Threshold,\r
+  IDC_Centi, IDC_TestClaims, IDC_DetectMates, IDC_MaterialDraws, IDC_TrivialDraws,\r
+  GPB_Apply, IDC_Rule, IDC_Repeats, IDC_ScoreAbs1, IDC_ScoreAbs2, IDOK, IDCANCEL }, \r
+{ DLG_OptionsUCI, IDC_PolyDir, IDC_BrowseForPolyglotDir, IDC_Hash, IDC_Path,\r
+  IDC_BrowseForEGTB, IDC_Cache, IDC_UseBook, IDC_BrowseForBook, IDC_CPU, IDC_OwnBook1,\r
+  IDC_OwnBook2, IDC_Depth, IDC_Variation, IDC_DefGames, IDOK, IDCANCEL },\r
+{ 0 }\r
 };\r
 \r
+static char languageBuf[50000], *foreign[1000], *english[1000], *languageFile[MSG_SIZ];\r
+static int lastChecked;\r
+static char oldLanguage[MSG_SIZ], *menuText[10][30];\r
+extern int tinyLayout;\r
+extern char * menuBarText[][10];\r
+\r
+void\r
+LoadLanguageFile(char *name)\r
+{   //load the file with translations, and make a list of the strings to be translated, and their translations\r
+    FILE *f;\r
+    int i=0, j=0, n=0, k;\r
+    char buf[MSG_SIZ];\r
+\r
+    if(!name || name[0] == NULLCHAR) return;\r
+      snprintf(buf, MSG_SIZ, "%s%s", name, strchr(name, '.') ? "" : ".lng"); // auto-append lng extension\r
+    appData.language = oldLanguage;\r
+    if(!strcmp(buf, oldLanguage)) { barbaric = 1; return; } // this language already loaded; just switch on\r
+    if((f = fopen(buf, "r")) == NULL) return;\r
+    while((k = fgetc(f)) != EOF) {\r
+        if(i >= sizeof(languageBuf)) { DisplayError("Language file too big", 0); return; }\r
+        languageBuf[i] = k;\r
+        if(k == '\n') {\r
+            if(languageBuf[n] == '"' && languageBuf[i-1] == '"') {\r
+                char *p;\r
+                if(p = strstr(languageBuf + n + 1, "\" === \"")) {\r
+                    if(p > languageBuf+n+2 && p+8 < languageBuf+i) {\r
+                        if(j >= sizeof(english)) { DisplayError("Too many translated strings", 0); return; }\r
+                        english[j] = languageBuf + n + 1; *p = 0;\r
+                        foreign[j++] = p + 7; languageBuf[i-1] = 0;\r
+//if(appData.debugMode) fprintf(debugFP, "translation: replace '%s' by '%s'\n", english[j-1], foreign[j-1]);\r
+                    }\r
+                }\r
+            }\r
+            n = i + 1;\r
+        } else if(i > 0 && languageBuf[i-1] == '\\') {\r
+            switch(k) {\r
+              case 'n': k = '\n'; break;\r
+              case 'r': k = '\r'; break;\r
+              case 't': k = '\t'; break;\r
+            }\r
+            languageBuf[--i] = k;\r
+        }\r
+        i++;\r
+    }\r
+    fclose(f);\r
+    barbaric = (j != 0);\r
+    safeStrCpy(oldLanguage, buf, sizeof(oldLanguage)/sizeof(oldLanguage[0]) );\r
+}\r
+\r
+char *\r
+T_(char *s)\r
+{   // return the translation of the given string\r
+    // efficiency can be improved a lot...\r
+    int i=0;\r
+//if(appData.debugMode) fprintf(debugFP, "T_(%s)\n", s);\r
+    if(!barbaric) return s;\r
+    if(!s) return ""; // sanity\r
+    while(english[i]) {\r
+        if(!strcmp(s, english[i])) return foreign[i];\r
+        i++;\r
+    }\r
+    return s;\r
+}\r
+\r
+void\r
+Translate(HWND hDlg, int dialogID)\r
+{   // translate all text items in the given dialog\r
+    int i=0, j, k;\r
+    char buf[MSG_SIZ], *s;\r
+    if(!barbaric) return;\r
+    while(dialogItems[i][0] && dialogItems[i][0] != dialogID) i++; // find the dialog description\r
+    if(dialogItems[i][0] != dialogID) return; // unknown dialog, should not happen\r
+    GetWindowText( hDlg, buf, MSG_SIZ );\r
+    s = T_(buf);\r
+    if(strcmp(buf, s)) SetWindowText(hDlg, s); // replace by translated string (if different)\r
+    for(j=1; k=dialogItems[i][j]; j++) { // translate all listed dialog items\r
+        GetDlgItemText(hDlg, k, buf, MSG_SIZ);\r
+        if(strlen(buf) == 0) continue;\r
+        s = T_(buf);\r
+        if(strcmp(buf, s)) SetDlgItemText(hDlg, k, s); // replace by translated string (if different)\r
+    }\r
+}\r
+\r
+HMENU\r
+TranslateOneMenu(int i, HMENU subMenu)\r
+{\r
+    int j;\r
+    static MENUITEMINFO info;\r
+\r
+    info.cbSize = sizeof(MENUITEMINFO);\r
+    info.fMask = MIIM_STATE | MIIM_TYPE;\r
+          for(j=GetMenuItemCount(subMenu)-1; j>=0; j--){\r
+            char buf[MSG_SIZ];\r
+            info.dwTypeData = buf;\r
+            info.cch = sizeof(buf);\r
+            GetMenuItemInfo(subMenu, j, TRUE, &info);\r
+            if(i < 10) {
+                if(menuText[i][j]) safeStrCpy(buf, menuText[i][j], sizeof(buf)/sizeof(buf[0]) );\r
+                else menuText[i][j] = strdup(buf); // remember original on first change\r
+            }\r
+            if(buf[0] == NULLCHAR) continue;\r
+            info.dwTypeData = T_(buf);\r
+            info.cch = strlen(buf)+1;\r
+            SetMenuItemInfo(subMenu, j, TRUE, &info);\r
+          }\r
+    return subMenu;\r
+}\r
+\r
+void\r
+TranslateMenus(int addLanguage)\r
+{\r
+    int i;\r
+    WIN32_FIND_DATA fileData;\r
+    HANDLE hFind;\r
+#define IDM_English 1970\r
+    if(1) {\r
+        HMENU mainMenu = GetMenu(hwndMain);\r
+        for (i=GetMenuItemCount(mainMenu)-1; i>=0; i--) {\r
+          HMENU subMenu = GetSubMenu(mainMenu, i);\r
+          ModifyMenu(mainMenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP|EnableMenuItem(mainMenu, i, MF_BYPOSITION),\r
+                                                                  (UINT) subMenu, T_(menuBarText[tinyLayout][i]));\r
+          TranslateOneMenu(i, subMenu);\r
+        }\r
+        DrawMenuBar(hwndMain);\r
+    }\r
+\r
+    if(!addLanguage) return;\r
+    if((hFind = FindFirstFile("*.LNG", &fileData)) != INVALID_HANDLE_VALUE) {\r
+        HMENU mainMenu = GetMenu(hwndMain);\r
+        HMENU subMenu = GetSubMenu(mainMenu, GetMenuItemCount(mainMenu)-1);\r
+        AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);\r
+        AppendMenu(subMenu, MF_ENABLED|MF_STRING|(barbaric?MF_UNCHECKED:MF_CHECKED), (UINT_PTR) IDM_English, (LPCTSTR) "English");\r
+        i = 0; lastChecked = IDM_English;\r
+        do {\r
+            char *p, *q = fileData.cFileName;\r
+            int checkFlag = MF_UNCHECKED;\r
+            languageFile[i] = strdup(q);\r
+            if(barbaric && !strcmp(oldLanguage, q)) {\r
+                checkFlag = MF_CHECKED;\r
+                lastChecked = IDM_English + i + 1;\r
+                CheckMenuItem(mainMenu, IDM_English, MF_BYCOMMAND|MF_UNCHECKED);\r
+            }\r
+            *q = ToUpper(*q); while(*++q) *q = ToLower(*q);\r
+            p = strstr(fileData.cFileName, ".lng");\r
+            if(p) *p = 0;\r
+            AppendMenu(subMenu, MF_ENABLED|MF_STRING|checkFlag, (UINT_PTR) IDM_English + ++i, (LPCTSTR) fileData.cFileName);\r
+        } while(FindNextFile(hFind, &fileData));\r
+        FindClose(hFind);\r
+    }\r
+}\r
+\r
+#endif\r
+\r
 typedef struct {\r
   char *name;\r
   int squareSize;\r
@@ -232,63 +518,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), MF(GAMELIST_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), MF(GAMELIST_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), MF(GAMELIST_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), MF(GAMELIST_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), MF(GAMELIST_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), MF(GAMELIST_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), MF(GAMELIST_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), MF(GAMELIST_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), MF(GAMELIST_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), MF(GAMELIST_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),  MF(GAMELIST_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),  MF(GAMELIST_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),  MF(GAMELIST_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),  MF(GAMELIST_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), MF(GAMELIST_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), MF(GAMELIST_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), MF (GAMELIST_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), MF(GAMELIST_FONT_ALL) },\r
 };\r
 \r
 MyFont *font[NUM_SIZES][NUM_FONTS];\r
@@ -313,10 +563,10 @@ MyButtonDesc buttonDesc[N_BUTTONS] =
 };\r
 \r
 int tinyLayout = 0, smallLayout = 0;\r
-#define MENU_BAR_ITEMS 6\r
+#define MENU_BAR_ITEMS 9\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
+  { N_("&File"), N_("&Edit"), N_("&View"), N_("&Mode"), N_("&Action"), N_("E&ngine"), N_("&Options"), N_("&Help"), NULL },\r
+  { N_("&F"), N_("&E"), N_("&V"), N_("&M"), N_("&A"), N_("&N"), N_("&O"), N_("&H"), NULL },\r
 };\r
 \r
 \r
@@ -324,17 +574,17 @@ MySound sounds[(int)NSoundClasses];
 MyTextAttribs textAttribs[(int)NColorClasses];\r
 \r
 MyColorizeAttribs colorizeAttribs[] = {\r
-  { (COLORREF)0, 0, "Shout Text" },\r
-  { (COLORREF)0, 0, "SShout/CShout" },\r
-  { (COLORREF)0, 0, "Channel 1 Text" },\r
-  { (COLORREF)0, 0, "Channel Text" },\r
-  { (COLORREF)0, 0, "Kibitz Text" },\r
-  { (COLORREF)0, 0, "Tell Text" },\r
-  { (COLORREF)0, 0, "Challenge Text" },\r
-  { (COLORREF)0, 0, "Request Text" },\r
-  { (COLORREF)0, 0, "Seek Text" },\r
-  { (COLORREF)0, 0, "Normal Text" },\r
-  { (COLORREF)0, 0, "None" }\r
+  { (COLORREF)0, 0, N_("Shout Text") },\r
+  { (COLORREF)0, 0, N_("SShout/CShout") },\r
+  { (COLORREF)0, 0, N_("Channel 1 Text") },\r
+  { (COLORREF)0, 0, N_("Channel Text") },\r
+  { (COLORREF)0, 0, N_("Kibitz Text") },\r
+  { (COLORREF)0, 0, N_("Tell Text") },\r
+  { (COLORREF)0, 0, N_("Challenge Text") },\r
+  { (COLORREF)0, 0, N_("Request Text") },\r
+  { (COLORREF)0, 0, N_("Seek Text") },\r
+  { (COLORREF)0, 0, N_("Normal Text") },\r
+  { (COLORREF)0, 0, N_("None") }\r
 };\r
 \r
 \r
@@ -343,15 +593,7 @@ static char *commentTitle;
 static char *commentText;\r
 static int commentIndex;\r
 static Boolean editComment = FALSE;\r
-HWND commentDialog = NULL;\r
-BOOLEAN commentDialogUp = FALSE;\r
-static int commentX, commentY, commentH, commentW;\r
 \r
-static char *analysisTitle;\r
-static char *analysisText;\r
-HWND analysisDialog = NULL;\r
-BOOLEAN analysisDialogUp = FALSE;\r
-static int analysisX, analysisY, analysisH, analysisW;\r
 \r
 char errorTitle[MSG_SIZ];\r
 char errorMessage[2*MSG_SIZ];\r
@@ -413,10 +655,38 @@ LRESULT CALLBACK
   StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);\r
 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
-int NewGameFRC();
 \r
+/* [AS] */\r
+int NewGameFRC();\r
+int GameListOptions();\r
+\r
+int dummy; // [HGM] for obsolete args\r
+\r
+HWND hwndMain = NULL;        /* root window*/\r
+HWND hwndConsole = NULL;\r
+HWND commentDialog = NULL;\r
+HWND moveHistoryDialog = NULL;\r
+HWND evalGraphDialog = NULL;\r
+HWND engineOutputDialog = NULL;\r
+HWND gameListDialog = NULL;\r
+HWND editTagsDialog = NULL;\r
+\r
+int commentUp = FALSE;\r
+\r
+WindowPlacement wpMain;\r
+WindowPlacement wpConsole;\r
+WindowPlacement wpComment;\r
+WindowPlacement wpMoveHistory;\r
+WindowPlacement wpEvalGraph;\r
+WindowPlacement wpEngineOutput;\r
+WindowPlacement wpGameList;\r
+WindowPlacement wpTags;\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
@@ -452,6 +722,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
@@ -463,7 +753,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
@@ -477,8 +768,15 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
     return (FALSE);\r
   }\r
 \r
+  JAWS_INIT\r
+  TranslateMenus(1);\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
@@ -487,12 +785,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
@@ -508,6 +887,26 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  *\r
 \*---------------------------------------------------------------------------*/\r
 \r
+void\r
+SetUserLogo()\r
+{   // update user logo if necessary\r
+    static char oldUserName[MSG_SIZ], dir[MSG_SIZ], *curName;\r
+\r
+    if(appData.autoLogo) {\r
+         curName = UserName();\r
+         if(strcmp(curName, oldUserName)) {\r
+               GetCurrentDirectory(MSG_SIZ, dir);\r
+               SetCurrentDirectory(installDir);\r
+               snprintf(oldUserName, MSG_SIZ, "logos\\%s.bmp", curName);\r
+               userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );    \r
+               safeStrCpy(oldUserName, curName, sizeof(oldUserName)/sizeof(oldUserName[0]) );\r
+               if(userLogo == NULL)\r
+                   userLogo = LoadImage( 0, "logos\\dummy.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ); \r
+               SetCurrentDirectory(dir); /* return to prev directory */\r
+         }\r
+    }\r
+}\r
+\r
 BOOL\r
 InitApplication(HINSTANCE hInstance)\r
 {\r
@@ -550,11 +949,39 @@ 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
+VOID\r
+LoadLogo(ChessProgramState *cps, int n, Boolean ics)\r
+{\r
+  char buf[MSG_SIZ], dir[MSG_SIZ];\r
+  GetCurrentDirectory(MSG_SIZ, dir);\r
+  SetCurrentDirectory(installDir);\r
+  if( appData.logo[n] && appData.logo[n][0] != NULLCHAR) {\r
+      cps->programLogo = LoadImage( 0, appData.logo[n], IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );\r
+\r
+      if (cps->programLogo == NULL && appData.debugMode) {\r
+          fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.logo[n] );\r
+      }\r
+  } else if(appData.autoLogo) {\r
+      if(ics) { // [HGM] logo: in ICS mode second can be used for ICS\r
+       sprintf(buf, "logos\\%s.bmp", appData.icsHost);\r
+       cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );\r
+      } else\r
+      if(appData.directory[n] && appData.directory[n][0]) {\r
+        SetCurrentDirectory(appData.directory[n]);\r
+       cps->programLogo = LoadImage( 0, "logo.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );     \r
+      }\r
+  }\r
+  SetCurrentDirectory(dir); /* return to prev directory */\r
 }\r
 \r
 BOOL\r
@@ -566,20 +993,39 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
   char *filepart;\r
 \r
   hInst = hInstance;   /* Store instance handle in our global variable */\r
+  programName = szAppName;\r
 \r
   if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {\r
     *filepart = NULLCHAR;\r
   } 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
+  /* xboard, and older WinBoards, controlled the move sound with the\r
+     appData.ringBellAfterMoves option.  In the current WinBoard, we\r
+     always turn the option on (so that the backend will call us),\r
+     then let the user turn the sound off by setting it to silence if\r
+     desired.  To accommodate old winboard.ini files saved by old\r
+     versions of WinBoard, we also turn off the sound if the option\r
+     was initially set to false. [HGM] taken out of InitAppData */\r
+  if (!appData.ringBellAfterMoves) {\r
+    sounds[(int)SoundMove].name = strdup("");\r
+    appData.ringBellAfterMoves = TRUE;\r
+  }\r
   if (appData.debugMode) {\r
-    debugFP = fopen(appData.nameOfDebugFile, "w");
+    debugFP = fopen(appData.nameOfDebugFile, "w");\r
     setbuf(debugFP, NULL);\r
   }\r
 \r
+  LoadLanguageFile(appData.language);\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
@@ -592,6 +1038,12 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
     return (FALSE);\r
   }\r
 \r
+  /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */\r
+  LoadLogo(&first, 0, FALSE);\r
+  LoadLogo(&second, 1, appData.icsActive);\r
+\r
+  SetUserLogo();\r
+\r
   iconWhite = LoadIcon(hInstance, "icon_white");\r
   iconBlack = LoadIcon(hInstance, "icon_black");\r
   iconCurrent = iconWhite;\r
@@ -601,548 +1053,171 @@ 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 */
-  ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
-
-  if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
-      liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
-      liteBackTextureMode = appData.liteBackTextureMode;
-
-      if (liteBackTexture == NULL && appData.debugMode) {
-          fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
-      }
-  }
-
-  if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
-      darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
-      darkBackTextureMode = appData.darkBackTextureMode;
-
-      if (darkBackTexture == NULL && appData.debugMode) {
-          fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
-      }
-  }
-
-  mysrandom( (unsigned) time(NULL) );
-
-  /* Make a console window if needed */\r
-  if (appData.icsActive) {\r
-    ConsoleCreate();\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
-  InitBackEnd2();\r
+  if( wpEvalGraph.visible ) {\r
+      EvalGraphPopUp();\r
+  }\r
+\r
+  if( wpEngineOutput.visible ) {\r
+      EngineOutputPopUp();\r
+  }\r
 \r
   /* Make the window visible; update its client area; and return "success" */\r
-  EnsureOnScreen(&boardX, &boardY);\r
+  EnsureOnScreen(&wpMain.x, &wpMain.y, minX, minY);\r
   wp.length = sizeof(WINDOWPLACEMENT);\r
   wp.flags = 0;\r
   wp.showCmd = nCmdShow;\r
   wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;\r
-  wp.rcNormalPosition.left = boardX;\r
-  wp.rcNormalPosition.right = boardX + winWidth;\r
-  wp.rcNormalPosition.top = boardY;\r
-  wp.rcNormalPosition.bottom = boardY + winHeight;\r
+  wp.rcNormalPosition.left = wpMain.x;\r
+  wp.rcNormalPosition.right = wpMain.x + wpMain.width;\r
+  wp.rcNormalPosition.top = wpMain.y;\r
+  wp.rcNormalPosition.bottom = wpMain.y + wpMain.height;\r
   SetWindowPlacement(hwndMain, &wp);\r
 \r
-  SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,\r
-              0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);\r
-
-  /* [AS] Disable the FRC stuff if not playing the proper variant */
-  if( gameInfo.variant != VariantFischeRandom ) {
-      EnableMenuItem( GetMenu(hwndMain), IDM_NewGameFRC, MF_GRAYED );
-  }
-
+  InitBackEnd2(); // [HGM] moved until after all windows placed, to save correct position if fatal error on engine start\r
+\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
                  0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);\r
 #endif\r
     ShowWindow(hwndConsole, nCmdShow);\r
+    if(appData.chatBoxes) { // [HGM] chat: open chat boxes\r
+      char buf[MSG_SIZ], *p = buf, *q;\r
+       safeStrCpy(buf, appData.chatBoxes, sizeof(buf)/sizeof(buf[0]) );\r
+      do {\r
+       q = strchr(p, ';');\r
+       if(q) *q++ = 0;\r
+       if(*p) ChatPopUp(p);\r
+      } while(p=q);\r
+    }\r
+    SetActiveWindow(hwndConsole);\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
 }\r
 \r
+VOID\r
+InitMenuChecks()\r
+{\r
+  HMENU hmenu = GetMenu(hwndMain);\r
+\r
+  (void) EnableMenuItem(hmenu, IDM_CommPort,\r
+                       MF_BYCOMMAND|((appData.icsActive &&\r
+                                      *appData.icsCommPort != NULLCHAR) ?\r
+                                     MF_ENABLED : MF_GRAYED));\r
+  (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,\r
+                      MF_BYCOMMAND|(saveSettingsOnExit ?\r
+                                    MF_CHECKED : MF_UNCHECKED));\r
+}\r
 \r
-typedef enum {\r
-  ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone, \r
-  ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,\r
-  ArgSettingsFilename\r
-} ArgType;\r
+//---------------------------------------------------------------------------------------------------------\r
 \r
-typedef struct {\r
-  char *argName;\r
-  ArgType argType;\r
-  /***\r
-  union {\r
-    String *pString;       // ArgString\r
-    int *pInt;             // ArgInt\r
-    float *pFloat;         // ArgFloat\r
-    Boolean *pBoolean;     // ArgBoolean\r
-    COLORREF *pColor;      // ArgColor\r
-    ColorClass cc;         // ArgAttribs\r
-    String *pFilename;     // ArgFilename\r
-    BoardSize *pBoardSize; // ArgBoardSize\r
-    int whichFont;         // ArgFont\r
-    DCB *pDCB;             // ArgCommSettings\r
-    String *pFilename;     // ArgSettingsFilename\r
-  } argLoc;\r
-  ***/\r
-  LPVOID argLoc;\r
-  BOOL save;\r
-} ArgDescriptor;\r
-\r
-int junk;\r
-ArgDescriptor argDescriptors[] = {\r
-  /* positional arguments */\r
-  { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },\r
-  { "", ArgNone, NULL },\r
-  /* keyword arguments */\r
-  { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },\r
-  { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },\r
-  { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },\r
-  { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },\r
-  { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },\r
-  { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },\r
-  { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },\r
-  { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },\r
-  { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },\r
-  { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },\r
-  { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },\r
-  { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },\r
-  { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },\r
-  { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },\r
-  { "initString", ArgString, (LPVOID) &appData.initString, FALSE },\r
-  { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },\r
-  { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },\r
-  { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,\r
-    FALSE },\r
-  { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,\r
-    FALSE },\r
-  { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,\r
-    FALSE },\r
-  { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },\r
-  { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,\r
-    FALSE },\r
-  { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },\r
-  { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },\r
-  { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },\r
-  { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },\r
-  { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },\r
-  { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },\r
-  { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },\r
-  { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },\r
-  { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },\r
-  { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },\r
-  { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },\r
-  { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },\r
-  { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },\r
-  { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },\r
-  { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },\r
-  { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },\r
-  { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },\r
-  /*!!bitmapDirectory?*/\r
-  { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },\r
-  { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },\r
-  { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },\r
-  { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },\r
-  { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },\r
-  { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },\r
-  { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },\r
-  { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },\r
-  { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },\r
-  { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },\r
-  { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },\r
-  { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },\r
-  { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },\r
-  { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },\r
-  { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },\r
-  { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },\r
-  { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },\r
-  { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },\r
-  { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },\r
-  { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },\r
-  { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },\r
-  { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },\r
-  { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },\r
-  { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },\r
-  { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },\r
-  { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },\r
-  { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },\r
-  { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },\r
-  { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },\r
-  { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },\r
-  { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },\r
-  { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },\r
-  { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },\r
-  { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },\r
-  { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },\r
-  { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },\r
-  { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },\r
-  { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },\r
-  { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },\r
-  { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },\r
-  { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },\r
-  { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },\r
-  { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },\r
-  { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },\r
-  { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },\r
-  { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },\r
-  { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },\r
-  { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },\r
-  { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },\r
-  { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },\r
-  { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },\r
-  { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },\r
-  { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },\r
-  { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },\r
-  { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },\r
-  { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },\r
-  { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },\r
-  { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },\r
-  { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },\r
-  { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },\r
-  { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },\r
-  { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },\r
-  { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },\r
-  { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },\r
-  { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },\r
-  { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },\r
-  { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },\r
-  { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },\r
-  { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },\r
-  { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },\r
-  { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },\r
-  { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },\r
-  { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },\r
-  { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },\r
-  { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },\r
-  { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },\r
-  { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },\r
-  { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },\r
-  { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },\r
-  { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },\r
-  { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },\r
-  { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },\r
-  { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },\r
-  { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },\r
-  { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },\r
-  { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },\r
-  { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },\r
-  { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },\r
-  { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },\r
-  { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },\r
-  { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },\r
-  { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },\r
-  { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },\r
-  { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, \r
-    FALSE }, /* only so that old WinBoard.ini files from betas can be read */\r
-  { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },\r
-  { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },\r
-  { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },\r
-  { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },\r
-  { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },\r
-  { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },\r
-  { "boardSize", ArgBoardSize, (LPVOID) &boardSize,\r
-    TRUE }, /* must come after all fonts */\r
-  { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },\r
-  { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,\r
-    FALSE }, /* historical; kept only so old winboard.ini files will parse */\r
-  { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },\r
-  { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },\r
-  { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },\r
-  { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },\r
-  { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },\r
-  { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },\r
-  { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },\r
-  { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },\r
-  { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },\r
-  { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },\r
-  { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },\r
-  { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },\r
-  { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },\r
-  { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },\r
-  { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },\r
-  { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },\r
-  { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },\r
-  { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },\r
-  { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },\r
-  { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },\r
-  { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },\r
-  { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },\r
-  { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },\r
-  { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },\r
-  { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },\r
-  { "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
-  { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },\r
-  { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },\r
-  { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },\r
-  { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },\r
-  { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },\r
-  { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },\r
-  { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },\r
-  { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },\r
-  { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },\r
-  { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },\r
-  { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },\r
-  { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },\r
-  { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },\r
-  { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },\r
-  { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },\r
-  { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },\r
-  { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },\r
-  { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },\r
-  { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },\r
-  { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },\r
-  { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },\r
-  { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },\r
-  { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },\r
-  { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },\r
-  { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },\r
-  { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },\r
-  { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },\r
-  { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },\r
-  { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },\r
-  { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },\r
-  { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },\r
-  { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},\r
-  { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},\r
-  { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},\r
-  { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},\r
-  { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},\r
-  { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},\r
-  { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},\r
-  { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },\r
-  { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },\r
-  { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },\r
-  { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },\r
-  { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },\r
-  { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },\r
-  { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },\r
-  { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },\r
-  { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },\r
-  { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },\r
-  { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },\r
-  { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },\r
-  { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },\r
-  { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },\r
-  { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },\r
-  { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },\r
-  { "highlightLastMove", ArgBoolean,\r
-    (LPVOID) &appData.highlightLastMove, TRUE },\r
-  { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },\r
-  { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },\r
-  { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },\r
-  { "highlightDragging", ArgBoolean,\r
-    (LPVOID) &appData.highlightDragging, TRUE },\r
-  { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },\r
-  { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },\r
-  { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },\r
-  { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },\r
-  { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },\r
-  { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },\r
-  { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },\r
-  { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },\r
-  { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },\r
-  { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },\r
-  { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },\r
-  { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },\r
-  { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },\r
-  { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },\r
-  { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },\r
-  { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },\r
-  { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },\r
-  { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },\r
-  { "soundShout", ArgFilename,\r
-    (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },\r
-  { "soundSShout", ArgFilename,\r
-    (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },\r
-  { "soundChannel1", ArgFilename,\r
-    (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },\r
-  { "soundChannel", ArgFilename,\r
-    (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },\r
-  { "soundKibitz", ArgFilename,\r
-    (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },\r
-  { "soundTell", ArgFilename,\r
-    (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },\r
-  { "soundChallenge", ArgFilename,\r
-    (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },\r
-  { "soundRequest", ArgFilename,\r
-    (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },\r
-  { "soundSeek", ArgFilename,\r
-    (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },\r
-  { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },\r
-  { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },\r
-  { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },\r
-  { "soundIcsLoss", ArgFilename, \r
-    (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },\r
-  { "soundIcsDraw", ArgFilename, \r
-    (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },\r
-  { "soundIcsUnfinished", ArgFilename, \r
-    (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},\r
-  { "soundIcsAlarm", ArgFilename, \r
-    (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },\r
-  { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },\r
-  { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },\r
-  { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },\r
-  { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },\r
-  { "reuseChessPrograms", ArgBoolean,\r
-    (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */\r
-  { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },\r
-  { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },\r
-  { "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
-  { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },\r
-  { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },\r
-  { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },\r
-  { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },\r
-  { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },\r
-  { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },\r
-  { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,\r
-    TRUE },\r
-  { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,\r
-    TRUE },\r
-  { "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, FALSE },
-  { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
-  { "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 */
-  { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, TRUE },
-  { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, TRUE },
-  { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
-  { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
-  { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
-  { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
-  { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
-  { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
-  { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
-  { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
-  { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
-  { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
-  { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
-  { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
-  { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
-  { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
-  { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
-  { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
-  { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
-  { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
-  { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
-  { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
-  { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
-#ifdef ZIPPY\r
-  { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },\r
-  { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },\r
-  { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },\r
-  { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },\r
-  { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },\r
-  { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },\r
-  { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },\r
-  { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },\r
-  { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },\r
-  { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },\r
-  { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },\r
-  { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },\r
-  { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,\r
-    FALSE },\r
-  { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },\r
-  { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },\r
-  { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },\r
-  { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },\r
-  { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },\r
-  { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },\r
-  { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,\r
-    FALSE },\r
-  { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },\r
-  { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },\r
-  { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },\r
-  { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },\r
-  { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },\r
-  { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },\r
-  { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },\r
-  { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },\r
-  { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },\r
-  { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },\r
-  { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },\r
-  { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },\r
-  { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },\r
-  { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },\r
-  { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },\r
-  { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, 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
-  { NULL, ArgNone, NULL, FALSE }\r
-};\r
+#define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)\r
+#define XBOARD FALSE\r
 \r
+#define OPTCHAR "/"\r
+#define SEPCHAR "="\r
 \r
-/* Kludge for indirection files on command line */\r
-char* lastIndirectionFilename;\r
-ArgDescriptor argDescriptorIndirection =\r
-{ "", ArgSettingsFilename, (LPVOID) NULL, FALSE };\r
+#include "args.h"\r
 \r
+// front-end part of option handling\r
 \r
 VOID\r
-ExitArgError(char *msg, char *badArg)\r
+LFfromMFP(LOGFONT* lf, MyFontParams *mfp)\r
 {\r
-  char buf[MSG_SIZ];\r
+  HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);\r
+  lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);\r
+  DeleteDC(hdc);\r
+  lf->lfWidth = 0;\r
+  lf->lfEscapement = 0;\r
+  lf->lfOrientation = 0;\r
+  lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;\r
+  lf->lfItalic = mfp->italic;\r
+  lf->lfUnderline = mfp->underline;\r
+  lf->lfStrikeOut = mfp->strikeout;\r
+  lf->lfCharSet = mfp->charset;\r
+  lf->lfOutPrecision = OUT_DEFAULT_PRECIS;\r
+  lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;\r
+  lf->lfQuality = DEFAULT_QUALITY;\r
+  lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;\r
+    safeStrCpy(lf->lfFaceName, mfp->faceName, sizeof(lf->lfFaceName)/sizeof(lf->lfFaceName[0]) );\r
+}\r
 \r
-  sprintf(buf, "%s %s", msg, badArg);\r
-  DisplayFatalError(buf, 0, 2);\r
-  exit(2);\r
+void\r
+CreateFontInMF(MyFont *mf)\r
+{ \r
+  LFfromMFP(&mf->lf, &mf->mfp);\r
+  if (mf->hf) DeleteObject(mf->hf);\r
+  mf->hf = CreateFontIndirect(&mf->lf);\r
 }\r
 \r
+// [HGM] This platform-dependent table provides the location for storing the color info\r
+void *\r
+colorVariable[] = {\r
+  &whitePieceColor, \r
+  &blackPieceColor, \r
+  &lightSquareColor,\r
+  &darkSquareColor, \r
+  &highlightSquareColor,\r
+  &premoveHighlightColor,\r
+  NULL,\r
+  &consoleBackgroundColor,\r
+  &appData.fontForeColorWhite,\r
+  &appData.fontBackColorWhite,\r
+  &appData.fontForeColorBlack,\r
+  &appData.fontBackColorBlack,\r
+  &appData.evalHistColorWhite,\r
+  &appData.evalHistColorBlack,\r
+  &appData.highlightArrowColor,\r
+};\r
+\r
 /* Command line font name parser.  NULL name means do nothing.\r
    Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"\r
    For backward compatibility, syntax without the colon is also\r
@@ -1157,7 +1232,7 @@ ParseFontName(char *name, MyFontParams *mfp)
   q = strchr(p, ':');\r
   if (q) {\r
     if (q - p >= sizeof(mfp->faceName))\r
-      ExitArgError("Font name too long:", name);\r
+      ExitArgError(_("Font name too long:"), name, TRUE);\r
     memcpy(mfp->faceName, p, q - p);\r
     mfp->faceName[q - p] = NULLCHAR;\r
     p = q + 1;\r
@@ -1166,19 +1241,53 @@ ParseFontName(char *name, MyFontParams *mfp)
     while (*p && !isdigit(*p)) {\r
       *q++ = *p++;\r
       if (q - mfp->faceName >= sizeof(mfp->faceName))\r
-       ExitArgError("Font name too long:", name);\r
+       ExitArgError(_("Font name too long:"), name, TRUE);\r
     }\r
     while (q > mfp->faceName && q[-1] == ' ') q--;\r
     *q = NULLCHAR;\r
   }\r
-  if (!*p) ExitArgError("Font point size missing:", name);\r
+  if (!*p) ExitArgError(_("Font point size missing:"), name, TRUE);\r
   mfp->pointSize = (float) atof(p);\r
   mfp->bold = (strchr(p, 'b') != NULL);\r
   mfp->italic = (strchr(p, 'i') != NULL);\r
   mfp->underline = (strchr(p, 'u') != NULL);\r
   mfp->strikeout = (strchr(p, 's') != NULL);\r
+  mfp->charset = DEFAULT_CHARSET;\r
+  q = strchr(p, 'c');\r
+  if (q)\r
+    mfp->charset = (BYTE) atoi(q+1);\r
+}\r
+\r
+void\r
+ParseFont(char *name, int number)\r
+{ // wrapper to shield back-end from 'font'\r
+  ParseFontName(name, &font[boardSize][number]->mfp);\r
 }\r
 \r
+void\r
+SetFontDefaults()\r
+{ // in WB  we have a 2D array of fonts; this initializes their description\r
+  int i, j;\r
+  /* Point font array elements to structures and\r
+     parse default font names */\r
+  for (i=0; i<NUM_FONTS; i++) {\r
+    for (j=0; j<NUM_SIZES; j++) {\r
+      font[j][i] = &fontRec[j][i];\r
+      ParseFontName(font[j][i]->def, &font[j][i]->mfp);\r
+    }\r
+  }\r
+}\r
+\r
+void\r
+CreateFonts()\r
+{ // here we create the actual fonts from the selected descriptions\r
+  int i, j;\r
+  for (i=0; i<NUM_FONTS; i++) {\r
+    for (j=0; j<NUM_SIZES; j++) {\r
+      CreateFontInMF(font[j][i]);\r
+    }\r
+  }\r
+}\r
 /* Color name parser.\r
    X version accepts X color names, but this one\r
    handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */\r
@@ -1194,15 +1303,21 @@ ParseColorName(char *name)
       &red, &green, &blue);\r
   }\r
   if (count != 3) {\r
-    sprintf(buf, "Can't parse color name %s", name);\r
+    snprintf(buf, MSG_SIZ, _("Can't parse color name %s"), name);\r
     DisplayError(buf, 0);\r
     return RGB(0, 0, 0);\r
   }\r
   return PALETTERGB(red, green, blue);\r
 }\r
 \r
+void\r
+ParseColor(int n, char *name)\r
+{ // for WinBoard the color is an int, which needs to be derived from the string\r
+  if(colorVariable[n]) *(int*)colorVariable[n] = ParseColorName(name);\r
+}\r
 \r
-void ParseAttribs(COLORREF *color, int *effects, char* argValue)\r
+void\r
+ParseAttribs(COLORREF *color, int *effects, char* argValue)\r
 {\r
   char *e = argValue;\r
   int eff = 0;\r
@@ -1219,471 +1334,52 @@ void ParseAttribs(COLORREF *color, int *effects, char* argValue)
   *color   = ParseColorName(e);\r
 }\r
 \r
+void\r
+ParseTextAttribs(ColorClass cc, char *s)\r
+{   // [HGM] front-end wrapper that does the platform-dependent call\r
+    // for XBoard we would set (&appData.colorShout)[cc] = strdup(s);\r
+    ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, s);\r
+}\r
 \r
-BoardSize\r
-ParseBoardSize(char *name)\r
-{\r
+void\r
+ParseBoardSize(void *addr, char *name)\r
+{ // [HGM] rewritten with return-value ptr to shield back-end from BoardSize\r
   BoardSize bs = SizeTiny;\r
   while (sizeInfo[bs].name != NULL) {\r
-    if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;\r
-    bs++;\r
-  }\r
-  ExitArgError("Unrecognized board size value", name);\r
-  return bs; /* not reached */\r
-}\r
-\r
-\r
-char\r
-StringGet(void *getClosure)\r
-{\r
-  char **p = (char **) getClosure;\r
-  return *((*p)++);\r
-}\r
-\r
-char\r
-FileGet(void *getClosure)\r
-{\r
-  int c;\r
-  FILE* f = (FILE*) getClosure;\r
-\r
-  c = getc(f);\r
-  if (c == EOF)\r
-    return NULLCHAR;\r
-  else\r
-    return (char) c;\r
-}\r
-\r
-/* Parse settings file named "name". If file found, return the\r
-   full name in fullname and return TRUE; else return FALSE */\r
-BOOLEAN\r
-ParseSettingsFile(char *name, char fullname[MSG_SIZ])\r
-{\r
-  char *dummy;\r
-  FILE *f;\r
-\r
-  if (SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy)) {\r
-    f = fopen(fullname, "r");\r
-    if (f != NULL) {\r
-      ParseArgs(FileGet, f);\r
-      fclose(f);\r
-      return TRUE;\r
-    }\r
-  }\r
-  return FALSE;\r
-}\r
-\r
-VOID\r
-ParseArgs(GetFunc get, void *cl)\r
-{\r
-  char argName[ARG_MAX];\r
-  char argValue[ARG_MAX];\r
-  ArgDescriptor *ad;\r
-  char start;\r
-  char *q;\r
-  int i, octval;\r
-  char ch;\r
-  int posarg = 0;\r
-\r
-  ch = get(cl);\r
-  for (;;) {\r
-    while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);\r
-    if (ch == NULLCHAR) break;\r
-    if (ch == ';') {\r
-      /* Comment to end of line */\r
-      ch = get(cl);\r
-      while (ch != '\n' && ch != NULLCHAR) ch = get(cl);\r
-      continue;\r
-    } else if (ch == '/' || ch == '-') {\r
-      /* Switch */\r
-      q = argName;\r
-      while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&\r
-            ch != '\n' && ch != '\t') {\r
-       *q++ = ch;\r
-       ch = get(cl);\r
-      }\r
-      *q = NULLCHAR;\r
-\r
-      for (ad = argDescriptors; ad->argName != NULL; ad++)\r
-       if (strcmp(ad->argName, argName + 1) == 0) break;\r
-\r
-      if (ad->argName == NULL)\r
-       ExitArgError("Unrecognized argument", argName);\r
-\r
-    } else if (ch == '@') {\r
-      /* Indirection file */\r
-      ad = &argDescriptorIndirection;\r
-      ch = get(cl);\r
-    } else {\r
-      /* Positional argument */\r
-      ad = &argDescriptors[posarg++];\r
-      strcpy(argName, ad->argName);\r
-    }\r
-\r
-    if (ad->argType == ArgTrue) {\r
-      *(Boolean *) ad->argLoc = TRUE;\r
-      continue;\r
-    }\r
-    if (ad->argType == ArgFalse) {\r
-      *(Boolean *) ad->argLoc = FALSE;\r
-      continue;\r
-    }\r
-\r
-    while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);\r
-    if (ch == NULLCHAR || ch == '\n') {\r
-      ExitArgError("No value provided for argument", argName);\r
-    }\r
-    q = argValue;\r
-    if (ch == '{') {\r
-      // Quoting with { }.  No characters have to (or can) be escaped.\r
-      // Thus the string cannot contain a '}' character.\r
-      start = ch;\r
-      ch = get(cl);\r
-      while (start) {\r
-       switch (ch) {\r
-       case NULLCHAR:\r
-         start = NULLCHAR;\r
-         break;\r
-         \r
-       case '}':\r
-         ch = get(cl);\r
-         start = NULLCHAR;\r
-         break;\r
-\r
-       default:\r
-         *q++ = ch;\r
-         ch = get(cl);\r
-         break;\r
-       }\r
-      }          \r
-    } else if (ch == '\'' || ch == '"') {\r
-      // Quoting with ' ' or " ", with \ as escape character.\r
-      // Inconvenient for long strings that may contain Windows filenames.\r
-      start = ch;\r
-      ch = get(cl);\r
-      while (start) {\r
-       switch (ch) {\r
-       case NULLCHAR:\r
-         start = NULLCHAR;\r
-         break;\r
-\r
-       default:\r
-        not_special:\r
-         *q++ = ch;\r
-         ch = get(cl);\r
-         break;\r
-\r
-       case '\'':\r
-       case '\"':\r
-         if (ch == start) {\r
-           ch = get(cl);\r
-           start = NULLCHAR;\r
-           break;\r
-         } else {\r
-           goto not_special;\r
-         }\r
-\r
-       case '\\':\r
-          if (ad->argType == ArgFilename\r
-             || ad->argType == ArgSettingsFilename) {\r
-             goto not_special;\r
-         }\r
-         ch = get(cl);\r
-         switch (ch) {\r
-         case NULLCHAR:\r
-           ExitArgError("Incomplete \\ escape in value for", argName);\r
-           break;\r
-         case 'n':\r
-           *q++ = '\n';\r
-           ch = get(cl);\r
-           break;\r
-         case 'r':\r
-           *q++ = '\r';\r
-           ch = get(cl);\r
-           break;\r
-         case 't':\r
-           *q++ = '\t';\r
-           ch = get(cl);\r
-           break;\r
-         case 'b':\r
-           *q++ = '\b';\r
-           ch = get(cl);\r
-           break;\r
-         case 'f':\r
-           *q++ = '\f';\r
-           ch = get(cl);\r
-           break;\r
-         default:\r
-           octval = 0;\r
-           for (i = 0; i < 3; i++) {\r
-             if (ch >= '0' && ch <= '7') {\r
-               octval = octval*8 + (ch - '0');\r
-               ch = get(cl);\r
-             } else {\r
-               break;\r
-             }\r
-           }\r
-           if (i > 0) {\r
-             *q++ = (char) octval;\r
-           } else {\r
-             *q++ = ch;\r
-             ch = get(cl);\r
-           }\r
-           break;\r
-         }\r
-         break;\r
-       }\r
-      }\r
-    } else {\r
-      while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {\r
-       *q++ = ch;\r
-       ch = get(cl);\r
-      }\r
+    if (StrCaseCmp(name, sizeInfo[bs].name) == 0) {\r
+       *(BoardSize *)addr = bs;\r
+       return;\r
     }\r
-    *q = NULLCHAR;\r
-\r
-    switch (ad->argType) {\r
-    case ArgInt:\r
-      *(int *) ad->argLoc = atoi(argValue);\r
-      break;\r
-\r
-    case ArgFloat:\r
-      *(float *) ad->argLoc = (float) atof(argValue);\r
-      break;\r
-\r
-    case ArgString:\r
-    case ArgFilename:\r
-      *(char **) ad->argLoc = strdup(argValue);\r
-      break;\r
-\r
-    case ArgSettingsFilename:\r
-      {\r
-       char fullname[MSG_SIZ];\r
-       if (ParseSettingsFile(argValue, fullname)) {\r
-         if (ad->argLoc != NULL) {\r
-           *(char **) ad->argLoc = strdup(fullname);\r
-         }\r
-       } else {\r
-         if (ad->argLoc != NULL) {\r
-         } else {\r
-           ExitArgError("Failed to open indirection file", argValue);\r
-         }\r
-       }\r
-      }\r
-      break;\r
-\r
-    case ArgBoolean:\r
-      switch (argValue[0]) {\r
-      case 't':\r
-      case 'T':\r
-       *(Boolean *) ad->argLoc = TRUE;\r
-       break;\r
-      case 'f':\r
-      case 'F':\r
-       *(Boolean *) ad->argLoc = FALSE;\r
-       break;\r
-      default:\r
-       ExitArgError("Unrecognized boolean argument value", argValue);\r
-       break;\r
-      }\r
-      break;\r
-\r
-    case ArgColor:\r
-      *(COLORREF *)ad->argLoc = ParseColorName(argValue);\r
-      break;\r
-\r
-    case ArgAttribs: {\r
-      ColorClass cc = (ColorClass)ad->argLoc;\r
-      ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);\r
-      }\r
-      break;\r
-      \r
-    case ArgBoardSize:\r
-      *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);\r
-      break;\r
-\r
-    case ArgFont:\r
-      ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);\r
-      break;\r
-\r
-    case ArgCommSettings:\r
-      ParseCommSettings(argValue, &dcb);\r
-      break;\r
-\r
-    case ArgNone:\r
-      ExitArgError("Unrecognized argument", argValue);\r
-      break;\r
-    }\r
-  }\r
-}\r
-\r
-VOID\r
-LFfromMFP(LOGFONT* lf, MyFontParams *mfp)\r
-{\r
-  HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);\r
-  lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);\r
-  DeleteDC(hdc);\r
-  lf->lfWidth = 0;\r
-  lf->lfEscapement = 0;\r
-  lf->lfOrientation = 0;\r
-  lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;\r
-  lf->lfItalic = mfp->italic;\r
-  lf->lfUnderline = mfp->underline;\r
-  lf->lfStrikeOut = mfp->strikeout;\r
-  lf->lfCharSet = DEFAULT_CHARSET;\r
-  lf->lfOutPrecision = OUT_DEFAULT_PRECIS;\r
-  lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;\r
-  lf->lfQuality = DEFAULT_QUALITY;\r
-  lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;\r
-  strcpy(lf->lfFaceName, mfp->faceName);\r
-}\r
-\r
-VOID\r
-CreateFontInMF(MyFont *mf)\r
-{\r
-  LFfromMFP(&mf->lf, &mf->mfp);\r
-  if (mf->hf) DeleteObject(mf->hf);\r
-  mf->hf = CreateFontIndirect(&mf->lf);\r
-}\r
-\r
-VOID\r
-SetDefaultTextAttribs()\r
-{\r
-  ColorClass cc;\r
-  for (cc = (ColorClass)0; cc < NColorClasses; cc++) {\r
-    ParseAttribs(&textAttribs[cc].color, \r
-                &textAttribs[cc].effects, \r
-                defaultTextAttribs[cc]);\r
+    bs++;\r
   }\r
+  ExitArgError(_("Unrecognized board size value"), name, TRUE);\r
 }\r
 \r
-VOID\r
-SetDefaultSounds()\r
-{\r
+void\r
+LoadAllSounds()\r
+{ // [HGM] import name from appData first\r
   ColorClass cc;\r
   SoundClass sc;\r
-  for (cc = (ColorClass)0; cc < NColorClasses; cc++) {\r
+  for (cc = (ColorClass)0; cc < ColorNormal; cc++) {\r
+    textAttribs[cc].sound.name = strdup((&appData.soundShout)[cc]);\r
+    textAttribs[cc].sound.data = NULL;\r
+    MyLoadSound(&textAttribs[cc].sound);\r
+  }\r
+  for (cc = ColorNormal; cc < NColorClasses; cc++) {\r
     textAttribs[cc].sound.name = strdup("");\r
     textAttribs[cc].sound.data = NULL;\r
   }\r
   for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {\r
-    sounds[sc].name = strdup("");\r
+    sounds[sc].name = strdup((&appData.soundMove)[sc]);\r
     sounds[sc].data = NULL;\r
-  }\r
-  sounds[(int)SoundBell].name = strdup(SOUND_BELL);\r
-}\r
-\r
-VOID\r
-LoadAllSounds()\r
-{\r
-  ColorClass cc;\r
-  SoundClass sc;\r
-  for (cc = (ColorClass)0; cc < NColorClasses; cc++) {\r
-    MyLoadSound(&textAttribs[cc].sound);\r
-  }\r
-  for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {\r
     MyLoadSound(&sounds[sc]);\r
   }\r
 }\r
 \r
-VOID\r
-InitAppData(LPSTR lpCmdLine)\r
+void\r
+SetCommPortDefaults()\r
 {\r
-  int i, j;\r
-  char buf[ARG_MAX], currDir[MSG_SIZ];\r
-  char *dummy, *p;\r
-\r
-  programName = szAppName;\r
-\r
-  /* Initialize to defaults */\r
-  lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);\r
-  darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);\r
-  whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);\r
-  blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);\r
-  highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);\r
-  premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);\r
-  consoleBackgroundColor = ParseColorName(COLOR_BKGD);\r
-  SetDefaultTextAttribs();\r
-  SetDefaultSounds();\r
-  appData.movesPerSession = MOVES_PER_SESSION;\r
-  appData.initString = INIT_STRING;\r
-  appData.secondInitString = INIT_STRING;\r
-  appData.firstComputerString = COMPUTER_STRING;\r
-  appData.secondComputerString = COMPUTER_STRING;\r
-  appData.firstChessProgram = FIRST_CHESS_PROGRAM;\r
-  appData.secondChessProgram = SECOND_CHESS_PROGRAM;\r
-  appData.firstPlaysBlack = FALSE;\r
-  appData.noChessProgram = FALSE;\r
-  chessProgram = FALSE;\r
-  appData.firstHost = FIRST_HOST;\r
-  appData.secondHost = SECOND_HOST;\r
-  appData.firstDirectory = FIRST_DIRECTORY;\r
-  appData.secondDirectory = SECOND_DIRECTORY;\r
-  appData.bitmapDirectory = "";\r
-  appData.remoteShell = REMOTE_SHELL;\r
-  appData.remoteUser = "";\r
-  appData.timeDelay = TIME_DELAY;\r
-  appData.timeControl = TIME_CONTROL;\r
-  appData.timeIncrement = TIME_INCREMENT;\r
-  appData.icsActive = FALSE;\r
-  appData.icsHost = "";\r
-  appData.icsPort = ICS_PORT;\r
-  appData.icsCommPort = ICS_COMM_PORT;\r
-  appData.icsLogon = ICS_LOGON;\r
-  appData.icsHelper = "";\r
-  appData.useTelnet = FALSE;\r
-  appData.telnetProgram = TELNET_PROGRAM;\r
-  appData.gateway = "";\r
-  appData.loadGameFile = "";\r
-  appData.loadGameIndex = 0;\r
-  appData.saveGameFile = "";\r
-  appData.autoSaveGames = FALSE;\r
-  appData.loadPositionFile = "";\r
-  appData.loadPositionIndex = 1;\r
-  appData.savePositionFile = "";\r
-  appData.matchMode = FALSE;\r
-  appData.matchGames = 0;\r
-  appData.monoMode = FALSE;\r
-  appData.debugMode = FALSE;\r
-  appData.clockMode = TRUE;\r
-  boardSize = (BoardSize) -1; /* determine by screen size */\r
-  appData.Iconic = FALSE; /*unused*/\r
-  appData.searchTime = "";\r
-  appData.searchDepth = 0;\r
-  appData.showCoords = FALSE;\r
-  appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/\r
-  appData.autoCallFlag = FALSE;\r
-  appData.flipView = FALSE;\r
-  appData.autoFlipView = TRUE;\r
-  appData.cmailGameName = "";\r
-  appData.alwaysPromoteToQueen = FALSE;\r
-  appData.oldSaveStyle = FALSE;\r
-  appData.quietPlay = FALSE;\r
-  appData.showThinking = FALSE;\r
-  appData.ponderNextMove = TRUE;\r
-  appData.periodicUpdates = TRUE;\r
-  appData.popupExitMessage = TRUE;\r
-  appData.popupMoveErrors = FALSE;\r
-  appData.autoObserve = FALSE;\r
-  appData.autoComment = FALSE;\r
-  appData.animate = TRUE;\r
-  appData.animSpeed = 10;\r
-  appData.animateDragging = TRUE;\r
-  appData.highlightLastMove = TRUE;\r
-  appData.getMoveList = TRUE;\r
-  appData.testLegality = TRUE;\r
-  appData.premove = TRUE;\r
-  appData.premoveWhite = FALSE;\r
-  appData.premoveWhiteText = "";\r
-  appData.premoveBlack = FALSE;\r
-  appData.premoveBlackText = "";\r
-  appData.icsAlarm = TRUE;\r
-  appData.icsAlarmTime = 5000;\r
-  appData.autoRaiseBoard = TRUE;\r
-  appData.localLineEditing = TRUE;\r
-  appData.colorize = TRUE;\r
-  appData.reuseFirst = TRUE;\r
-  appData.reuseSecond = TRUE;\r
-  appData.blindfold = 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
@@ -1698,797 +1394,692 @@ 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
-  settingsFileName = SETTINGS_FILE;\r
-  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
-  analysisH = CW_USEDEFAULT;\r
-  commentX = CW_USEDEFAULT; \r
-  commentY = CW_USEDEFAULT; \r
-  commentW = CW_USEDEFAULT;\r
-  commentH = CW_USEDEFAULT;\r
-  editTagsX = CW_USEDEFAULT; \r
-  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
-  secondChessProgramNames = SCP_NAMES;\r
-  appData.initialMode = "";\r
-  appData.variant = "normal";\r
-  appData.firstProtocolVersion = PROTOVER;\r
-  appData.secondProtocolVersion = PROTOVER;\r
-  appData.showButtonBar = TRUE;\r
-
-   /* [AS] New properties (see comments in header file) */
-  appData.firstScoreIsAbsolute = FALSE;
-  appData.secondScoreIsAbsolute = FALSE;
-  appData.saveExtendedInfoInPGN = FALSE;
-  appData.hideThinkingFromHuman = FALSE;
-  appData.liteBackTextureFile = "";
-  appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
-  appData.darkBackTextureFile = "";
-  appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
-  appData.renderPiecesWithFont = "";
-  appData.fontToPieceTable = "";
-  appData.fontBackColorWhite = 0;
-  appData.fontForeColorWhite = 0;
-  appData.fontBackColorBlack = 0;
-  appData.fontForeColorBlack = 0;
-  appData.fontPieceSize = 80;
-  appData.overrideLineGap = 1;
-  appData.adjudicateLossThreshold = 0;
-  appData.delayBeforeQuit = 0;
-  appData.delayAfterQuit = 0;
-  appData.nameOfDebugFile = "winboard.debug";
-  appData.pgnEventHeader = "Computer Chess Game";
-  appData.defaultFrcPosition = -1;
-
-#ifdef ZIPPY\r
-  appData.zippyTalk = ZIPPY_TALK;\r
-  appData.zippyPlay = ZIPPY_PLAY;\r
-  appData.zippyLines = ZIPPY_LINES;\r
-  appData.zippyPinhead = ZIPPY_PINHEAD;\r
-  appData.zippyPassword = ZIPPY_PASSWORD;\r
-  appData.zippyPassword2 = ZIPPY_PASSWORD2;\r
-  appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;\r
-  appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;\r
-  appData.zippyUseI = ZIPPY_USE_I;\r
-  appData.zippyBughouse = ZIPPY_BUGHOUSE;\r
-  appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;\r
-  appData.zippyGameEnd = ZIPPY_GAME_END;\r
-  appData.zippyGameStart = ZIPPY_GAME_START;\r
-  appData.zippyAdjourn = ZIPPY_ADJOURN;\r
-  appData.zippyAbort = ZIPPY_ABORT;\r
-  appData.zippyVariants = ZIPPY_VARIANTS;\r
-  appData.zippyMaxGames = ZIPPY_MAX_GAMES;\r
-  appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;\r
-#endif\r
+}\r
 \r
-  /* Point font array elements to structures and\r
-     parse default font names */\r
-  for (i=0; i<NUM_FONTS; i++) {\r
-    for (j=0; j<NUM_SIZES; j++) {\r
-      font[j][i] = &fontRec[j][i];\r
-      ParseFontName(font[j][i]->def, &font[j][i]->mfp);\r
+// [HGM] args: these three cases taken out to stay in front-end\r
+void\r
+SaveFontArg(FILE *f, ArgDescriptor *ad)\r
+{      // in WinBoard every board size has its own font, and the "argLoc" identifies the table,\r
+       // while the curent board size determines the element. This system should be ported to XBoard.\r
+       // What the table contains pointers to, and how to print the font description, remains platform-dependent\r
+        int bs;\r
+       for (bs=0; bs<NUM_SIZES; bs++) {\r
+         MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;\r
+          fprintf(f, "/size=%s ", sizeInfo[bs].name);\r
+         fprintf(f, "/%s=\"%s:%g%s%s%s%s%sc%d\"\n",\r
+           ad->argName, mfp->faceName, mfp->pointSize,\r
+            mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",\r
+           mfp->bold ? "b" : "",\r
+           mfp->italic ? "i" : "",\r
+           mfp->underline ? "u" : "",\r
+           mfp->strikeout ? "s" : "",\r
+            (int)mfp->charset);\r
+       }\r
+      }\r
+\r
+void\r
+ExportSounds()\r
+{ // [HGM] copy the names from the internal WB variables to appData\r
+  ColorClass cc;\r
+  SoundClass sc;\r
+  for (cc = (ColorClass)0; cc < ColorNormal; cc++)\r
+    (&appData.soundShout)[cc] = textAttribs[cc].sound.name;\r
+  for (sc = (SoundClass)0; sc < NSoundClasses; sc++)\r
+    (&appData.soundMove)[sc] = sounds[sc].name;\r
+}\r
+\r
+void\r
+SaveAttribsArg(FILE *f, ArgDescriptor *ad)\r
+{      // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though\r
+       MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];\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
+          (ta->effects & CFE_STRIKEOUT) ? "s" : "",\r
+          (ta->effects) ? " " : "",\r
+         ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);\r
+      }\r
+\r
+void\r
+SaveColor(FILE *f, ArgDescriptor *ad)\r
+{      // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?\r
+       COLORREF color = *(COLORREF *)colorVariable[(int)ad->argLoc];\r
+       fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName, \r
+         color&0xff, (color>>8)&0xff, (color>>16)&0xff);\r
+}\r
+\r
+void\r
+SaveBoardSize(FILE *f, char *name, void *addr)\r
+{ // wrapper to shield back-end from BoardSize & sizeInfo\r
+  fprintf(f, "/%s=%s\n", name, sizeInfo[*(BoardSize *)addr].name);\r
+}\r
+\r
+void\r
+ParseCommPortSettings(char *s)\r
+{ // wrapper to keep dcb from back-end\r
+  ParseCommSettings(s, &dcb);\r
+}\r
+\r
+void\r
+GetWindowCoords()\r
+{ // wrapper to shield use of window handles from back-end (make addressible by number?)\r
+  GetActualPlacement(hwndMain, &wpMain);\r
+  GetActualPlacement(hwndConsole, &wpConsole);\r
+  GetActualPlacement(commentDialog, &wpComment);\r
+  GetActualPlacement(editTagsDialog, &wpTags);\r
+  GetActualPlacement(gameListDialog, &wpGameList);\r
+  GetActualPlacement(moveHistoryDialog, &wpMoveHistory);\r
+  GetActualPlacement(evalGraphDialog, &wpEvalGraph);\r
+  GetActualPlacement(engineOutputDialog, &wpEngineOutput);\r
+}\r
+\r
+void\r
+PrintCommPortSettings(FILE *f, char *name)\r
+{ // wrapper to shield back-end from DCB\r
+      PrintCommSettings(f, name, &dcb);\r
+}\r
+\r
+int\r
+MySearchPath(char *installDir, char *name, char *fullname)\r
+{\r
+  char *dummy, buf[MSG_SIZ], *p = name, *q;\r
+  if(name[0]== '%') {\r
+    fullname[0] = 0; // [HGM] first expand any environment variables in the given name\r
+    while(*p == '%' && (q = strchr(p+1, '%'))) { // [HGM] recognize %*% as environment variable\r
+      safeStrCpy(buf, p+1, sizeof(buf)/sizeof(buf[0]) );\r
+      *strchr(buf, '%') = 0;\r
+      strcat(fullname, getenv(buf));\r
+      p = q+1; while(*p == '\\') { strcat(fullname, "\\"); p++; }\r
     }\r
+    strcat(fullname, p); // after environment variables (if any), take the remainder of the given name\r
+    if(appData.debugMode) fprintf(debugFP, "name = '%s', expanded name = '%s'\n", name, fullname);\r
+    return (int) strlen(fullname);\r
   }\r
-  \r
-  /* Parse default settings file if any */\r
-  if (ParseSettingsFile(settingsFileName, buf)) {\r
-    settingsFileName = strdup(buf);\r
-  }\r
+  return (int) SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);\r
+}\r
 \r
-  /* Parse command line */\r
-  ParseArgs(StringGet, &lpCmdLine);\r
+int\r
+MyGetFullPathName(char *name, char *fullname)\r
+{\r
+  char *dummy;\r
+  return (int) GetFullPathName(name, MSG_SIZ, fullname, &dummy);\r
+}\r
 \r
-  /* Propagate options that affect others */\r
-  if (appData.matchMode || appData.matchGames) chessProgram = TRUE;\r
-  if (appData.icsActive || appData.noChessProgram) {\r
-     chessProgram = FALSE;  /* not local chess program mode */\r
-  }\r
+int\r
+MainWindowUp()\r
+{ // [HGM] args: allows testing if main window is realized from back-end\r
+  return hwndMain != NULL;\r
+}\r
 \r
-  /* Open startup dialog if needed */\r
-  if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||\r
-      (appData.icsActive && *appData.icsHost == NULLCHAR) ||\r
-      (chessProgram && (*appData.firstChessProgram == NULLCHAR ||\r
-                        *appData.secondChessProgram == NULLCHAR))) {\r
+void\r
+PopUpStartupDialog()\r
+{\r
     FARPROC lpProc;\r
     \r
+    LoadLanguageFile(appData.language);\r
     lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);\r
     DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);\r
     FreeProcInstance(lpProc);\r
-  }\r
+}\r
 \r
-  /* Make sure save files land in the right (?) directory */\r
-  if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {\r
-    appData.saveGameFile = strdup(buf);\r
-  }\r
-  if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {\r
-    appData.savePositionFile = strdup(buf);\r
-  }\r
+/*---------------------------------------------------------------------------*\\r
+ *\r
+ * GDI board drawing routines\r
+ *\r
+\*---------------------------------------------------------------------------*/\r
 \r
-  /* Finish initialization for fonts and sounds */\r
-  for (i=0; i<NUM_FONTS; i++) {\r
-    for (j=0; j<NUM_SIZES; j++) {\r
-      CreateFontInMF(font[j][i]);\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
-  }\r
-  /* xboard, and older WinBoards, controlled the move sound with the\r
-     appData.ringBellAfterMoves option.  In the current WinBoard, we\r
-     always turn the option on (so that the backend will call us),\r
-     then let the user turn the sound off by setting it to silence if\r
-     desired.  To accommodate old winboard.ini files saved by old\r
-     versions of WinBoard, we also turn off the sound if the option\r
-     was initially set to false. */\r
-  if (!appData.ringBellAfterMoves) {\r
-    sounds[(int)SoundMove].name = strdup("");\r
-    appData.ringBellAfterMoves = TRUE;\r
-  }\r
-  GetCurrentDirectory(MSG_SIZ, currDir);\r
-  SetCurrentDirectory(installDir);\r
-  LoadAllSounds();\r
-  SetCurrentDirectory(currDir);\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
-  p = icsTextMenuString;\r
-  if (p[0] == '@') {\r
-    FILE* f = fopen(p + 1, "r");\r
-    if (f == NULL) {\r
-      DisplayFatalError(p + 1, errno, 2);\r
-      return;\r
+        SelectObject( hdc, hpen );\r
     }\r
-    i = fread(buf, 1, sizeof(buf)-1, f);\r
-    fclose(f);\r
-    buf[i] = NULLCHAR;\r
-    p = buf;\r
-  }\r
-  ParseIcsTextMenu(strdup(p));\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
-VOID\r
-InitMenuChecks()\r
-{\r
-  HMENU hmenu = GetMenu(hwndMain);\r
+    /* Mask */\r
+    hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );\r
 \r
-  (void) EnableMenuItem(hmenu, IDM_CommPort,\r
-                       MF_BYCOMMAND|((appData.icsActive &&\r
-                                      *appData.icsCommPort != NULLCHAR) ?\r
-                                     MF_ENABLED : MF_GRAYED));\r
-  (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,\r
-                      MF_BYCOMMAND|(saveSettingsOnExit ?\r
-                                    MF_CHECKED : MF_UNCHECKED));\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
-VOID\r
-SaveSettings(char* name)\r
-{\r
-  FILE *f;\r
-  ArgDescriptor *ad;\r
-  WINDOWPLACEMENT wp;\r
-  char dir[MSG_SIZ];\r
+    /* Step 1: background is now black */\r
+    FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );\r
 \r
-  if (!hwndMain) return;\r
+    GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );\r
 \r
-  GetCurrentDirectory(MSG_SIZ, dir);\r
-  SetCurrentDirectory(installDir);\r
-  f = fopen(name, "w");\r
-  SetCurrentDirectory(dir);\r
-  if (f == NULL) {\r
-    DisplayError(name, errno);\r
-    return;\r
-  }\r
-  fprintf(f, ";\n");\r
-  fprintf(f, "; %s %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);\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
-  fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");\r
-  fprintf(f, ";\n");\r
+    pt.x = (squareSize - sz.cx) / 2;\r
+    pt.y = (squareSize - sz.cy) / 2;\r
 \r
-  wp.length = sizeof(WINDOWPLACEMENT);\r
-  GetWindowPlacement(hwndMain, &wp);\r
-  boardX = wp.rcNormalPosition.left;\r
-  boardY = wp.rcNormalPosition.top;\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
-  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
-  }\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
-  if (analysisDialog) {\r
-    GetWindowPlacement(analysisDialog, &wp);\r
-    analysisX = wp.rcNormalPosition.left;\r
-    analysisY = wp.rcNormalPosition.top;\r
-    analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
-    analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\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
-  if (commentDialog) {\r
-    GetWindowPlacement(commentDialog, &wp);\r
-    commentX = wp.rcNormalPosition.left;\r
-    commentY = wp.rcNormalPosition.top;\r
-    commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
-    commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\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
-  if (editTagsDialog) {\r
-    GetWindowPlacement(editTagsDialog, &wp);\r
-    editTagsX = wp.rcNormalPosition.left;\r
-    editTagsY = wp.rcNormalPosition.top;\r
-    editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
-    editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
-  }\r
+        DeleteDC( dc2 );\r
+        DeleteObject( bm2 );\r
+    }\r
 \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
-  }\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
-  for (ad = argDescriptors; ad->argName != NULL; ad++) {\r
-    if (!ad->save) continue;\r
-    switch (ad->argType) {\r
-    case ArgString:\r
-      {\r
-       char *p = *(char **)ad->argLoc;\r
-       if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {\r
-         /* Quote multiline values or \-containing values\r
-            with { } if possible */\r
-         fprintf(f, "/%s={%s}\n", ad->argName, p);\r
-       } else {\r
-         /* Else quote with " " */\r
-         fprintf(f, "/%s=\"", ad->argName);\r
-         while (*p) {\r
-           if (*p == '\n') fprintf(f, "\n");\r
-           else if (*p == '\r') fprintf(f, "\\r");\r
-           else if (*p == '\t') fprintf(f, "\\t");\r
-           else if (*p == '\b') fprintf(f, "\\b");\r
-           else if (*p == '\f') fprintf(f, "\\f");\r
-           else if (*p < ' ') fprintf(f, "\\%03o", *p);\r
-           else if (*p == '\"') fprintf(f, "\\\"");\r
-           else if (*p == '\\') fprintf(f, "\\\\");\r
-           else putc(*p, f);\r
-           p++;\r
-         }\r
-         fprintf(f, "\"\n");\r
-       }\r
-      }\r
-      break;\r
-    case ArgInt:\r
-      fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);\r
-      break;\r
-    case ArgFloat:\r
-      fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);\r
-      break;\r
-    case ArgBoolean:\r
-      fprintf(f, "/%s=%s\n", ad->argName, \r
-       (*(Boolean *)ad->argLoc) ? "true" : "false");\r
-      break;\r
-    case ArgTrue:\r
-      if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);\r
-      break;\r
-    case ArgFalse:\r
-      if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);\r
-      break;\r
-    case ArgColor:\r
-      {\r
-       COLORREF color = *(COLORREF *)ad->argLoc;\r
-       fprintf(f, "/%s=#%02x%02x%02x\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
-          (ta->effects & CFE_BOLD) ? "b" : "",\r
-          (ta->effects & CFE_ITALIC) ? "i" : "",\r
-          (ta->effects & CFE_UNDERLINE) ? "u" : "",\r
-          (ta->effects & CFE_STRIKEOUT) ? "s" : "",\r
-          (ta->effects) ? " " : "",\r
-         ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);\r
-      }\r
-      break;\r
-    case ArgFilename:\r
-      if (strchr(*(char **)ad->argLoc, '\"')) {\r
-       fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);\r
-      } else {\r
-       fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);\r
-      }\r
-      break;\r
-    case ArgBoardSize:\r
-      fprintf(f, "/%s=%s\n", ad->argName,\r
-             sizeInfo[*(BoardSize *)ad->argLoc].name);\r
-      break;\r
-    case ArgFont:\r
-      {\r
-        int bs;\r
-       for (bs=0; bs<NUM_SIZES; bs++) {\r
-         MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;\r
-          fprintf(f, "/size=%s ", sizeInfo[bs].name);\r
-         fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",\r
-           ad->argName, mfp->faceName, mfp->pointSize,\r
-            mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",\r
-           mfp->bold ? "b" : "",\r
-           mfp->italic ? "i" : "",\r
-           mfp->underline ? "u" : "",\r
-           mfp->strikeout ? "s" : "");\r
-       }\r
-      }\r
-      break;\r
-    case ArgCommSettings:\r
-      PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);\r
+    SelectObject( hdc, hbm_old );\r
+\r
+    if( hPieceMask[index] != NULL ) {\r
+        DeleteObject( hPieceMask[index] );\r
     }\r
-  }\r
-  fclose(f);\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
-/*---------------------------------------------------------------------------*\\r
- *\r
- * GDI board drawing routines\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??S??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
-/* [AS] Draw square using background texture */
-static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
-{
-    XFORM   x;
-
-    if( mode == 0 ) {
-        return; /* Should never happen! */
-    }
-
-    SetGraphicsMode( dst, GM_ADVANCED );
-
-    switch( mode ) {
-    case 1:
-        /* Identity */
-        break;
-    case 2:
-        /* X reflection */
-        x.eM11 = -1.0;
-        x.eM12 = 0;
-        x.eM21 = 0;
-        x.eM22 = 1.0;
-        x.eDx = (FLOAT) dw + dx - 1;
-        x.eDy = 0;
-        dx = 0;
-        SetWorldTransform( dst, &x );
-        break;
-    case 3:
-        /* Y reflection */
-        x.eM11 = 1.0;
-        x.eM12 = 0;
-        x.eM21 = 0;
-        x.eM22 = -1.0;
-        x.eDx = 0;
-        x.eDy = (FLOAT) dh + dy - 1;
-        dy = 0;
-        SetWorldTransform( dst, &x );
-        break;
-    case 4:
-        /* X/Y flip */
-        x.eM11 = 0;
-        x.eM12 = 1.0;
-        x.eM21 = 1.0;
-        x.eM22 = 0;
-        x.eDx = (FLOAT) dx;
-        x.eDy = (FLOAT) dy;
-        dx = 0;
-        dy = 0;
-        SetWorldTransform( dst, &x );
-        break;
-    }
-
-    BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
-
-    x.eM11 = 1.0;
-    x.eM12 = 0;
-    x.eM21 = 0;
-    x.eM22 = 1.0;
-    x.eDx = 0;
-    x.eDy = 0;
-    SetWorldTransform( dst, &x );
-
-    ModifyWorldTransform( dst, 0, MWT_IDENTITY );
-}
-
-/* [AS] */
-enum {
-    PM_WP = 0,
-    PM_WN = 1,
-    PM_WB = 2,
-    PM_WR = 3,
-    PM_WQ = 4,
-    PM_WK = 5,
-    PM_BP = 6,
-    PM_BN = 7,
-    PM_BB = 8,
-    PM_BR = 9,
-    PM_BQ = 10,
-    PM_BK = 11
-};
-
-static HFONT hPieceFont = NULL;
-static HBITMAP hPieceMask[12];
-static HBITMAP hPieceFace[12];
-static int fontBitmapSquareSize = 0;
-static char pieceToFontChar[12] = { 'p', 'n', 'b', 'r', 'q', 'k', 'o', 'm', 'v', 't', 'w', 'l' };
-
-static BOOL SetPieceToFontCharTable( const char * map )
-{
-    BOOL result = FALSE;
-
-    if( map != NULL && strlen(map) == 12 ) {
-        int i;
-
-        for( i=0; i<12; i++ ) {
-            pieceToFontChar[i] = map[i];
-        }
-
-        result = TRUE;
-    }
-
-    return result;
-}
-
-static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
-{
-    HBRUSH hbrush;
-    BYTE r1 = GetRValue( color );
-    BYTE g1 = GetGValue( color );
-    BYTE b1 = GetBValue( color );
-    BYTE r2 = r1 / 2;
-    BYTE g2 = g1 / 2;
-    BYTE b2 = b1 / 2;
-    RECT rc;
-
-    /* Create a uniform background first */
-    hbrush = CreateSolidBrush( color );
-    SetRect( &rc, 0, 0, squareSize, squareSize );
-    FillRect( hdc, &rc, hbrush );
-    DeleteObject( hbrush );
-
-    if( mode == 1 ) {
-        /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
-        int steps = squareSize / 2;
-        int i;
-
-        for( i=0; i<steps; i++ ) {
-            BYTE r = r1 - (r1-r2) * i / steps;
-            BYTE g = g1 - (g1-g2) * i / steps;
-            BYTE b = b1 - (b1-b2) * i / steps;
-
-            hbrush = CreateSolidBrush( RGB(r,g,b) );
-            SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
-            FillRect( hdc, &rc, hbrush );
-            DeleteObject(hbrush);
-        }
-    }
-    else if( mode == 2 ) {
-        /* Diagonal gradient, good more or less for every piece */
-        POINT triangle[3];
-        HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
-        HBRUSH hbrush_old;
-        int steps = squareSize;
-        int i;
-
-        triangle[0].x = squareSize - steps;
-        triangle[0].y = squareSize;
-        triangle[1].x = squareSize;
-        triangle[1].y = squareSize;
-        triangle[2].x = squareSize;
-        triangle[2].y = squareSize - steps;
-
-        for( i=0; i<steps; i++ ) {
-            BYTE r = r1 - (r1-r2) * i / steps;
-            BYTE g = g1 - (g1-g2) * i / steps;
-            BYTE b = b1 - (b1-b2) * i / steps;
-
-            hbrush = CreateSolidBrush( RGB(r,g,b) );
-            hbrush_old = SelectObject( hdc, hbrush );
-            Polygon( hdc, triangle, 3 );
-            SelectObject( hdc, hbrush_old );
-            DeleteObject(hbrush);
-            triangle[0].x++;
-            triangle[2].y++;
-        }
-
-        SelectObject( hdc, hpen );
-    }
-}
-
-/*
-    [AS] The method I use to create the bitmaps it a bit tricky, but it
-    seems to work ok. The main problem here is to find the "inside" of a chess
-    piece: follow the steps as explained below.
-*/
-static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
-{
-    HBITMAP hbm;
-    HBITMAP hbm_old;
-    COLORREF chroma = RGB(0xFF,0x00,0xFF);
-    RECT rc;
-    SIZE sz;
-    POINT pt;
-    int backColor = whitePieceColor;
-    int foreColor = blackPieceColor;
-    int shapeIndex = index < 6 ? index+6 : index;
-
-    if( index < 6 && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
-        backColor = appData.fontBackColorWhite;
-        foreColor = appData.fontForeColorWhite;
-    }
-    else if( index >= 6 && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
-        backColor = appData.fontBackColorBlack;
-        foreColor = appData.fontForeColorBlack;
-    }
-
-    /* Mask */
-    hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
-
-    hbm_old = SelectObject( hdc, hbm );
-
-    rc.left = 0;
-    rc.top = 0;
-    rc.right = squareSize;
-    rc.bottom = squareSize;
-
-    /* Step 1: background is now black */
-    FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
-
-    GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
-
-    pt.x = (squareSize - sz.cx) / 2;
-    pt.y = (squareSize - sz.cy) / 2;
-
-    SetBkMode( hdc, TRANSPARENT );
-    SetTextColor( hdc, chroma );
-    /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
-    TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
-
-    SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
-    /* Step 3: the area outside the piece is filled with white */
-    FloodFill( hdc, 0, 0, chroma );
-    SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
-    /*
-        Step 4: this is the tricky part, the area inside the piece is filled with black,
-        but if the start point is not inside the piece we're lost!
-        There should be a better way to do this... if we could create a region or path
-        from the fill operation we would be fine for example.
-    */
-    FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
-
-    SetTextColor( hdc, 0 );
-    /*
-        Step 5: some fonts have "disconnected" areas that are skipped by the fill:
-        draw the piece again in black for safety.
-    */
-    TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
-
-    SelectObject( hdc, hbm_old );
-
-    if( hPieceMask[index] != NULL ) {
-        DeleteObject( hPieceMask[index] );
-    }
-
-    hPieceMask[index] = hbm;
-
-    /* Face */
-    hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
-
-    SelectObject( hdc, hbm );
-
-    {
-        HDC dc1 = CreateCompatibleDC( hdc_window );
-        HDC dc2 = CreateCompatibleDC( hdc_window );
-        HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
-
-        SelectObject( dc1, hPieceMask[index] );
-        SelectObject( dc2, bm2 );
-        FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
-        BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
-
-        /*
-            Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
-            the piece background and deletes (makes transparent) the rest.
-            Thanks to that mask, we are free to paint the background with the greates
-            freedom, as we'll be able to mask off the unwanted parts when finished.
-            We use this, to make gradients and give the pieces a "roundish" look.
-        */
-        SetPieceBackground( hdc, backColor, 2 );
-        BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
-
-        DeleteDC( dc2 );
-        DeleteDC( dc1 );
-        DeleteObject( bm2 );
-    }
-
-    SetTextColor( hdc, foreColor );
-    TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
-
-    SelectObject( hdc, hbm_old );
-
-    hPieceFace[index] = hbm;
-}
-
-static int TranslatePieceToFontPiece( int piece )
-{
-    switch( piece ) {
-    case BlackPawn:
-        return PM_BP;
-    case BlackKnight:
-        return PM_BN;
-    case BlackBishop:
-        return PM_BB;
-    case BlackRook:
-        return PM_BR;
-    case BlackQueen:
-        return PM_BQ;
-    case BlackKing:
-        return PM_BK;
-    case WhitePawn:
-        return PM_WP;
-    case WhiteKnight:
-        return PM_WN;
-    case WhiteBishop:
-        return PM_WB;
-    case WhiteRook:
-        return PM_WR;
-    case WhiteQueen:
-        return PM_WQ;
-    case WhiteKing:
-        return PM_WK;
-    }
-
-    return 0;
-}
-
-void CreatePiecesFromFont()
-{
-    LOGFONT lf;
-    HDC hdc_window = NULL;
-    HDC hdc = NULL;
-    HFONT hfont_old;
-    int fontHeight;
-    int i;
-
-    if( fontBitmapSquareSize < 0 ) {
-        /* Something went seriously wrong in the past: do not try to recreate fonts! */
-        return;
-    }
-
-    if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
-        fontBitmapSquareSize = -1;
-        return;
-    }
-
-    if( fontBitmapSquareSize != squareSize ) {
-        hdc_window = GetDC( hwndMain );
-        hdc = CreateCompatibleDC( hdc_window );
-
-        if( hPieceFont != NULL ) {
-            DeleteObject( hPieceFont );
-        }
-        else {
-            for( i=0; i<12; i++ ) {
-                hPieceMask[i] = NULL;
-            }
-        }
-
-        fontHeight = 75;
-
-        if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
-            fontHeight = appData.fontPieceSize;
-        }
-
-        fontHeight = (fontHeight * squareSize) / 100;
-
-        lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
-        lf.lfWidth = 0;
-        lf.lfEscapement = 0;
-        lf.lfOrientation = 0;
-        lf.lfWeight = FW_NORMAL;
-        lf.lfItalic = 0;
-        lf.lfUnderline = 0;
-        lf.lfStrikeOut = 0;
-        lf.lfCharSet = DEFAULT_CHARSET;
-        lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
-        lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
-        lf.lfQuality = PROOF_QUALITY;
-        lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
-        strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
-        lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
-
-        hPieceFont = CreateFontIndirect( &lf );
-
-        if( hPieceFont == NULL ) {
-            fontBitmapSquareSize = -2;
-        }
-        else {
-            /* Setup font-to-piece character table */
-            if( ! SetPieceToFontCharTable(appData.fontToPieceTable) ) {
-                /* No (or wrong) global settings, try to detect the font */
-                if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
-                    /* Alpha */
-                    SetPieceToFontCharTable("phbrqkojntwl");
-                }
-                else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
-                    /* DiagramTT* family */
-                    SetPieceToFontCharTable("PNLRQKpnlrqk");
-                }
-                else {
-                    /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
-                    SetPieceToFontCharTable("pnbrqkomvtwl");
-                }
-            }
-
-            /* Create bitmaps */
-            hfont_old = SelectObject( hdc, hPieceFont );
-
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
-
-            SelectObject( hdc, hfont_old );
-
-            fontBitmapSquareSize = squareSize;
-        }
-    }
-
-    if( hdc != NULL ) {
-        DeleteDC( hdc );
-    }
-
-    if( hdc_window != NULL ) {
-        ReleaseDC( hwndMain, hdc_window );
-    }
-}
-
 HBITMAP\r
 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)\r
 {\r
   char name[128];\r
 \r
-  sprintf(name, "%s%d%s", piece, squareSize, suffix);\r
+    snprintf(name, sizeof(name)/sizeof(name[0]), "%s%d%s", piece, squareSize, suffix);\r
   if (gameInfo.event &&\r
       strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&\r
       strcmp(name, "k80s") == 0) {\r
-    strcpy(name, "tim");\r
+    safeStrCpy(name, "tim", sizeof(name)/sizeof(name[0]) );\r
   }\r
   return LoadBitmap(hinst, name);\r
 }\r
@@ -2505,7 +2096,7 @@ InsertInPalette(COLORREF color)
   LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);\r
 \r
   if (pLogPal->palNumEntries++ >= PALETTESIZE) {\r
-    DisplayFatalError("Too many colors", 0, 1);\r
+    DisplayFatalError(_("Too many colors"), 0, 1);\r
     pLogPal->palNumEntries--;\r
     return;\r
   }\r
@@ -2546,29 +2137,31 @@ 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
-
-  /* [AS] Force rendering of the font-based pieces */
-  if( fontBitmapSquareSize > 0 ) {
-    fontBitmapSquareSize = 0;
-  }
+  explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic\r
+  markerBrush = CreateSolidBrush(premoveHighlightColor); // [HGM] markers\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
-  int lineGap = sizeInfo[boardSize].lineGap;
-
-  if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
-      lineGap = appData.overrideLineGap;
-  }
-
-  return (BOARD_SIZE + 1) * lineGap +
-         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
@@ -2580,9 +2173,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
@@ -2591,11 +2185,12 @@ ResizeBoard(int newSizeX, int newSizeY, int flags)
 }\r
 \r
 \r
+extern Boolean twoBoards, partnerUp; // [HGM] dual\r
 \r
 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
@@ -2604,21 +2199,33 @@ 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 = wpMain.x; //[HGM] placement: remember previous window params\r
+  oldRect.top = wpMain.y;\r
+  oldRect.right = wpMain.x + wpMain.width;\r
+  oldRect.bottom = wpMain.y + wpMain.height;\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( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
-      lineGap = appData.overrideLineGap;
-  }
-
   if (tinyLayout != oldTinyLayout) {\r
-    long style = GetWindowLong(hwndMain, GWL_STYLE);\r
+    long style = GetWindowLongPtr(hwndMain, GWL_STYLE);\r
     if (tinyLayout) {\r
       style &= ~WS_SYSMENU;\r
       InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,\r
@@ -2627,96 +2234,138 @@ InitDrawingSizes(BoardSize boardSize, int flags)
       style |= WS_SYSMENU;\r
       RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);\r
     }\r
-    SetWindowLong(hwndMain, GWL_STYLE, style);\r
+    SetWindowLongPtr(hwndMain, GWL_STYLE, style);\r
 \r
     for (i=0; menuBarText[tinyLayout][i]; i++) {\r
       ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP, \r
-       (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);\r
+       (UINT)GetSubMenu(hmenu, i), T_(menuBarText[tinyLayout][i]));\r
     }\r
     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
   if (appData.clockMode) {\r
-    sprintf(buf, "White: %s", TimeString(23*60*60*1000L));\r
+    snprintf(buf, MSG_SIZ, _("White: %s"), TimeString(23*60*60*1000L));\r
   } else {\r
-    sprintf(buf, "White");\r
+    snprintf(buf, MSG_SIZ, _("White"));\r
   }\r
   oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);\r
   GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);\r
   SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);\r
-  str = "We only care about the height here";\r
+  str = _("We only care about the height here");\r
   GetTextExtentPoint(hdc, str, strlen(str), &messageSize);\r
   SelectObject(hdc, oldFont);\r
   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
 \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
+    logoHeight = 0; // [HGM] logo: suppress logo after change to tiny layout!\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
+  winW *= 1 + twoBoards;\r
+  if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only\r
+  wpMain.width = winW;  // [HGM] placement: set through temporary which can used by initial sizing choice\r
+  wpMain.height = winH; //       without disturbing window attachments\r
   GetWindowRect(hwndMain, &wrect);\r
-  SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,\r
+  SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,\r
               SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);\r
+\r
+  // [HGM] placement: let attached windows follow size change.\r
+  ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, moveHistoryDialog, &wpMoveHistory );\r
+  ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, evalGraphDialog, &wpEvalGraph );\r
+  ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, engineOutputDialog, &wpEngineOutput );\r
+  ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, gameListDialog, &wpGameList );\r
+  ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, hwndConsole, &wpConsole );\r
+\r
   /* compensate if menu bar wrapped */\r
   GetClientRect(hwndMain, &crect);\r
   offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;\r
-  winHeight += offby;\r
+  wpMain.height += offby;\r
   switch (flags) {\r
   case WMSZ_TOPLEFT:\r
     SetWindowPos(hwndMain, NULL, \r
-                 wrect.right - winWidth, wrect.bottom - winHeight, \r
-                 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);\r
+                 wrect.right - wpMain.width, wrect.bottom - wpMain.height, \r
+                 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);\r
     break;\r
 \r
   case WMSZ_TOPRIGHT:\r
   case WMSZ_TOP:\r
     SetWindowPos(hwndMain, NULL, \r
-                 wrect.left, wrect.bottom - winHeight, \r
-                 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);\r
+                 wrect.left, wrect.bottom - wpMain.height, \r
+                 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);\r
     break;\r
 \r
   case WMSZ_BOTTOMLEFT:\r
   case WMSZ_LEFT:\r
     SetWindowPos(hwndMain, NULL, \r
-                 wrect.right - winWidth, wrect.top, \r
-                 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);\r
+                 wrect.right - wpMain.width, wrect.top, \r
+                 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);\r
     break;\r
 \r
   case WMSZ_BOTTOMRIGHT:\r
   case WMSZ_BOTTOM:\r
   case WMSZ_RIGHT:\r
   default:\r
-    SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,\r
+    SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,\r
                SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);\r
     break;\r
   }\r
@@ -2734,7 +2383,7 @@ InitDrawingSizes(BoardSize boardSize, int flags)
                     boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),\r
                     messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,\r
                     (HMENU) buttonDesc[i].id,\r
-                    (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);\r
+                    (HINSTANCE) GetWindowLongPtr(hwndMain, GWLP_HINSTANCE), NULL);\r
       if (tinyLayout) {\r
        SendMessage(buttonDesc[i].hwnd, WM_SETFONT, \r
                    (WPARAM)font[boardSize][MESSAGE_FONT]->hf,\r
@@ -2743,7 +2392,7 @@ InitDrawingSizes(BoardSize boardSize, int flags)
       if (buttonDesc[i].id == IDM_Pause)\r
        hwndPause = buttonDesc[i].hwnd;\r
       buttonDesc[i].wndproc = (WNDPROC)\r
-       SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);\r
+       SetWindowLongPtr(buttonDesc[i].hwnd, GWLP_WNDPROC, (LONG_PTR) ButtonProc);\r
     }\r
   }\r
   if (gridPen != NULL) DeleteObject(gridPen);\r
@@ -2765,55 +2414,250 @@ 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( gameInfo.variant == VariantShogi && squareSize <= 72 && squareSize >= 33) {\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
+      if(gameInfo.variant == VariantSChess) {\r
+        pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "s");\r
+        pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "o");\r
+        pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "w");\r
+      } else {\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
+    }\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 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {\r
+      pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "s");\r
+      pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "o");\r
+      pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "e", 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
@@ -2838,19 +2682,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[] = "0123456789012345678901221098765432109876543210";\r
+  static char ranks[] = "wvutsrqponmlkjihgfedcbaabcdefghijklmnopqrstuvw";\r
   char str[2] = { NULLCHAR, NULLCHAR };\r
   int oldMode, oldAlign, x, y, start, i;\r
   HFONT oldFont;\r
@@ -2859,7 +2703,7 @@ DrawCoordsOnDC(HDC hdc)
   if (!appData.showCoords)\r
     return;\r
 \r
-  start = flipView ? 0 : 8;\r
+  start = flipView ? 1-(ONE!='1') : 45+(ONE!='1')-BOARD_HEIGHT;\r
 \r
   oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));\r
   oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));\r
@@ -2867,17 +2711,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 ? 23-(BOARD_RGHT-BOARD_LEFT) : 23;\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
@@ -2896,7 +2742,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
@@ -2912,14 +2758,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
@@ -2932,23 +2778,14 @@ DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
 }\r
 \r
 VOID\r
-DrawHighlightsOnDC(HDC hdc)\r
+DrawHighlightsOnDC(HDC hdc, HighlightInfo *h, int pen)\r
 {\r
   int i;\r
   for (i=0; i<2; i++) {\r
-    if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) \r
+    if (h->sq[i].x >= 0 && h->sq[i].y >= 0) \r
       DrawHighlightOnDC(hdc, TRUE,\r
-                       highlightInfo.sq[i].x, highlightInfo.sq[i].y,\r
-                       HIGHLIGHT_PEN);\r
-  }\r
-  for (i=0; i<2; i++) {\r
-    if (premoveHighlightInfo.sq[i].x >= 0 && \r
-       premoveHighlightInfo.sq[i].y >= 0) {\r
-       DrawHighlightOnDC(hdc, TRUE,\r
-                         premoveHighlightInfo.sq[i].x, \r
-                         premoveHighlightInfo.sq[i].y,\r
-                         PREMOVE_PEN);\r
-    }\r
+                       h->sq[i].x, h->sq[i].y,\r
+                       pen);\r
   }\r
 }\r
 \r
@@ -2960,184 +2797,523 @@ 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 */
-  if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
-    /* Create piece bitmaps, or do nothing if piece set is up to data */
-    CreatePiecesFromFont();
-
-    if( fontBitmapSquareSize == squareSize ) {
-        int index = TranslatePieceToFontPiece( piece );
-
-        SelectObject( tmphdc, hPieceMask[ index ] );
-
-        BitBlt( hdc,
-            x, y,
-            squareSize, squareSize,
-            tmphdc,
-            0, 0,
-            SRCAND );
-
-        SelectObject( tmphdc, hPieceFace[ index ] );
-
-        BitBlt( hdc,
-            x, y,
-            squareSize, squareSize,
-            tmphdc,
-            0, 0,
-            SRCPAINT );
-
-        return;
-    }
-  }
-
+  /* [AS] Use font-based pieces if needed */\r
+  if( fontBitmapSquareSize >= 0 && (squareSize > 32 || gameInfo.variant >= VariantShogi)) {\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
+      if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))\r
+        StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCAND);\r
+      else\r
+        BitBlt( hdc,\r
+            x, y,\r
+            squareSize, squareSize,\r
+            tmphdc,\r
+            0, 0,\r
+            SRCAND );\r
+\r
+        SelectObject( tmphdc, hPieceFace[ index ] );\r
+\r
+      if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))\r
+        StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCPAINT);\r
+      else\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) */
-int GetBackTextureMode( int algo )
-{
-    int result = BACK_TEXTURE_MODE_DISABLED;
-
-    switch( algo )
-    {
-        case BACK_TEXTURE_MODE_PLAIN:
-            result = 1; /* Always use identity map */
-            break;
-        case BACK_TEXTURE_MODE_FULL_RANDOM:
-            result = 1 + (myrandom() % 3); /* Pick a transformation at random */
-            break;
-    }
-
-    return result;
-}
-
-/*
-    [AS] Compute and save texture drawing info, otherwise we may not be able
-    to handle redraws cleanly (as random numbers would always be different).
-*/
-VOID RebuildTextureSquareInfo()
-{
-    BITMAP bi;
-    int lite_w = 0;
-    int lite_h = 0;
-    int dark_w = 0;
-    int dark_h = 0;
-    int row;
-    int col;
-
-    ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
-
-    if( liteBackTexture != NULL ) {
-        if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
-            lite_w = bi.bmWidth;
-            lite_h = bi.bmHeight;
-        }
-    }
-
-    if( darkBackTexture != NULL ) {
-        if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
-            dark_w = bi.bmWidth;
-            dark_h = bi.bmHeight;
-        }
-    }
-
-    for( row=0; row<BOARD_SIZE; row++ ) {
-        for( col=0; col<BOARD_SIZE; col++ ) {
-            if( (col + row) & 1 ) {
-                /* Lite square */
-                if( lite_w >= squareSize && lite_h >= squareSize ) {
-                    backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / BOARD_SIZE;
-                    backTextureSquareInfo[row][col].y = row * (lite_h - squareSize) / BOARD_SIZE;
-                    backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
-                }
-            }
-            else {
-                /* Dark square */
-                if( dark_w >= squareSize && dark_h >= squareSize ) {
-                    backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / BOARD_SIZE;
-                    backTextureSquareInfo[row][col].y = row * (dark_h - squareSize) / BOARD_SIZE;
-                    backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
-                }
-            }
-        }
-    }
-}
-
+/* [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
+                  if( lite_w >= squareSize*BOARD_WIDTH )\r
+                    backTextureSquareInfo[row][col].x = (2*col+1)*lite_w/(2*BOARD_WIDTH) - squareSize/2;  /* [HGM] cut out of center of virtual square */\r
+                  else\r
+                    backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1);  /* [HGM] divide by size-1 in stead of size! */\r
+                  if( lite_h >= squareSize*BOARD_HEIGHT )\r
+                    backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1)*lite_h/(2*BOARD_HEIGHT) - squareSize/2;\r
+                  else\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
+                  if( dark_w >= squareSize*BOARD_WIDTH )\r
+                    backTextureSquareInfo[row][col].x = (2*col+1) * dark_w / (2*BOARD_WIDTH) - squareSize/2;\r
+                  else\r
+                    backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);\r
+                  if( dark_h >= squareSize*BOARD_HEIGHT )\r
+                    backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1) * dark_h / (2*BOARD_HEIGHT) - squareSize/2;\r
+                  else\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 double 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 + 0.5;\r
+        arrow[0].y = s_y;\r
+\r
+        arrow[1].x = s_x + A_WIDTH + 0.5;\r
+        arrow[1].y = d_y - h;\r
+\r
+        arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;\r
+        arrow[2].y = d_y - h;\r
+\r
+        arrow[3].x = d_x;\r
+        arrow[3].y = d_y;\r
+\r
+        arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;\r
+        arrow[5].y = d_y - h;\r
+\r
+        arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;\r
+        arrow[4].y = d_y - h;\r
+\r
+        arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;\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 + 0.5;\r
+\r
+        arrow[1].x = d_x - w;\r
+        arrow[1].y = s_y + A_WIDTH + 0.5;\r
+\r
+        arrow[2].x = d_x - w;\r
+        arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;\r
+\r
+        arrow[3].x = d_x;\r
+        arrow[3].y = d_y;\r
+\r
+        arrow[5].x = d_x - w;\r
+        arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;\r
+\r
+        arrow[4].x = d_x - w;\r
+        arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;\r
+\r
+        arrow[6].x = s_x;\r
+        arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;\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(arrow[0].x + 2*j);   // [HGM] prevent width to be affected by rounding twice\r
+        arrow[1].y = Round(arrow[0].y - 2*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
+        x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends\r
+\r
+        arrow[6].x = Round(x - j);\r
+        arrow[6].y = Round(y + j*dx);\r
+\r
+        arrow[2].x = Round(arrow[6].x + 2*j);\r
+        arrow[2].y = Round(arrow[6].y - 2*j*dx);\r
+\r
+        arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));\r
+        arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);\r
+\r
+        arrow[4].x = d_x;\r
+        arrow[4].y = d_y;\r
+\r
+        arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));\r
+        arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*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 / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!\r
+    }\r
+    else if( d_y < s_y ) {\r
+        d_y += squareSize / 2 + squareSize / 4;\r
+    }\r
+    else {\r
+        d_y += squareSize / 2;\r
+    }\r
+\r
+    if( d_x > s_x ) {\r
+        d_x += squareSize / 2 - squareSize / 4;\r
+    }\r
+    else if( d_x < s_x ) {\r
+        d_x += squareSize / 2 + 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.; //[HGM] make float\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;
-
-  /* [AS] Initialize background textures if needed */
-  if( liteBackTexture != NULL || darkBackTexture != NULL ) {
-      if( backTextureSquareSize != squareSize ) {
-          backTextureSquareSize = squareSize;
-          RebuildTextureSquareInfo();
-      }
-
-      texture_hdc = CreateCompatibleDC( hdc );
-  }
-\r
-  for (row = 0; row < BOARD_SIZE; row++) {\r
-    for (column = 0; column < BOARD_SIZE; column++) {\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_FILES*BOARD_HEIGHT) {\r
+         backTextureBoardSize = BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT;\r
+          backTextureSquareSize = squareSize;\r
+          RebuildTextureSquareInfo();\r
+      }\r
+\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
@@ -3145,28 +3321,31 @@ DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
         } else {\r
           DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);\r
         }\r
-      }
-      else if( backTextureSquareInfo[row][column].mode > 0 ) {
-          /* [AS] Draw the square using a texture bitmap */
-          HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
-
-          DrawTile( x, y,
-              squareSize, squareSize,
-              hdc,
-              texture_hdc,
-              backTextureSquareInfo[row][column].mode,
-              backTextureSquareInfo[row][column].x,
-              backTextureSquareInfo[row][column].y );
-
-          SelectObject( texture_hdc, hbm );
-
-          if (piece != EmptySquare) {
-              DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
-          }
-      }
-      else {
-        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
@@ -3174,21 +3353,166 @@ DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
       }\r
     }\r
   }\r
-
-  if( texture_hdc != NULL ) {
-    DeleteDC( texture_hdc );
-  }
+\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) {\r
+    if(!logoHeight) return;\r
+    FillRect( hdc, &logoRect, whitePieceBrush );\r
+  }\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
+DisplayLogos()\r
+{\r
+  if(logoHeight) {\r
+       HDC hdc = GetDC(hwndMain);\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
+       ReleaseDC(hwndMain, hdc);\r
+  }\r
+}\r
+\r
+void\r
+UpdateLogos(int display)\r
+{ // called after loading new engine(s), in tourney or from menu\r
+  LoadLogo(&first, 0, FALSE);\r
+  LoadLogo(&second, 1, appData.icsActive);\r
+  InitDrawingSizes(-2, 0); // adapt layout of board window to presence/absence of logos\r
+  if(display) DisplayLogos();\r
+}\r
+\r
+static HDC hdcSeek;\r
+\r
+// [HGM] seekgraph\r
+void DrawSeekAxis( int x, int y, int xTo, int yTo )\r
+{\r
+    POINT stPt;\r
+    HPEN hp = SelectObject( hdcSeek, gridPen );\r
+    MoveToEx( hdcSeek, boardRect.left+x, boardRect.top+y, &stPt );\r
+    LineTo( hdcSeek, boardRect.left+xTo, boardRect.top+yTo );\r
+    SelectObject( hdcSeek, hp );\r
+}\r
+\r
+// front-end wrapper for drawing functions to do rectangles\r
+void DrawSeekBackground( int left, int top, int right, int bottom )\r
+{\r
+    HPEN hp;\r
+    RECT rc;\r
+\r
+    if (hdcSeek == NULL) {\r
+    hdcSeek = GetDC(hwndMain);\r
+      if (!appData.monoMode) {\r
+        SelectPalette(hdcSeek, hPal, FALSE);\r
+        RealizePalette(hdcSeek);\r
+      }\r
+    }\r
+    hp = SelectObject( hdcSeek, gridPen );\r
+    rc.top = boardRect.top+top; rc.left = boardRect.left+left; \r
+    rc.bottom = boardRect.top+bottom; rc.right = boardRect.left+right;\r
+    FillRect( hdcSeek, &rc, lightSquareBrush );\r
+    SelectObject( hdcSeek, hp );\r
+}\r
+\r
+// front-end wrapper for putting text in graph\r
+void DrawSeekText(char *buf, int x, int y)\r
+{\r
+        SIZE stSize;\r
+       SetBkMode( hdcSeek, TRANSPARENT );\r
+        GetTextExtentPoint32( hdcSeek, buf, strlen(buf), &stSize );\r
+        TextOut( hdcSeek, boardRect.left+x-3, boardRect.top+y-stSize.cy/2, buf, strlen(buf) );\r
+}\r
+\r
+void DrawSeekDot(int x, int y, int color)\r
+{\r
+       int square = color & 0x80;\r
+       HBRUSH oldBrush = SelectObject(hdcSeek, \r
+                       color == 0 ? markerBrush : color == 1 ? darkSquareBrush : explodeBrush);\r
+       color &= 0x7F;\r
+       if(square)\r
+           Rectangle(hdcSeek, boardRect.left+x - squareSize/9, boardRect.top+y - squareSize/9,\r
+                              boardRect.left+x + squareSize/9, boardRect.top+y + squareSize/9);\r
+       else\r
+           Ellipse(hdcSeek, boardRect.left+x - squareSize/8, boardRect.top+y - squareSize/8,\r
+                            boardRect.left+x + squareSize/8, boardRect.top+y + squareSize/8);\r
+           SelectObject(hdcSeek, oldBrush);\r
+}\r
+\r
+VOID\r
 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)\r
 {\r
-  static Board lastReq, lastDrawn;\r
+  static Board lastReq[2], lastDrawn[2];\r
   static HighlightInfo lastDrawnHighlight, lastDrawnPremove;\r
   static int lastDrawnFlipView = 0;\r
-  static int lastReqValid = 0, lastDrawnValid = 0;\r
+  static int lastReqValid[2] = {0, 0}, lastDrawnValid[2] = {0, 0};\r
   int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;\r
   HDC tmphdc;\r
   HDC hdcmem;\r
@@ -3197,6 +3521,7 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
   RECT Rect;\r
   HRGN clips[MAX_CLIPS];\r
   ChessSquare dragged_piece = EmptySquare;\r
+  int nr = twoBoards*partnerUp;\r
 \r
   /* I'm undecided on this - this function figures out whether a full\r
    * repaint is necessary on its own, so there's no real reason to have the\r
@@ -3208,14 +3533,20 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
    */\r
   Boolean fullrepaint = repaint;\r
 \r
+  if(DrawSeekGraph()) return; // [HG} seekgraph: suppress printing board if seek graph up\r
+\r
+  if( DrawPositionNeedsFullRepaint() ) {\r
+      fullrepaint = TRUE;\r
+  }\r
+\r
   if (board == NULL) {\r
-    if (!lastReqValid) {\r
+    if (!lastReqValid[nr]) {\r
       return;\r
     }\r
-    board = lastReq;\r
+    board = lastReq[nr];\r
   } else {\r
-    CopyBoard(lastReq, board);\r
-    lastReqValid = 1;\r
+    CopyBoard(lastReq[nr], board);\r
+    lastReqValid[nr] = 1;\r
   }\r
 \r
   if (doingSizing) {\r
@@ -3237,53 +3568,41 @@ 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] = gatingPiece;\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
-       if (lastDrawn[row][column] != board[row][column]) {\r
+  if (!fullrepaint && lastDrawnValid[nr] && (nr == 1 || lastDrawnFlipView == flipView)) {\r
+    for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */\r
+      for (column = 0; column < BOARD_WIDTH; column++) {\r
+       if (lastDrawn[nr][row][column] != board[row][column]) {\r
          SquareToPos(row, column, &x, &y);\r
          clips[num_clips++] =\r
            CreateRectRgn(x, y, x + squareSize, y + squareSize);\r
        }\r
       }\r
     }\r
+   if(nr == 0) { // [HGM] dual: no highlights on second board\r
     for (i=0; i<2; i++) {\r
       if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||\r
          lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {\r
@@ -3324,6 +3643,30 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
        }\r
       }\r
     }\r
+   } else { // nr == 1\r
+       partnerHighlightInfo.sq[0].y = board[EP_STATUS-4];\r
+       partnerHighlightInfo.sq[0].x = board[EP_STATUS-3];\r
+       partnerHighlightInfo.sq[1].y = board[EP_STATUS-2];\r
+       partnerHighlightInfo.sq[1].x = board[EP_STATUS-1];\r
+      for (i=0; i<2; i++) {\r
+       if (partnerHighlightInfo.sq[i].x >= 0 &&\r
+           partnerHighlightInfo.sq[i].y >= 0) {\r
+         SquareToPos(partnerHighlightInfo.sq[i].y,\r
+                     partnerHighlightInfo.sq[i].x, &x, &y);\r
+         clips[num_clips++] =\r
+           CreateRectRgn(x - lineGap, y - lineGap, \r
+                         x + squareSize + lineGap, y + squareSize + lineGap);\r
+       }\r
+       if (oldPartnerHighlight.sq[i].x >= 0 && \r
+           oldPartnerHighlight.sq[i].y >= 0) {\r
+         SquareToPos(oldPartnerHighlight.sq[i].y, \r
+                     oldPartnerHighlight.sq[i].x, &x, &y);\r
+         clips[num_clips++] =\r
+           CreateRectRgn(x - lineGap, y - lineGap, \r
+                         x + squareSize + lineGap, y + squareSize + lineGap);\r
+       }\r
+      }\r
+   }\r
   } else {\r
     fullrepaint = TRUE;\r
   }\r
@@ -3363,12 +3706,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
@@ -3388,8 +3725,8 @@ 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
-      lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;\r
+        we have to remember to erase it. [HGM] moved until after setting lastDrawn */\r
+      lastDrawn[0][animInfo.to.y][animInfo.to.x] = animInfo.piece;\r
     }\r
   }\r
 \r
@@ -3407,18 +3744,73 @@ 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
+        ChessSquare piece = board[explodeInfo.fromY][explodeInfo.fromX];\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, &highlightInfo, HIGHLIGHT_PEN);\r
+       DrawHighlightsOnDC(hdcmem, &premoveHighlightInfo, PREMOVE_PEN);\r
+       DrawBoardOnDC(hdcmem, board, tmphdc);\r
+        board[explodeInfo.fromY][explodeInfo.fromX] = piece;\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
+    if(nr == 0) { // [HGM] dual: decide which highlights to draw\r
+       DrawHighlightsOnDC(hdcmem, &highlightInfo, HIGHLIGHT_PEN);\r
+       DrawHighlightsOnDC(hdcmem, &premoveHighlightInfo, PREMOVE_PEN);\r
+    } else {\r
+       DrawHighlightsOnDC(hdcmem, &partnerHighlightInfo, HIGHLIGHT_PEN);\r
+       oldPartnerHighlight = partnerHighlightInfo;\r
+    }\r
+    DrawBoardOnDC(hdcmem, board, tmphdc);\r
+  }\r
+  if(nr == 0) // [HGM] dual: markers only on left board\r
+  for (row = 0; row < BOARD_HEIGHT; row++) {\r
+    for (column = 0; column < BOARD_WIDTH; column++) {\r
+       if (marker[row][column]) { // marker changes only occur with full repaint!\r
+           HBRUSH oldBrush = SelectObject(hdcmem, \r
+                       marker[row][column] == 2 ? markerBrush : explodeBrush);\r
+           SquareToPos(row, column, &x, &y);\r
+           Ellipse(hdcmem, x + squareSize/4, y + squareSize/4,\r
+                         x + 3*squareSize/4, y + 3*squareSize/4);\r
+           SelectObject(hdcmem, oldBrush);\r
+       }\r
+    }\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[nr], 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
-    DrawPieceOnDC(hdcmem, dragged_piece,\r
-                 ((int) dragged_piece < (int) BlackPawn), \r
+    DrawPieceOnDC(hdcmem, dragInfo.piece,\r
+                 ((int) dragInfo.piece < (int) BlackPawn), \r
                   (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);\r
   }   \r
   \r
@@ -3440,6 +3832,13 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
 \r
   /* Set clipping on the target DC */\r
   if (!fullrepaint) {\r
+    if(nr == 1) for (x = 0; x < num_clips; x++) { // [HGM] dual: translate clips\r
+       RECT rect;\r
+       GetRgnBox(clips[x], &rect);\r
+       DeleteObject(clips[x]);\r
+       clips[x] = CreateRectRgn(rect.left + wpMain.width/2, rect.top, \r
+                         rect.right + wpMain.width/2, rect.bottom);\r
+    }\r
     SelectClipRgn(hdc, clips[0]);\r
     for (x = 1; x < num_clips; x++) {\r
       if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)\r
@@ -3451,10 +3850,83 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
    * This way we avoid any flickering\r
    */\r
   oldBitmap = SelectObject(tmphdc, bufferBitmap);\r
-  BitBlt(hdc, boardRect.left, boardRect.top,\r
+  BitBlt(hdc, boardRect.left + twoBoards*partnerUp*wpMain.width/2, boardRect.top, // [HGM] dual\r
         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; \r
+    BITMAPINFOHEADER bih; int color[16], nrColors=0;\r
+\r
+    GetObject(bufferBitmap, sizeof(b), &b);\r
+    if(pData = malloc(b.bmWidthBytes*b.bmHeight + 10000)) {\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
+       free(pData);\r
+     }\r
+  }\r
+\r
   SelectObject(tmphdc, oldBitmap);\r
 \r
   /* Massive cleanup */\r
@@ -3467,18 +3939,31 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
   if (releaseDC) \r
     ReleaseDC(hwndMain, hdc);\r
   \r
-  if (lastDrawnFlipView != flipView) {\r
+  if (lastDrawnFlipView != flipView && nr == 0) {\r
     if (flipView)\r
       CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);\r
     else\r
       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
+  lastDrawnValid[nr] = 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
+    saveDiagFlag = 0;\r
+\r
+    fclose(f);\r
+    return TRUE;\r
 }\r
 \r
 \r
@@ -3494,7 +3979,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
@@ -3503,6 +3988,11 @@ PaintProc(HWND hwnd)
        RealizePalette(hdc);\r
       }\r
       HDCDrawPosition(hdc, 1, NULL);\r
+      if(twoBoards) { // [HGM] dual: also redraw other board in other orientation\r
+       flipView = !flipView; partnerUp = !partnerUp;\r
+       HDCDrawPosition(hdc, 1, NULL);\r
+       flipView = !flipView; partnerUp = !partnerUp;\r
+      }\r
       oldFont =\r
        SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);\r
       ExtTextOut(hdc, messageRect.left, messageRect.top,\r
@@ -3510,6 +4000,7 @@ PaintProc(HWND hwnd)
                 &messageRect, messageText, strlen(messageText), NULL);\r
       SelectObject(hdc, oldFont);\r
       DisplayBothClocks();\r
+      DisplayLogos();\r
     }\r
     EndPaint(hwnd,&ps);\r
   }\r
@@ -3524,8 +4015,8 @@ PaintProc(HWND hwnd)
  * The offset boardRect.left or boardRect.top must already have been\r
  *   subtracted from x.\r
  */\r
-int\r
-EventToSquare(int x)\r
+int EventToSquare(x, limit)\r
+     int x, limit;\r
 {\r
   if (x <= 0)\r
     return -2;\r
@@ -3535,7 +4026,7 @@ EventToSquare(int x)
   if ((x % (squareSize + lineGap)) >= squareSize)\r
     return -1;\r
   x /= (squareSize + lineGap);\r
-  if (x >= BOARD_SIZE)\r
+    if (x >= limit)\r
     return -2;\r
   return x;\r
 }\r
@@ -3547,11 +4038,11 @@ typedef struct {
 } DropEnable;\r
 \r
 DropEnable dropEnables[] = {\r
-  { 'P', DP_Pawn, "Pawn" },\r
-  { 'N', DP_Knight, "Knight" },\r
-  { 'B', DP_Bishop, "Bishop" },\r
-  { 'R', DP_Rook, "Rook" },\r
-  { 'Q', DP_Queen, "Queen" },\r
+  { 'P', DP_Pawn, N_("Pawn") },\r
+  { 'N', DP_Knight, N_("Knight") },\r
+  { 'B', DP_Bishop, N_("Bishop") },\r
+  { 'R', DP_Rook, N_("Rook") },\r
+  { 'Q', DP_Queen, N_("Queen") },\r
 };\r
 \r
 VOID\r
@@ -3567,7 +4058,7 @@ SetupDropMenu(HMENU hmenu)
               dropEnables[i].piece);\r
     count = 0;\r
     while (p && *p++ == dropEnables[i].piece) count++;\r
-    sprintf(item, "%s  %d", dropEnables[i].name, count);\r
+      snprintf(item, MSG_SIZ, "%s  %d", T_(dropEnables[i].name), count);\r
     enable = count > 0 || !appData.testLegality\r
       /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse\r
                      && !appData.icsActive);\r
@@ -3577,18 +4068,40 @@ SetupDropMenu(HMENU hmenu)
   }\r
 }\r
 \r
-static int fromX = -1, fromY = -1, toX, toY;\r
+void DragPieceBegin(int x, int y, Boolean instantly)\r
+{\r
+      dragInfo.lastpos.x = boardRect.left + x;\r
+      dragInfo.lastpos.y = boardRect.top + y;\r
+      if(instantly) dragInfo.pos = dragInfo.lastpos;\r
+      dragInfo.from.x = fromX;\r
+      dragInfo.from.y = fromY;\r
+      dragInfo.piece = boards[currentMove][fromY][fromX];\r
+      dragInfo.start = dragInfo.from;\r
+      SetCapture(hwndMain);\r
+}\r
+\r
+void DragPieceEnd(int x, int y)\r
+{\r
+    ReleaseCapture();\r
+    dragInfo.start.x = dragInfo.start.y = -1;\r
+    dragInfo.from = dragInfo.start;\r
+    dragInfo.pos = dragInfo.lastpos = dragInfo.start;\r
+}\r
+\r
+void ChangeDragPiece(ChessSquare piece)\r
+{\r
+    dragInfo.piece = piece;\r
+}\r
 \r
 /* Event handler for mouse messages */\r
 VOID\r
 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)\r
 {\r
-  int x, y;\r
+  int x, y, menuNr;\r
   POINT pt;\r
   static int recursive = 0;\r
   HMENU hmenu;\r
-  BOOLEAN saveAnimate;\r
-  static BOOLEAN sameAgain = FALSE;\r
+  BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */\r
 \r
   if (recursive) {\r
     if (message == WM_MBUTTONUP) {\r
@@ -3604,178 +4117,87 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
   \r
   pt.x = LOWORD(lParam);\r
   pt.y = HIWORD(lParam);\r
-  x = EventToSquare(pt.x - boardRect.left);\r
-  y = EventToSquare(pt.y - boardRect.top);\r
+  x = EventToSquare(pt.x - boardRect.left, BOARD_WIDTH);\r
+  y = EventToSquare(pt.y - boardRect.top, BOARD_HEIGHT);\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
+  shiftKey = GetKeyState(VK_SHIFT) < 0; // [HGM] remember last shift status\r
+\r
   switch (message) {\r
   case WM_LBUTTONDOWN:\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
-         SetWhiteToPlayEvent();\r
-       } else if (gameMode == IcsPlayingBlack ||\r
-                  gameMode == MachinePlaysWhite) {\r
-         CallFlagEvent();\r
-       }\r
+        ClockClick(flipClock);\r
       } else if (PtInRect((LPRECT) &blackRect, pt)) {\r
-       if (gameMode == EditPosition) {\r
-         SetBlackToPlayEvent();\r
-       } else if (gameMode == IcsPlayingWhite ||\r
-                  gameMode == MachinePlaysBlack) {\r
-         CallFlagEvent();\r
-       }\r
+       ClockClick(!flipClock);\r
       }\r
-      if (!appData.highlightLastMove) {\r
-        ClearHighlights();\r
-       DrawPosition(FALSE, NULL);\r
-      }\r
-      fromX = fromY = -1;\r
       dragInfo.start.x = dragInfo.start.y = -1;\r
       dragInfo.from = dragInfo.start;\r
+    if(fromX == -1 && frozen) { // not sure where this is for\r
+               fromX = fromY = -1; \r
+      DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */\r
       break;\r
-    } else if (x < 0 || y < 0) {\r
-      break;\r
-    } else if (fromX == x && fromY == y) {\r
-      /* Downclick on same square again */\r
-      ClearHighlights();\r
-      DrawPosition(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
-       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
-    }\r
-    /* First downclick, or restart on a square with same color piece */\r
-    if (!frozen && OKToStartUserMove(x, y)) {\r
-      fromX = x;\r
-      fromY = y;\r
-      dragInfo.lastpos = pt;\r
-      dragInfo.from.x = fromX;\r
-      dragInfo.from.y = fromY;\r
-      dragInfo.start = dragInfo.from;\r
-      SetCapture(hwndMain);\r
-    } else {\r
-      fromX = fromY = -1;\r
-      dragInfo.start.x = dragInfo.start.y = -1;\r
-      dragInfo.from = dragInfo.start;\r
     }\r
+      LeftClick(Press, pt.x - boardRect.left, pt.y - boardRect.top);\r
+      DrawPosition(TRUE, NULL);\r
     break;\r
 \r
   case WM_LBUTTONUP:\r
-    ReleaseCapture();\r
-    if (fromX == -1) break;\r
-    if (x == fromX && y == fromY) {\r
-      dragInfo.from.x = dragInfo.from.y = -1;\r
-      /* Upclick on same square */\r
-      if (sameAgain) {\r
-       /* Clicked same square twice: abort click-click move */\r
-       fromX = fromY = -1;\r
-       gotPremove = 0;\r
-       ClearPremoveHighlights();\r
-      } else {\r
-       /* First square clicked: start click-click move */\r
-       SetHighlights(fromX, fromY, -1, -1);\r
-      }\r
-      DrawPosition(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
-      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
-      }\r
-      if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);\r
-      appData.animate = saveAnimate;\r
-      fromX = fromY = -1;\r
-      if (appData.highlightDragging && !appData.highlightLastMove) {\r
-       ClearHighlights();\r
-      }\r
-      if (appData.animate || appData.animateDragging ||\r
-         appData.highlightDragging || gotPremove) {\r
-       DrawPosition(FALSE, NULL);\r
-      }\r
-    }\r
-    dragInfo.start.x = dragInfo.start.y = -1; \r
-    dragInfo.pos = dragInfo.lastpos = dragInfo.start;\r
+      LeftClick(Release, pt.x - boardRect.left, pt.y - boardRect.top);\r
+      DrawPosition(TRUE, NULL);\r
     break;\r
 \r
   case WM_MOUSEMOVE:\r
+    if(SeekGraphClick(Press, pt.x - boardRect.left, pt.y - boardRect.top, 1)) break;\r
+    if(PromoScroll(pt.x - boardRect.left, pt.y - boardRect.top)) break;\r
+    MovePV(pt.x - boardRect.left, pt.y - boardRect.top, boardRect.bottom - boardRect.top);\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
       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
 \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_MBUTTONUP:\r
+  case WM_RBUTTONUP:\r
+    ReleaseCapture();\r
+    RightClick(Release, pt.x - boardRect.left, pt.y - boardRect.top, &fromX, &fromY);\r
+    break;\r
\r
   case WM_MBUTTONDOWN:\r
   case WM_RBUTTONDOWN:\r
     ErrorPopDown();\r
@@ -3788,14 +4210,20 @@ 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 || GetKeyState(VK_SHIFT) < 0) AdjustClock(flipClock, 1);\r
+      } else if (PtInRect((LPRECT) &blackRect, pt)) {\r
+          if (gameMode == EditGame || GetKeyState(VK_SHIFT) < 0) AdjustClock(!flipClock, 1);\r
+      }\r
+      break;\r
+    }\r
     DrawPosition(TRUE, NULL);\r
 \r
-    switch (gameMode) {\r
-    case EditPosition:\r
-    case IcsExamining:\r
-      if (x < 0 || y < 0) break;\r
-      fromX = x;\r
-      fromY = y;\r
+    menuNr = RightClick(Press, pt.x - boardRect.left, pt.y - boardRect.top, &fromX, &fromY);\r
+    switch (menuNr) {\r
+    case 0:\r
       if (message == WM_MBUTTONDOWN) {\r
        buttonCount = 3;  /* even if system didn't think so */\r
        if (wParam & MK_SHIFT) \r
@@ -3803,38 +4231,22 @@ 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
-    case IcsPlayingBlack:\r
-    case EditGame:\r
-    case MachinePlaysWhite:\r
-    case MachinePlaysBlack:\r
-      if (appData.testLegality &&\r
-         gameInfo.variant != VariantBughouse &&\r
-         gameInfo.variant != VariantCrazyhouse) break;\r
-      if (x < 0 || y < 0) break;\r
-      fromX = x;\r
-      fromY = y;\r
+    case 2:\r
+      SetCapture(hwndMain);
+      break;\r
+    case 1:\r
       hmenu = LoadMenu(hInst, "DropPieceMenu");\r
       SetupDropMenu(hmenu);\r
       MenuPopup(hwnd, pt, hmenu, -1);\r
-      break;\r
     default:\r
       break;\r
     }\r
@@ -3848,7 +4260,7 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 LRESULT CALLBACK\r
 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)\r
 {\r
-  int id = GetWindowLong(hwnd, GWL_ID);\r
+  int id = GetWindowLongPtr(hwnd, GWLP_ID);\r
   int i, dir;\r
 \r
   for (i=0; i<N_BUTTONS; i++) {\r
@@ -3870,31 +4282,16 @@ 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
        SendMessage(h, WM_CHAR, wParam, lParam);\r
        return TRUE;\r
       } else if (isalpha((char)wParam) || isdigit((char)wParam)){\r
-       PopUpMoveDialog((char)wParam);\r
+       TypeInEvent((char)wParam);\r
       }\r
       break;\r
     }\r
@@ -3913,9 +4310,39 @@ Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
   case WM_INITDIALOG: /* message: initialize dialog box */\r
     /* Center the dialog over the application window */\r
     CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));\r
+    Translate(hDlg, DLG_PromotionKing);\r
     ShowWindow(GetDlgItem(hDlg, PB_King), \r
       (!appData.testLegality || gameInfo.variant == VariantSuicide ||\r
-       gameInfo.variant == VariantGiveaway) ?\r
+       gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||\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' && WhiteOnMove(currentMove) &&\r
+         PieceToChar(WhiteAngel) != '~') ||\r
+        (PieceToChar(BlackAngel) >= 'A' && !WhiteOnMove(currentMove) &&\r
+         PieceToChar(BlackAngel) != '~')   ) ?\r
+              SW_SHOW : SW_HIDE);\r
+    ShowWindow(GetDlgItem(hDlg, PB_Chancellor), \r
+       ((PieceToChar(WhiteMarshall) >= 'A' && WhiteOnMove(currentMove) &&\r
+         PieceToChar(WhiteMarshall) != '~') ||\r
+        (PieceToChar(BlackMarshall) >= 'A' && !WhiteOnMove(currentMove) &&\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
+    if(gameInfo.variant == VariantShogi) {\r
+        SetDlgItemText(hDlg, PB_Queen, "YES");\r
+        SetDlgItemText(hDlg, PB_Knight, "NO");\r
+        SetWindowText(hDlg, "Promote?");\r
+    }\r
+    ShowWindow(GetDlgItem(hDlg, IDC_Centaur), \r
+       gameInfo.variant == VariantSuper ?\r
               SW_SHOW : SW_HIDE);\r
     return TRUE;\r
 \r
@@ -3927,25 +4354,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 ? '+' : ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteQueen : BlackQueen));\r
       break;\r
     case PB_Rook:\r
-      promoChar = 'r';\r
+      promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteRook : BlackRook));\r
+      if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) promoChar = PieceToChar(BlackDragon);\r
       break;\r
     case PB_Bishop:\r
-      promoChar = 'b';\r
+      promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteBishop : BlackBishop));\r
+      if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) promoChar = PieceToChar(BlackAlfil);\r
+      break;\r
+    case PB_Chancellor:\r
+      promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteMarshall : BlackMarshall));\r
+      break;\r
+    case PB_Archbishop:\r
+      promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteAngel : BlackAngel));\r
       break;\r
     case PB_Knight:\r
-      promoChar = 'n';\r
+      promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(WhiteOnMove(currentMove) ? WhiteKnight : BlackKnight);\r
       break;\r
     default:\r
       return FALSE;\r
     }\r
+    if(promoChar == '.') return FALSE; // invalid piece chosen \r
     EndDialog(hDlg, TRUE); /* Exit the dialog */\r
     UserMoveEvent(fromX, fromY, toX, toY, promoChar);\r
+    fromX = fromY = -1;\r
     if (!appData.highlightLastMove) {\r
       ClearHighlights();\r
       DrawPosition(FALSE, NULL);\r
@@ -3967,11 +4404,19 @@ PromotionPopup(HWND hwnd)
   FreeProcInstance(lpProc);\r
 }\r
 \r
+void\r
+PromotionPopUp()\r
+{\r
+  DrawPosition(TRUE, NULL);\r
+  PromotionPopup(hwndMain);\r
+}\r
+\r
 /* Toggle ShowThinking */\r
 VOID\r
 ToggleShowThinking()\r
 {\r
-  ShowThinkingEvent(!appData.showThinking);\r
+  appData.showThinking = !appData.showThinking;\r
+  ShowThinkingEvent();\r
 }\r
 \r
 VOID\r
@@ -3980,7 +4425,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
@@ -3989,7 +4434,7 @@ LoadGameDialog(HWND hwnd, char* title)
     if (number == 0) {\r
       int error = GameListBuild(f);\r
       if (error) {\r
-        DisplayError("Cannot build game list", error);\r
+        DisplayError(_("Cannot build game list"), error);\r
       } else if (!ListEmpty(&gameList) &&\r
                  ((ListGame *) gameList.tailPred)->number > 1) {\r
        GameListPopUp(f, fileTitle);\r
@@ -4002,6 +4447,57 @@ LoadGameDialog(HWND hwnd, char* title)
   }\r
 }\r
 \r
+int get_term_width()\r
+{\r
+    HDC hdc;\r
+    TEXTMETRIC tm;\r
+    RECT rc;\r
+    HFONT hfont, hold_font;\r
+    LOGFONT lf;\r
+    HWND hText;\r
+\r
+    if (hwndConsole)\r
+        hText = GetDlgItem(hwndConsole, OPT_ConsoleText);\r
+    else\r
+        return 79;\r
+\r
+    // get the text metrics\r
+    hdc = GetDC(hText);\r
+    lf = font[boardSize][CONSOLE_FONT]->lf;\r
+    if (consoleCF.dwEffects & CFE_BOLD)\r
+        lf.lfWeight = FW_BOLD;\r
+    if (consoleCF.dwEffects & CFE_ITALIC)\r
+        lf.lfItalic = TRUE;\r
+    if (consoleCF.dwEffects & CFE_STRIKEOUT)\r
+        lf.lfStrikeOut = TRUE;\r
+    if (consoleCF.dwEffects & CFE_UNDERLINE)\r
+        lf.lfUnderline = TRUE;\r
+    hfont = CreateFontIndirect(&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
+    return (rc.right-rc.left) / tm.tmAveCharWidth;\r
+}\r
+\r
+void UpdateICSWidth(HWND hText)\r
+{\r
+    LONG old_width, new_width;\r
+\r
+    new_width = get_term_width(hText, FALSE);\r
+    old_width = GetWindowLongPtr(hText, GWLP_USERDATA);\r
+    if (new_width != old_width)\r
+    {\r
+        ics_update_width(new_width);\r
+        SetWindowLongPtr(hText, GWLP_USERDATA, new_width);\r
+    }\r
+}\r
+\r
 VOID\r
 ChangedConsoleFont()\r
 {\r
@@ -4014,7 +4510,8 @@ ChangedConsoleFont()
 \r
   cfmt.cbSize = sizeof(CHARFORMAT);\r
   cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;\r
-  strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);\r
+    safeStrCpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName,\r
+              sizeof(cfmt.szFaceName)/sizeof(cfmt.szFaceName[0]) );\r
   /* yHeight is expressed in twips.  A twip is 1/20 of a font's point\r
    * size.  This was undocumented in the version of MSVC++ that I had\r
    * when I wrote the code, but is apparently documented now.\r
@@ -4041,6 +4538,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
@@ -4059,6 +4557,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
@@ -4082,33 +4582,29 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
   case WM_MBUTTONUP:\r
   case WM_RBUTTONUP:\r
   case WM_MOUSEMOVE:\r
+  case WM_MOUSEWHEEL:\r
     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 == '\r' || (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
+               TypeInEvent((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
@@ -4119,11 +4615,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
@@ -4151,18 +4643,21 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     switch (wmId) {\r
     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
+      }\r
+      break;\r
+\r
+    case IDM_NewVariant:\r
+      NewVariantPopup(hwnd);\r
       break;\r
 \r
-    case IDM_NewGameFRC:
-      if( NewGameFRC() == 0 ) {
-        ResetGameEvent();
-        AnalysisPopDown();
-      }
-      break;
-
     case IDM_LoadGame:\r
-      LoadGameDialog(hwnd, "Load Game from File");\r
+      LoadGameDialog(hwnd, _("Load Game from File"));\r
       break;\r
 \r
     case IDM_LoadNextGame:\r
@@ -4182,10 +4677,10 @@ 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
+                        _("Load Position from File"), &number, fileTitle, NULL);\r
       if (f != NULL) {\r
        LoadPosition(f, number, fileTitle);\r
       }\r
@@ -4205,10 +4700,10 @@ 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
+                        _("Save Game to File"), NULL, fileTitle, NULL);\r
       if (f != NULL) {\r
        SaveGame(f, 0, "");\r
       }\r
@@ -4216,15 +4711,26 @@ 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
+                        _("Save Position to File"), NULL, fileTitle, NULL);\r
       if (f != NULL) {\r
        SavePosition(f, 0, "");\r
       }\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
@@ -4233,24 +4739,68 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       PasteGameFromClipboard();\r
       break;\r
 \r
-    /* [AS] Autodetect FEN or PGN data */
-    case IDM_Paste:
-      PasteGameOrFENFromClipboard();
-      break;
-
-    /* [AS] User adjudication */
-    case IDM_UserAdjudication_White:
-        UserAdjudicationEvent( +1 );
-        break;
-
-    case IDM_UserAdjudication_Black:
-        UserAdjudicationEvent( -1 );
-        break;
-
-    case IDM_UserAdjudication_Draw:
-        UserAdjudicationEvent( 0 );
-        break;
-
+    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(NULL);\r
+      break;\r
+\r
     case IDM_CopyPosition:\r
       CopyFENToClipboard();\r
       break;\r
@@ -4287,6 +4837,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
@@ -4300,6 +4851,11 @@ 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_Match: // [HGM] match: flows into next case, after setting Match Mode and nr of Games\r
+      MatchEvent(2); // distinguish from command-line-triggered case (matchMode=1)\r
       break;\r
 \r
     case IDM_TwoMachines:\r
@@ -4313,14 +4869,40 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
          TagsPopUp(tags, CmailMsg());\r
          free(tags);\r
       }\r
+      SAY("computer starts playing both sides");\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
+        snprintf(buf, MSG_SIZ, _("%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
+                snprintf(buf, MSG_SIZ, "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
@@ -4329,12 +4911,12 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     case IDM_AnalyzeFile:\r
       if (!first.analysisSupport) {\r
         char buf[MSG_SIZ];\r
-        sprintf(buf, "%s does not support analysis", first.tidy);\r
+         snprintf(buf, MSG_SIZ, _("%s does not support analysis"), first.tidy);\r
         DisplayError(buf, 0);\r
       } else {\r
        if (!appData.showThinking) ToggleShowThinking();\r
        AnalyzeFileEvent();\r
-       LoadGameDialog(hwnd, "Analyze Game from File");\r
+       LoadGameDialog(hwnd, _("Analyze Game from File"));\r
        AnalysisPeriodicEvent(1);\r
       }\r
       break;\r
@@ -4344,11 +4926,15 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       break;\r
 \r
     case IDM_EditGame:\r
+    case IDM_EditGame2:\r
       EditGameEvent();\r
+      SAY("edit game");\r
       break;\r
 \r
     case IDM_EditPosition:\r
+    case IDM_EditPosition2:\r
       EditPositionEvent();\r
+      SAY("enter a FEN string or setup a position on the board using the control R pop up menu");\r
       break;\r
 \r
     case IDM_Training:\r
@@ -4359,12 +4945,31 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       ShowGameListProc();\r
       break;\r
 \r
+    case IDM_EditProgs1:\r
+      EditTagsPopUp(firstChessProgramNames, &firstChessProgramNames);\r
+      break;\r
+\r
+    case IDM_EditProgs2:\r
+     LoadEnginePopUp(hwndMain);\r
+//      EditTagsPopUp(secondChessProgramNames, &secondChessProgramNames);\r
+      break;\r
+\r
+    case IDM_EditServers:\r
+      EditTagsPopUp(icsNames, &icsNames);\r
+      break;\r
+\r
     case IDM_EditTags:\r
+    case IDM_Tags:\r
       EditTagsProc();\r
       break;\r
 \r
+    case IDM_EditBook:\r
+      EditBookEvent();\r
+      break;\r
+\r
     case IDM_EditComment:\r
-      if (commentDialogUp && editComment) {\r
+    case IDM_Comment:\r
+      if (commentUp && editComment) {\r
        CommentPopDown();\r
       } else {\r
        EditCommentEvent();\r
@@ -4415,8 +5020,16 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       StopExaminingEvent();\r
       break;\r
 \r
+    case IDM_Upload:\r
+      UploadGameEvent();\r
+      break;\r
+\r
     case IDM_TypeInMove:\r
-      PopUpMoveDialog('\000');\r
+      TypeInEvent('\000');\r
+      break;\r
+\r
+    case IDM_TypeInName:\r
+      PopUpNameDialog('\000');\r
       break;\r
 \r
     case IDM_Backward:\r
@@ -4424,6 +5037,8 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       SetFocus(hwndMain);\r
       break;\r
 \r
+    JAWS_MENU_ITEMS\r
+\r
     case IDM_Forward:\r
       ForwardEvent();\r
       SetFocus(hwndMain);\r
@@ -4440,7 +5055,11 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       break;\r
 \r
     case IDM_Revert:\r
-      RevertEvent();\r
+      RevertEvent(FALSE);\r
+      break;\r
+\r
+    case IDM_Annotate: // [HGM] vari: revert with annotation\r
+      RevertEvent(TRUE);\r
       break;\r
 \r
     case IDM_TruncateGame:\r
@@ -4460,14 +5079,49 @@ 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
+      DisplayLogos();\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
+      savedHwnd = hwnd;\r
+      if(WaitForEngine(&second, SettingsMenuIfReady)) break;\r
+      EngineOptionsPopup(hwnd, &second);\r
+      break;\r
+\r
+    case IDM_OptionsUCI:\r
+      UciOptionsPopup(hwnd);\r
+      break;\r
+\r
+    case IDM_Tourney:\r
+      TourneyPopup(hwnd);\r
+      break;\r
+\r
     case IDM_IcsOptions:\r
       IcsOptionsPopup(hwnd);\r
       break;\r
@@ -4525,7 +5179,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(appData.nameOfDebugFile, "w");
+       debugFP = fopen(appData.nameOfDebugFile, "w");\r
         SetCurrentDirectory(dir);\r
         setbuf(debugFP, NULL);\r
       } else {\r
@@ -4535,17 +5189,19 @@ 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
-                   "Unable to activate help",\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
+                   _("Unable to activate help"),\r
                    szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);\r
       }\r
       break;\r
@@ -4553,7 +5209,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     case IDM_HELPHELP:\r
       if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {\r
        MessageBox (GetFocus(),\r
-                   "Unable to activate help",\r
+                   _("Unable to activate help"),\r
                    szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);\r
       }\r
       break;\r
@@ -4567,12 +5223,12 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       break;\r
 \r
     case IDM_DirectCommand1:\r
-      AskQuestionEvent("Direct Command",\r
-                      "Send to chess program:", "", "1");\r
+      AskQuestionEvent(_("Direct Command"),\r
+                      _("Send to chess program:"), "", "1");\r
       break;\r
     case IDM_DirectCommand2:\r
-      AskQuestionEvent("Direct Command",\r
-                      "Send to second chess program:", "", "2");\r
+      AskQuestionEvent(_("Direct Command"),\r
+                      _("Send to second chess program:"), "", "2");\r
       break;\r
 \r
     case EP_WhitePawn:\r
@@ -4600,6 +5256,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
@@ -4630,6 +5316,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
@@ -4655,6 +5371,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
@@ -4680,7 +5406,23 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       fromX = fromY = -1;\r
       break;\r
 \r
+    case IDM_English:\r
+      barbaric = 0; appData.language = "";\r
+      TranslateMenus(0);\r
+      CheckMenuItem(GetMenu(hwndMain), lastChecked, MF_BYCOMMAND|MF_UNCHECKED);\r
+      CheckMenuItem(GetMenu(hwndMain), IDM_English, MF_BYCOMMAND|MF_CHECKED);\r
+      lastChecked = wmId;\r
+      break;\r
+\r
     default:\r
+      if(wmId > IDM_English && wmId < IDM_English+20) {\r
+          LoadLanguageFile(languageFile[wmId - IDM_English - 1]);\r
+          TranslateMenus(0);\r
+          CheckMenuItem(GetMenu(hwndMain), lastChecked, MF_BYCOMMAND|MF_UNCHECKED);\r
+          CheckMenuItem(GetMenu(hwndMain), wmId, MF_BYCOMMAND|MF_CHECKED);\r
+          lastChecked = wmId;\r
+          break;\r
+      }\r
       return (DefWindowProc(hwnd, message, wParam, lParam));\r
     }\r
     break;\r
@@ -4698,8 +5440,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
@@ -4718,20 +5460,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   = wpMain.x;           //              replace by these 4 lines to reconstruct old rect\r
+           rcMain.right  = wpMain.x + wpMain.width;\r
+           rcMain.top    = wpMain.y;\r
+           rcMain.bottom = wpMain.y + wpMain.height;\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
+           wpMain.x = lpwp->x;\r
+            wpMain.y = 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
@@ -4739,7 +5517,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
@@ -4843,7 +5623,7 @@ MyLoadSound(MySound *ms)
   struct stat st;\r
   FILE *f;\r
 \r
-  if (ms->data) free(ms->data);\r
+  if (ms->data && ms->flag) free(ms->data);\r
   ms->data = NULL;\r
 \r
   switch (ms->name[0]) {\r
@@ -4864,6 +5644,7 @@ MyLoadSound(MySound *ms)
       HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");\r
       if (h == NULL) break;\r
       ms->data = (void *)LoadResource(hInst, h);\r
+      ms->flag = 0; // not maloced, so cannot be freed!\r
       if (h == NULL) break;\r
       ok = TRUE;\r
     }\r
@@ -4874,6 +5655,7 @@ MyLoadSound(MySound *ms)
     if (f == NULL) break;\r
     if (fstat(fileno(f), &st) < 0) break;\r
     ms->data = malloc(st.st_size);\r
+    ms->flag = 1;\r
     if (fread(ms->data, st.st_size, 1, f) < 1) break;\r
     fclose(f);\r
     ok = TRUE;\r
@@ -4881,7 +5663,7 @@ MyLoadSound(MySound *ms)
   }\r
   if (!ok) {\r
     char buf[MSG_SIZ];\r
-    sprintf(buf, "Error loading sound %s", ms->name);\r
+      snprintf(buf, MSG_SIZ, _("Error loading sound %s"), ms->name);\r
     DisplayError(buf, GetLastError());\r
   }\r
   return ok;\r
@@ -4891,8 +5673,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
@@ -4922,13 +5707,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
@@ -4951,6 +5729,7 @@ OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
       number = NULL;\r
     }\r
     CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));\r
+    Translate(hDlg, 1536);\r
     return FALSE;  /* Allow for further processing */\r
 \r
   case WM_COMMAND:\r
@@ -4970,6 +5749,7 @@ OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
   OFNOTIFY *ofnot;\r
   switch (uiMsg) {\r
   case WM_INITDIALOG:\r
+    Translate(hdlg, DLG_IndexNumber);\r
     ofname = (OPENFILENAME *)lParam;\r
     number = (UINT *)(ofname->lCustData);\r
     break;\r
@@ -4985,7 +5765,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
@@ -4995,12 +5775,12 @@ OpenFileDialog(HWND hwnd, BOOL write, char *defName, char *defExt,
 \r
   if (fileName == NULL) fileName = buf1;\r
   if (defName == NULL) {\r
-    strcpy(fileName, "*.");\r
+    safeStrCpy(fileName, "*.", 3 );\r
     strcat(fileName, defExt);\r
   } else {\r
-    strcpy(fileName, defName);\r
+    safeStrCpy(fileName, defName, MSG_SIZ );\r
   }\r
-  if (fileTitle) strcpy(fileTitle, "");\r
+    if (fileTitle) safeStrCpy(fileTitle, "", MSG_SIZ );\r
   if (number) *number = 0;\r
 \r
   openFileName.lStructSize       = sizeof(OPENFILENAME);\r
@@ -5017,7 +5797,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
@@ -5028,18 +5808,18 @@ 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
+      MessageBox(hwnd, _("File open failed"), NULL,\r
                 MB_OK|MB_ICONEXCLAMATION);\r
       return NULL;\r
     }\r
   } else {\r
     int err = CommDlgExtendedError();\r
-    if (err != 0) DisplayError("Internal error in file dialog box", err);\r
+    if (err != 0) DisplayError(_("Internal error in file dialog box"), err);\r
     return FALSE;\r
   }\r
   return f;\r
@@ -5057,6 +5837,7 @@ MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
    * menu that TrackPopupMenu displays.\r
    */\r
   hmenuTrackPopup = GetSubMenu(hmenu, 0);\r
+  TranslateOneMenu(10, hmenuTrackPopup);\r
 \r
   SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);\r
 \r
@@ -5132,8 +5913,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
@@ -5165,7 +5945,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
@@ -5177,6 +5963,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
@@ -5188,7 +5980,7 @@ InitComboStrings(HANDLE hwndCombo, char **cd)
   SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);\r
 \r
   while (*cd != NULL) {\r
-    SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);\r
+    SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) T_(*cd));\r
     cd++;\r
   }\r
 }\r
@@ -5196,7 +5988,7 @@ InitComboStrings(HANDLE hwndCombo, char **cd)
 void\r
 InitComboStringsFromOption(HANDLE hwndCombo, char *str)\r
 {\r
-  char buf1[ARG_MAX];\r
+  char buf1[MAX_ARG_LEN];\r
   int len;\r
 \r
   if (str[0] == '@') {\r
@@ -5229,7 +6021,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
@@ -5267,10 +6059,10 @@ InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir,
 \r
   InitComboStringsFromOption(hwndCombo, nthnames);\r
   q = QuoteForFilename(nthcp);\r
-  sprintf(buf, "%s%s%s", q, nthcp, q);\r
+    snprintf(buf, MSG_SIZ, "%s%s%s", q, nthcp, q);\r
   if (*nthdir != NULLCHAR) {\r
     q = QuoteForFilename(nthdir);\r
-    sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);\r
+      snprintf(buf + strlen(buf), MSG_SIZ, " /%s=%s%s%s", nthd, q, nthdir, q);\r
   }\r
   if (*nthcp == NULLCHAR) {\r
     SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);\r
@@ -5291,16 +6083,17 @@ StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
   case WM_INITDIALOG:\r
     /* Center the dialog */\r
     CenterWindow (hDlg, GetDesktopWindow());\r
+    Translate(hDlg, DLG_Startup);\r
     /* Initialize the dialog items */\r
     InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),\r
                  appData.firstChessProgram, "fd", appData.firstDirectory,\r
                  firstChessProgramNames);\r
     InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),\r
-                 appData.secondChessProgram, "sd", appData.secondDirectory,\r
-                 secondChessProgramNames);\r
+                 appData.secondChessProgram, singleList ? "fd" : "sd", appData.secondDirectory,\r
+                 singleList ? firstChessProgramNames : secondChessProgramNames); //[HGM] single: use first list in second combo\r
     hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);\r
     InitComboStringsFromOption(hwndCombo, icsNames);    \r
-    sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);\r
+      snprintf(buf, MSG_SIZ, "%s /icsport=%s", appData.icsHost, appData.icsPort);\r
     if (*appData.icsHelper != NULLCHAR) {\r
       char *q = QuoteForFilename(appData.icsHelper);\r
       sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);\r
@@ -5312,17 +6105,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 (appData.icsActive) {
+\r
+    if (appData.icsActive) {\r
       CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);\r
-    }
-    else if (appData.noChessProgram) {
+    }\r
+    else if (appData.noChessProgram) {\r
       CheckDlgButton(hDlg, OPT_View, BST_CHECKED);\r
     }\r
-    else {
-      CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
-    }
-
+    else {\r
+      CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);\r
+    }\r
+\r
     SetStartupDialogEnables(hDlg);\r
     return TRUE;\r
 \r
@@ -5330,23 +6123,25 @@ StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
     switch (LOWORD(wParam)) {\r
     case IDOK:\r
       if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {\r
-        strcpy(buf, "/fcp=");\r
+        safeStrCpy(buf, "/fcp=", sizeof(buf)/sizeof(buf[0]) );\r
        GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));\r
         p = buf;\r
        ParseArgs(StringGet, &p);\r
-        strcpy(buf, "/scp=");\r
+       safeStrCpy(buf, singleList ? "/fcp=" : "/scp=", sizeof(buf)/sizeof(buf[0]) );\r
        GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));\r
-        p = buf;\r
+        p = buf;
+       SwapEngines(singleList); // temporarily swap first and second, to load a second 'first', ...\r
        ParseArgs(StringGet, &p);\r
+       SwapEngines(singleList); // ... and then make it 'second'\r
        appData.noChessProgram = FALSE;\r
        appData.icsActive = FALSE;\r
       } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {\r
-        strcpy(buf, "/ics /icshost=");\r
+        safeStrCpy(buf, "/ics /icshost=", sizeof(buf)/sizeof(buf[0]) );\r
        GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));\r
         p = buf;\r
        ParseArgs(StringGet, &p);\r
        if (appData.zippyPlay) {\r
-         strcpy(buf, "/fcp=");\r
+         safeStrCpy(buf, "/fcp=", sizeof(buf)/sizeof(buf[0]) );\r
          GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));\r
          p = buf;\r
          ParseArgs(StringGet, &p);\r
@@ -5355,8 +6150,8 @@ StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
        appData.noChessProgram = TRUE;\r
        appData.icsActive = FALSE;\r
       } else {\r
-       MessageBox(hDlg, "Choose an option, or cancel to exit",\r
-                  "Option Error", MB_OK|MB_ICONEXCLAMATION);\r
+       MessageBox(hDlg, _("Choose an option, or cancel to exit"),\r
+                  _("Option Error"), MB_OK|MB_ICONEXCLAMATION);\r
        return TRUE;\r
       }\r
       if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {\r
@@ -5374,7 +6169,7 @@ StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
     case IDM_HELPCONTENTS:\r
       if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {\r
        MessageBox (GetFocus(),\r
-                   "Unable to activate help",\r
+                   _("Unable to activate help"),\r
                    szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);\r
       }\r
       break;\r
@@ -5403,6 +6198,8 @@ 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
+    Translate(hDlg, ABOUTBOX);\r
+    JAWS_COPYRIGHT\r
     return (TRUE);\r
 \r
   case WM_COMMAND: /* message: received a command */\r
@@ -5435,6 +6232,7 @@ CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
   switch (message) {\r
   case WM_INITDIALOG: /* message: initialize dialog box */\r
     /* Initialize the dialog items */\r
+    Translate(hDlg, DLG_EditComment);\r
     hwndText = GetDlgItem(hDlg, OPT_CommentText);\r
     SetDlgItemText(hDlg, OPT_CommentText, commentText);\r
     EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);\r
@@ -5457,18 +6255,18 @@ CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
       GetClientRect(hDlg, &rect);\r
       sizeX = rect.right;\r
       sizeY = rect.bottom;\r
-      if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&\r
-         commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {\r
+      if (wpComment.x != CW_USEDEFAULT && wpComment.y != CW_USEDEFAULT &&\r
+         wpComment.width != CW_USEDEFAULT && wpComment.height != CW_USEDEFAULT) {\r
        WINDOWPLACEMENT wp;\r
-       EnsureOnScreen(&commentX, &commentY);\r
+       EnsureOnScreen(&wpComment.x, &wpComment.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 = commentX;\r
-       wp.rcNormalPosition.right = commentX + commentW;\r
-       wp.rcNormalPosition.top = commentY;\r
-       wp.rcNormalPosition.bottom = commentY + commentH;\r
+       wp.rcNormalPosition.left = wpComment.x;\r
+       wp.rcNormalPosition.right = wpComment.x + wpComment.width;\r
+       wp.rcNormalPosition.top = wpComment.y;\r
+       wp.rcNormalPosition.bottom = wpComment.y + wpComment.height;\r
        SetWindowPlacement(hDlg, &wp);\r
 \r
        GetClientRect(hDlg, &rect);\r
@@ -5480,6 +6278,7 @@ CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
        sizeY = newSizeY;\r
       }\r
     }\r
+    SendDlgItemMessage( hDlg, OPT_CommentText, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS | ENM_KEYEVENTS );\r
     return FALSE;\r
 \r
   case WM_COMMAND: /* message: received a command */\r
@@ -5524,6 +6323,42 @@ CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
     }\r
     break;\r
 \r
+  case WM_NOTIFY: // [HGM] vari: cloned from whistory.c\r
+        if( wParam == OPT_CommentText ) {\r
+            MSGFILTER * lpMF = (MSGFILTER *) lParam;\r
+\r
+            if( lpMF->msg == WM_RBUTTONDOWN && (lpMF->wParam & (MK_CONTROL | MK_SHIFT)) == 0 ||\r
+                lpMF->msg == WM_CHAR && lpMF->wParam == '\022' ) {\r
+                POINTL pt;\r
+                LRESULT index;\r
+\r
+                pt.x = LOWORD( lpMF->lParam );\r
+                pt.y = HIWORD( lpMF->lParam );\r
+\r
+                if(lpMF->msg == WM_CHAR) {\r
+                        CHARRANGE sel;\r
+                        SendDlgItemMessage( hDlg, OPT_CommentText, EM_EXGETSEL, 0, (LPARAM) &sel );\r
+                        index = sel.cpMin;\r
+                } else\r
+                index = SendDlgItemMessage( hDlg, OPT_CommentText, EM_CHARFROMPOS, 0, (LPARAM) &pt );\r
+\r
+               hwndText = GetDlgItem(hDlg, OPT_CommentText); // cloned from above\r
+               len = GetWindowTextLength(hwndText);\r
+               str = (char *) malloc(len + 1);\r
+               GetWindowText(hwndText, str, len + 1);\r
+               ReplaceComment(commentIndex, str);\r
+               if(commentIndex != currentMove) ToNrEvent(commentIndex);\r
+                LoadVariation( index, str ); // [HGM] also does the actual moving to it, now\r
+               free(str);\r
+\r
+                /* Zap the message for good: apparently, returning non-zero is not enough */\r
+                lpMF->msg = WM_USER;\r
+\r
+                return TRUE;\r
+            }\r
+        }\r
+        break;\r
+\r
   case WM_SIZE:\r
     newSizeX = LOWORD(lParam);\r
     newSizeY = HIWORD(lParam);\r
@@ -5548,7 +6383,7 @@ EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
   FARPROC lpProc;\r
   char *p, *q;\r
 \r
-  CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);\r
+  CheckMenuItem(GetMenu(hwndMain), IDM_Comment, edit ? MF_CHECKED : MF_UNCHECKED);\r
 \r
   if (str == NULL) str = "";\r
   p = (char *) malloc(2 * strlen(str) + 2);\r
@@ -5567,14 +6402,14 @@ EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
 \r
   if (commentDialog) {\r
     SendMessage(commentDialog, WM_INITDIALOG, 0, 0);\r
-    if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);\r
+    if (!commentUp) ShowWindow(commentDialog, SW_SHOW);\r
   } else {\r
     lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);\r
     CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),\r
                 hwndMain, (DLGPROC)lpProc);\r
     FreeProcInstance(lpProc);\r
   }\r
-  commentDialogUp = TRUE;\r
+  commentUp = TRUE;\r
 }\r
 \r
 \r
@@ -5589,15 +6424,13 @@ TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
 {\r
   char move[MSG_SIZ];\r
   HWND hInput;\r
-  ChessMove moveType;\r
-  int fromX, fromY, toX, toY;\r
-  char promoChar;\r
 \r
   switch (message) {\r
   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
+    Translate(hDlg, DLG_TypeInMove);\r
     hInput = GetDlgItem(hDlg, OPT_Move);\r
     SetWindowText(hInput, move);\r
     SetFocus(hInput);\r
@@ -5606,21 +6439,11 @@ TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
 \r
   case WM_COMMAND:\r
     switch (LOWORD(wParam)) {\r
-    case IDOK:\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
-         &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {\r
-         if (gameMode != Training)\r
-             forwardMostMove = currentMove;\r
-         UserMoveEvent(fromX, fromY, toX, toY, promoChar);     \r
-       } else {\r
-         DisplayMoveError("Could not parse move");\r
-       }\r
-      }\r
+    case IDOK:
+\r
+      shiftKey = GetKeyState(VK_SHIFT) < 0; // [HGM] remember last shift status\r
+      GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
+      TypeInDoneEvent(move);\r
       EndDialog(hDlg, TRUE);\r
       return TRUE;\r
     case IDCANCEL:\r
@@ -5638,18 +6461,72 @@ VOID
 PopUpMoveDialog(char firstchar)\r
 {\r
     FARPROC lpProc;\r
-    \r
-    if ((gameMode == BeginningOfGame && !appData.icsActive) || \r
-        gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||\r
-       gameMode == AnalyzeMode || gameMode == EditGame || \r
-       gameMode == EditPosition || gameMode == IcsExamining ||\r
-       gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||\r
-       gameMode == Training) {\r
+\r
       lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);\r
       DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),\r
        hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);\r
       FreeProcInstance(lpProc);\r
+}\r
+\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
+    Translate(hDlg, DLG_TypeInName);\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
+      SetGameInfo();\r
+      if(gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack) {\r
+       snprintf(move, MSG_SIZ, "%s vs. %s", gameInfo.white, gameInfo.black);\r
+       DisplayTitle(move);\r
+      }\r
+\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
@@ -5705,6 +6582,7 @@ ErrorPopDown()
   if (errorDialog == NULL) return;\r
   DestroyWindow(errorDialog);\r
   errorDialog = NULL;\r
+  if(errorExitStatus) ExitEvent(errorExitStatus);\r
 }\r
 \r
 LRESULT CALLBACK\r
@@ -5716,9 +6594,22 @@ 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
+    Translate(hDlg, DLG_Error);\r
+\r
     errorDialog = hDlg;\r
     SetWindowText(hDlg, errorTitle);\r
     hwndText = GetDlgItem(hDlg, OPT_ErrorText);\r
@@ -5741,6 +6632,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, wpMain.x, wpMain.y-height, wpMain.width, 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
@@ -5787,76 +6746,7 @@ NextInHistory()
 {\r
   if (histP == histIn) return NULL;\r
   histP = (histP + 1) % HISTORY_SIZE;\r
-  return history[histP];\r
-}\r
-\r
-typedef struct {\r
-  char *item;\r
-  char *command;\r
-  BOOLEAN getname;\r
-  BOOLEAN immediate;\r
-} IcsTextMenuEntry;\r
-#define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)\r
-IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];\r
-\r
-void\r
-ParseIcsTextMenu(char *icsTextMenuString)\r
-{\r
-  int flags = 0;\r
-  IcsTextMenuEntry *e = icsTextMenuEntry;\r
-  char *p = icsTextMenuString;\r
-  while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {\r
-    free(e->item);\r
-    e->item = NULL;\r
-    if (e->command != NULL) {\r
-      free(e->command);\r
-      e->command = NULL;\r
-    }\r
-    e++;\r
-  }\r
-  e = icsTextMenuEntry;\r
-  while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {\r
-    if (*p == ';' || *p == '\n') {\r
-      e->item = strdup("-");\r
-      e->command = NULL;\r
-      p++;\r
-    } else if (*p == '-') {\r
-      e->item = strdup("-");\r
-      e->command = NULL;\r
-      p++;\r
-      if (*p) p++;\r
-    } else {\r
-      char *q, *r, *s, *t;\r
-      char c;\r
-      q = strchr(p, ',');\r
-      if (q == NULL) break;\r
-      *q = NULLCHAR;\r
-      r = strchr(q + 1, ',');\r
-      if (r == NULL) break;\r
-      *r = NULLCHAR;\r
-      s = strchr(r + 1, ',');\r
-      if (s == NULL) break;\r
-      *s = NULLCHAR;\r
-      c = ';';\r
-      t = strchr(s + 1, c);\r
-      if (t == NULL) {\r
-       c = '\n';\r
-       t = strchr(s + 1, c);\r
-      }\r
-      if (t != NULL) *t = NULLCHAR;\r
-      e->item = strdup(p);\r
-      e->command = strdup(q + 1);\r
-      e->getname = *(r + 1) != '0';\r
-      e->immediate = *(s + 1) != '0';\r
-      *q = ',';\r
-      *r = ',';\r
-      *s = ',';\r
-      if (t == NULL) break;\r
-      *t = c;\r
-      p = t + 1;\r
-    }\r
-    e++;\r
-  } \r
+  return history[histP];   \r
 }\r
 \r
 HMENU\r
@@ -5869,13 +6759,14 @@ LoadIcsTextMenu(IcsTextMenuEntry *e)
   while (e->item) {\r
     if (strcmp(e->item, "-") == 0) {\r
       AppendMenu(h, MF_SEPARATOR, 0, 0);\r
-    } else {\r
+    } else { // [HGM] re-written a bit to use only one AppendMenu call for both cases (| or no |)\r
+      int flags = MF_STRING, j = 0;\r
       if (e->item[0] == '|') {\r
-       AppendMenu(h, MF_STRING|MF_MENUBARBREAK,\r
-                  IDM_CommandX + i, &e->item[1]);\r
-      } else {\r
-       AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);\r
+       flags |= MF_MENUBARBREAK;\r
+        j++;\r
       }\r
+      if(!strcmp(e->command, "none")) flags |= MF_GRAYED; // [HGM] chatclick: provide inactive dummy\r
+      AppendMenu(h, flags, IDM_CommandX + i, e->item + j);\r
     }\r
     e++;\r
     i++;\r
@@ -5940,11 +6831,13 @@ CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
     SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);\r
   }\r
   if (immediate) {\r
-    sprintf(buf, "%s %s", command, name);\r
+    if(strstr(command, "%s")) snprintf(buf, MSG_SIZ, command, name); else\r
+    snprintf(buf, MSG_SIZ, "%s %s", command, name);\r
     SetWindowText(hInput, buf);\r
     SendMessage(hInput, WM_CHAR, '\r', 0);\r
   } else {\r
-    sprintf(buf, "%s %s ", command, name); /* trailing space */\r
+    if(!strcmp(command, "chat")) { ChatPopUp(name); return; }\r
+      snprintf(buf, MSG_SIZ, "%s %s ", command, name); /* trailing space */\r
     SetWindowText(hInput, buf);\r
     sel.cpMin = 999999;\r
     sel.cpMax = 999999;\r
@@ -5962,6 +6855,7 @@ ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
   switch (message) {\r
   case WM_KEYDOWN:\r
     if (!(GetKeyState(VK_CONTROL) & ~1)) break;\r
+    if(wParam=='R') return 0;\r
     switch (wParam) {\r
     case VK_PRIOR:\r
       SendMessage(hwnd, EM_LINESCROLL, 0, -999999);\r
@@ -5975,6 +6869,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
@@ -5990,16 +6885,12 @@ 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
-  case WM_PASTE:\r
-    hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);\r
-    SetFocus(hInput);\r
-    return SendMessage(hInput, message, wParam, lParam);\r
-  case WM_MBUTTONDOWN:\r
-    return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);\r
+   } // [HGM] navigate: for Ctrl+R, flow into next case (moved up here) to summon up menu\r
+   lParam = -1;\r
   case WM_RBUTTONDOWN:\r
     if (!(GetKeyState(VK_SHIFT) & ~1)) {\r
       /* Move selection here if it was empty */\r
@@ -6008,18 +6899,12 @@ ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       pt.y = HIWORD(lParam);\r
       SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);\r
       if (sel.cpMin == sel.cpMax) {\r
-        sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/\r
+        if(lParam != -1) sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/\r
        sel.cpMax = sel.cpMin;\r
        SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);\r
       }\r
       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
+{ // [HGM] chatclick: code moved here from WM_RBUTTONUP case, to have menu appear on down-click\r
       POINT pt;\r
       HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);\r
       SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);\r
@@ -6030,11 +6915,25 @@ ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       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
+      pt.x = LOWORD(lParam)-30; // [HGM] chatclick: make menu pop up with pointer above upper-right item\r
+      pt.y = HIWORD(lParam)-10; //       make it appear as if mouse moved there, so it will be selected on up-click\r
+      PostMessage(hwnd, WM_MOUSEMOVE, wParam, lParam+5);\r
       MenuPopup(hwnd, pt, hmenu, -1);\r
+}\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
     }\r
     return 0;\r
+  case WM_PASTE:\r
+    hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);\r
+    SetFocus(hInput);\r
+    return SendMessage(hInput, message, wParam, lParam);\r
+  case WM_MBUTTONDOWN:\r
+    return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);\r
   case WM_COMMAND:\r
     switch (LOWORD(wParam)) {\r
     case IDM_QuickPaste:\r
@@ -6151,6 +7050,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
@@ -6244,24 +7144,42 @@ 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
+      SetWindowLongPtr(hText, GWLP_WNDPROC, (LONG_PTR) ConsoleTextSubclass);\r
     SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);\r
     consoleInputWindowProc = (WNDPROC)\r
-      SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);\r
+      SetWindowLongPtr(hInput, GWLP_WNDPROC, (LONG_PTR) ConsoleInputSubclass);\r
     SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);\r
     Colorize(ColorNormal, TRUE);\r
     SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);\r
@@ -6269,20 +7187,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 = wpMain.width + 1;\r
+       wpConsole.y = wpMain.y;\r
+       wpConsole.width = screenWidth -  wpMain.width;\r
+       wpConsole.height = wpMain.height;\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 = (WORD) SendMessage(hText, EM_GETEVENTMASK, 0, 0L);\r
+   SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);\r
+   SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);\r
+   SetWindowLongPtr(hText, GWLP_USERDATA, 79); // initialize the text window's width\r
+\r
     return FALSE;\r
 \r
   case WM_SETFOCUS:\r
@@ -6330,7 +7274,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
@@ -6438,8 +7397,40 @@ 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)
+    snprintf(buf, sizeof(buf)/sizeof(buf[0]),"%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
@@ -6448,9 +7439,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
+      snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%c %s %s", color[0], TimeString(timeRemaining), flagFell);\r
     else\r
-      sprintf(buf, "%s: %s", color, TimeString(timeRemaining));\r
+      snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);\r
     str = buf;\r
   } else {\r
     str = color;\r
@@ -6465,10 +7456,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
+      str += strlen(color)+2;\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
@@ -6481,15 +7484,15 @@ DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
 {\r
   int ok, err;\r
 \r
-  /* [AS]  */
-  if( count <= 0 ) {
-    if (appData.debugMode) {
-      fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
-    }
-
-    return ERROR_INVALID_USER_BUFFER;
-  }
-
+  /* [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
@@ -6532,28 +7535,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 */
-void CheckForInputBufferFull( InputSource * is )
-{
-    if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
-        /* Look for end of line */
-        char * p = is->buf;
-
-        while( p < is->next && *p != '\n' ) {
-            p++;
-        }
-
-        if( p >= is->next ) {
-            if (appData.debugMode) {
-                fprintf( debugFP, "Input line exceeded buffer size (source id=%u)\n", is->id );
-            }
-
-            is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
-            is->count = (DWORD) -1;
-            is->next = is->buf;
-        }
-    }
-}
+/* [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
@@ -6576,27 +7579,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! */
-        break;
+        /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */\r
+        break; \r
       }\r
     }\r
-
-    CheckForInputBufferFull( is );
-
+\r
+    CheckForInputBufferFull( is );\r
+\r
     SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);\r
-
-    if( is->count == ((DWORD) -1) ) break; /* [AS] */
-
+\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
-
-  if (appData.debugMode) {
-    fprintf( debugFP, "Input thread terminated (id=%u, error=%d, count=%d)\n", is->id, is->error, is->count );
-  }
-
+\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
@@ -6646,13 +7649,13 @@ NonOvlInputThread(LPVOID arg)
        is->count = (DWORD) -1;\r
       }\r
     }\r
-
-    CheckForInputBufferFull( is );
-
+\r
+    CheckForInputBufferFull( is );\r
+\r
     SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);\r
-
-    if( is->count == ((DWORD) -1) ) break; /* [AS] */
-
+\r
+    if( is->count == ((DWORD) -1) ) break; /* [AS] */\r
+\r
     if (is->count < 0) break;  /* Quit on error */\r
   }\r
   CloseHandle(is->hFile);\r
@@ -6679,9 +7682,9 @@ SocketInputThread(LPVOID arg)
       }\r
     }\r
     SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);\r
-
-    if( is->count == ((DWORD) -1) ) break; /* [AS] */
-
+\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
@@ -6703,14 +7706,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
@@ -6735,6 +7738,14 @@ typedef struct {
 } Enables;\r
 \r
 VOID\r
+GreyRevert(Boolean grey)\r
+{ // [HGM] vari: for retracting variations in local mode\r
+  HMENU hmenu = GetMenu(hwndMain);\r
+  EnableMenuItem(hmenu, IDM_Revert, MF_BYCOMMAND|(grey ? MF_GRAYED : MF_ENABLED));\r
+  EnableMenuItem(hmenu, IDM_Annotate, MF_BYCOMMAND|(grey ? MF_GRAYED : MF_ENABLED));\r
+}\r
+\r
+VOID\r
 SetMenuEnables(HMENU hmenu, Enables *enab)\r
 {\r
   while (enab->item > 0) {\r
@@ -6753,7 +7764,26 @@ Enables gnuEnables[] = {
   { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_Upload, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },\r
+\r
+  // Needed to switch from ncp to GNU mode on Engine Load\r
+  { ACTION_POS, MF_BYPOSITION|MF_ENABLED },\r
+  { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_Match, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_AnalyzeFile, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_Engine2Options, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_TimeControl, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_Book, MF_BYCOMMAND|MF_ENABLED },\r
   { -1, -1 }\r
 };\r
 \r
@@ -6763,21 +7793,29 @@ 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_Match, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_MachineBoth, 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
   { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_Book, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_EditProgs2, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_Tourney, MF_BYCOMMAND|MF_GRAYED },\r
   { -1, -1 }\r
 };\r
 \r
-#ifdef ZIPPY\r
+#if ZIPPY\r
 Enables zippyEnables[] = {\r
   { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },\r
   { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },\r
   { IDM_Book, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },\r
   { -1, -1 }\r
 };\r
 #endif\r
@@ -6788,21 +7826,29 @@ Enables ncpEnables[] = {
   { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_Match, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },\r
   { ACTION_POS, MF_BYPOSITION|MF_GRAYED },\r
   { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_Book, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_Sounds, MF_BYCOMMAND|MF_GRAYED },\r
   { -1, -1 }\r
 };\r
 \r
 Enables trainingOnEnables[] = {\r
   { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_Comment, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },\r
@@ -6815,6 +7861,7 @@ Enables trainingOnEnables[] = {
 \r
 Enables trainingOffEnables[] = {\r
   { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_Comment, MF_BYCOMMAND|MF_ENABLED },\r
   { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },\r
   { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },\r
   { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },\r
@@ -6851,6 +7898,7 @@ Enables machineThinkingEnables[] = {
   { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },\r
+//  { IDM_Match, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },\r
   { -1, -1 }\r
@@ -6870,6 +7918,7 @@ Enables userThinkingEnables[] = {
   { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },\r
   { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },\r
   { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },\r
+//  { IDM_Match, MF_BYCOMMAND|MF_ENABLED },\r
   { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },\r
   { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },\r
   { -1, -1 }\r
@@ -6882,6 +7931,12 @@ Enables userThinkingEnables[] = {
  * \r
 \*---------------------------------------------------------------------------*/\r
 VOID\r
+CheckMark(UINT item, int state)\r
+{\r
+    if(item) CheckMenuItem(GetMenu(hwndMain), item, MF_BYCOMMAND|state);\r
+}\r
+\r
+VOID\r
 ModeHighlight()\r
 {\r
   static UINT prevChecked = 0;\r
@@ -6942,12 +7997,9 @@ ModeHighlight()
     nowChecked = 0;\r
     break;\r
   }\r
-  if (prevChecked != 0)\r
-    (void) CheckMenuItem(GetMenu(hwndMain),\r
-                        prevChecked, MF_BYCOMMAND|MF_UNCHECKED);\r
-  if (nowChecked != 0)\r
-    (void) CheckMenuItem(GetMenu(hwndMain),\r
-                        nowChecked, MF_BYCOMMAND|MF_CHECKED);\r
+  CheckMark(prevChecked, MF_UNCHECKED);\r
+  CheckMark(nowChecked, MF_CHECKED);\r
+  CheckMark(IDM_Match, matchMode && matchGame < appData.matchGames ? MF_CHECKED : MF_UNCHECKED);\r
 \r
   if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {\r
     (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training, \r
@@ -6958,6 +8010,16 @@ ModeHighlight()
   }\r
 \r
   prevChecked = nowChecked;\r
+\r
+  /* [DM] icsEngineAnalyze - Do a sceure check too */\r
+  if (appData.icsActive) {\r
+       if (appData.icsEngineAnalyze) {\r
+               CheckMark(IDM_AnalysisMode, MF_CHECKED);\r
+       } else {\r
+               CheckMark(IDM_AnalysisMode, MF_UNCHECKED);\r
+       }\r
+  }\r
+  DisplayLogos(); // [HGM] logos: mode change could have altered logos\r
 }\r
 \r
 VOID\r
@@ -6965,11 +8027,14 @@ SetICSMode()
 {\r
   HMENU hmenu = GetMenu(hwndMain);\r
   SetMenuEnables(hmenu, icsEnables);\r
-  EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,\r
-    MF_BYPOSITION|MF_ENABLED);\r
-#ifdef ZIPPY\r
+  EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), IDM_IcsOptions,\r
+    MF_BYCOMMAND|MF_ENABLED);\r
+#if 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
@@ -6985,8 +8050,6 @@ SetNCPMode()
 {\r
   HMENU hmenu = GetMenu(hwndMain);\r
   SetMenuEnables(hmenu, ncpEnables);\r
-  EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,\r
-    MF_BYPOSITION|MF_GRAYED);\r
     DrawMenuBar(hwndMain);\r
 }\r
 \r
@@ -7038,7 +8101,7 @@ SetMachineThinkingEnables()
   } else if (gameMode == MachinePlaysWhite) {\r
     (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);\r
   } else if (gameMode == TwoMachinesPlay) {\r
-    (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);\r
+    (void)EnableMenuItem(hMenu, matchMode ? IDM_Match : IDM_TwoMachines, flags); // [HGM] match\r
   }\r
 }\r
 \r
@@ -7048,17 +8111,17 @@ DisplayTitle(char *str)
 {\r
   char title[MSG_SIZ], *host;\r
   if (str[0] != NULLCHAR) {\r
-    strcpy(title, str);\r
+    safeStrCpy(title, str, sizeof(title)/sizeof(title[0]) );\r
   } else if (appData.icsActive) {\r
     if (appData.icsCommPort[0] != NULLCHAR)\r
       host = "ICS";\r
     else \r
       host = appData.icsHost;\r
-    sprintf(title, "%s: %s", szTitle, host);\r
+      snprintf(title, MSG_SIZ, "%s: %s", szTitle, host);\r
   } else if (appData.noChessProgram) {\r
-    strcpy(title, szTitle);\r
+    safeStrCpy(title, szTitle, sizeof(title)/sizeof(title[0]) );\r
   } else {\r
-    strcpy(title, szTitle);\r
+    safeStrCpy(title, szTitle, sizeof(title)/sizeof(title[0]) );\r
     strcat(title, ": ");\r
     strcat(title, first.tidy);\r
   }\r
@@ -7092,9 +8155,13 @@ DisplayMessage(char *str1, char *str2)
     if (len > remain) len = remain;\r
     strncat(messageText, str2, len);\r
   }\r
-  messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;\r
+  messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
+  safeStrCpy(lastMsg, messageText, MSG_SIZ);
+\r
+  if (hwndMain == NULL || IsIconic(hwndMain)) return;\r
+\r
+  SAYMACHINEMOVE();\r
 \r
-  if (IsIconic(hwndMain)) return;\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
@@ -7110,25 +8177,25 @@ DisplayError(char *str, int error)
   int len;\r
 \r
   if (error == 0) {\r
-    strcpy(buf, str);\r
+    safeStrCpy(buf, str, sizeof(buf)/sizeof(buf[0]) );\r
   } else {\r
     len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,\r
                        NULL, error, LANG_NEUTRAL,\r
                        (LPSTR) buf2, MSG_SIZ, NULL);\r
     if (len > 0) {\r
-      sprintf(buf, "%s:\n%s", str, buf2);\r
+      snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, buf2);\r
     } else {\r
       ErrorMap *em = errmap;\r
       while (em->err != 0 && em->err != error) em++;\r
       if (em->err != 0) {\r
-       sprintf(buf, "%s:\n%s", str, em->msg);\r
+       snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, em->msg);\r
       } else {\r
-       sprintf(buf, "%s:\nError code %d", str, error);\r
+       snprintf(buf, 2*MSG_SIZ, "%s:\nError code %d", str, error);\r
       }\r
     }\r
   }\r
   \r
-  ErrorPopUp("Error", buf);\r
+  ErrorPopUp(_("Error"), buf);\r
 }\r
 \r
 \r
@@ -7139,7 +8206,7 @@ DisplayMoveError(char *str)
   ClearHighlights();\r
   DrawPosition(FALSE, NULL);\r
   if (appData.popupMoveErrors) {\r
-    ErrorPopUp("Error", str);\r
+    ErrorPopUp(_("Error"), str);\r
   } else {\r
     DisplayMessage(str, "");\r
     moveErrorMessageUp = TRUE;\r
@@ -7151,21 +8218,21 @@ DisplayFatalError(char *str, int error, int exitStatus)
 {\r
   char buf[2*MSG_SIZ], buf2[MSG_SIZ];\r
   int len;\r
-  char *label = exitStatus ? "Fatal Error" : "Exiting";\r
+  char *label = exitStatus ? _("Fatal Error") : _("Exiting");\r
 \r
   if (error != 0) {\r
     len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,\r
                        NULL, error, LANG_NEUTRAL,\r
                        (LPSTR) buf2, MSG_SIZ, NULL);\r
     if (len > 0) {\r
-      sprintf(buf, "%s:\n%s", str, buf2);\r
+      snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, buf2);\r
     } else {\r
       ErrorMap *em = errmap;\r
       while (em->err != 0 && em->err != error) em++;\r
       if (em->err != 0) {\r
-       sprintf(buf, "%s:\n%s", str, em->msg);\r
+       snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, em->msg);\r
       } else {\r
-       sprintf(buf, "%s:\nError code %d", str, error);\r
+       snprintf(buf, 2*MSG_SIZ, "%s:\nError code %d", str, error);\r
       }\r
     }\r
     str = buf;\r
@@ -7184,14 +8251,14 @@ DisplayFatalError(char *str, int error, int exitStatus)
 VOID\r
 DisplayInformation(char *str)\r
 {\r
-  (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);\r
+  (void) MessageBox(hwndMain, str, _("Information"), MB_OK|MB_ICONINFORMATION);\r
 }\r
 \r
 \r
 VOID\r
 DisplayNote(char *str)\r
 {\r
-  ErrorPopUp("Note", str);\r
+  ErrorPopUp(_("Note"), str);\r
 }\r
 \r
 \r
@@ -7211,6 +8278,7 @@ QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
   case WM_INITDIALOG:\r
     qp = (QuestionParams *) lParam;\r
     CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));\r
+    Translate(hDlg, DLG_Question);\r
     SetWindowText(hDlg, qp->title);\r
     SetDlgItemText(hDlg, OPT_QuestionText, qp->question);\r
     SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));\r
@@ -7219,14 +8287,14 @@ QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
   case WM_COMMAND:\r
     switch (LOWORD(wParam)) {\r
     case IDOK:\r
-      strcpy(reply, qp->replyPrefix);\r
+      safeStrCpy(reply, qp->replyPrefix, sizeof(reply)/sizeof(reply[0]) );\r
       if (*reply) strcat(reply, " ");\r
       len = strlen(reply);\r
       GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);\r
       strcat(reply, "\n");\r
       OutputToProcess(qp->pr, reply, strlen(reply), &err);\r
       EndDialog(hDlg, TRUE);\r
-      if (err) DisplayFatalError("Error writing to chess program", err, 1);\r
+      if (err) DisplayFatalError(_("Error writing to chess program"), err, 1);\r
       return TRUE;\r
     case IDCANCEL:\r
       EndDialog(hDlg, FALSE);\r
@@ -7255,77 +8323,199 @@ AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
     FreeProcInstance(lpProc);\r
 }\r
 \r
-/* [AS] Pick FRC position */
-LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
-{
-    static int * lpIndexFRC;
-    BOOL index_is_ok;
-    char buf[16];
-
-    switch( message )
-    {
-    case WM_INITDIALOG:
-        lpIndexFRC = (int *) lParam;
-
-        CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
-
-        SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
-        SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
-        SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
-        SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
-
-        break;
-
-    case WM_COMMAND:
-        switch( LOWORD(wParam) ) {
-        case IDOK:
-            *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
-            EndDialog( hDlg, 0 );
-            return TRUE;
-        case IDCANCEL:
-            EndDialog( hDlg, 1 );
-            return TRUE;
-        case IDC_NFG_Edit:
-            if( HIWORD(wParam) == EN_CHANGE ) {
-                GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
-
-                EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
-            }
-            return TRUE;
-        case IDC_NFG_Random:
-            sprintf( buf, "%d", myrandom() % 960 );
-            SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
-            return TRUE;
-        }
-
-        break;
-    }
-
-    return FALSE;
-}
-
-int NewGameFRC()
-{
-    int result;
-    int index = appData.defaultFrcPosition;
-    FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
-
-    result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
-
-    if( result == 0 ) {
-        appData.defaultFrcPosition = index;
-    }
-
-    return result;
-}
-
+/* [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
+        Translate(hDlg, DLG_NewGameFRC);\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
+         snprintf( buf, sizeof(buf)/sizeof(buf[0]), "%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. Refactored by HGM */\r
+\r
+HWND gameListOptionsDialog;\r
+\r
+// low-level front-end: clear text edit / list widget\r
+void\r
+GLT_ClearList()\r
+{\r
+    SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );\r
+}\r
+\r
+// low-level front-end: clear text edit / list widget\r
+void\r
+GLT_DeSelectList()\r
+{\r
+    SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_SETCURSEL, 0, 0 );\r
+}\r
+\r
+// low-level front-end: append line to text edit / list widget\r
+void\r
+GLT_AddToList( char *name )\r
+{\r
+    if( name != 0 ) {\r
+            SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) name );\r
+    }\r
+}\r
+\r
+// low-level front-end: get line from text edit / list widget\r
+Boolean\r
+GLT_GetFromList( int index, char *name )\r
+{\r
+    if( name != 0 ) {\r
+           if( SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR )\r
+               return TRUE;\r
+    }\r
+    return FALSE;\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
+    switch( message )\r
+    {\r
+    case WM_INITDIALOG:\r
+       gameListOptionsDialog = hDlg; // [HGM] pass through global to keep out off back-end\r
+        \r
+        CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));\r
+        Translate(hDlg, DLG_GameListOptions);\r
+\r
+        /* Initialize list */\r
+        GLT_TagsToList( lpUserGLT );\r
+\r
+        SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );\r
+\r
+        break;\r
+\r
+    case WM_COMMAND:\r
+        switch( LOWORD(wParam) ) {\r
+        case IDOK:\r
+           GLT_ParseList();\r
+            EndDialog( hDlg, 0 );\r
+            return TRUE;\r
+        case IDCANCEL:\r
+            EndDialog( hDlg, 1 );\r
+            return TRUE;\r
+\r
+        case IDC_GLT_Default:\r
+            GLT_TagsToList( GLT_DEFAULT_TAGS );\r
+            return TRUE;\r
+\r
+        case IDC_GLT_Restore:\r
+            GLT_TagsToList( appData.gameListTags );\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
+    int result;\r
+    FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );\r
+\r
+      safeStrCpy( lpUserGLT, appData.gameListTags ,LPUSERGLT_SIZE ); \r
+\r
+    result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)lpUserGLT );\r
+\r
+    if( result == 0 ) {\r
+        /* [AS] Memory leak here! */\r
+        appData.gameListTags = strdup( lpUserGLT ); \r
+    }\r
+\r
+    return result;\r
+}\r
 \r
 VOID\r
 DisplayIcsInteractionTitle(char *str)\r
 {\r
   char consoleTitle[MSG_SIZ];\r
 \r
-  sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);\r
+    snprintf(consoleTitle, MSG_SIZ, "%s: %s", szConsoleTitle, str);\r
   SetWindowText(hwndConsole, consoleTitle);\r
 }\r
 \r
@@ -7335,6 +8525,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
@@ -7349,6 +8544,7 @@ ResetFrontEnd()
     ReleaseCapture();\r
     DrawPosition(TRUE, NULL);\r
   }\r
+  TagsPopDown();\r
 }\r
 \r
 \r
@@ -7356,18 +8552,19 @@ VOID
 CommentPopUp(char *title, char *str)\r
 {\r
   HWND hwnd = GetActiveWindow();\r
-  EitherCommentPopUp(0, title, str, FALSE);\r
+  EitherCommentPopUp(currentMove, title, str, FALSE); // [HGM] vari: fake move index, rather than 0\r
+  SAY(str);\r
   SetActiveWindow(hwnd);\r
 }\r
 \r
 VOID\r
 CommentPopDown(void)\r
 {\r
-  CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);\r
+  CheckMenuItem(GetMenu(hwndMain), IDM_Comment, MF_UNCHECKED);\r
   if (commentDialog) {\r
     ShowWindow(commentDialog, SW_HIDE);\r
   }\r
-  commentDialogUp = FALSE;\r
+  commentUp = FALSE;\r
 }\r
 \r
 VOID\r
@@ -7409,6 +8606,12 @@ PlayAlarmSound()
   MyPlaySound(&sounds[(int)SoundAlarm]);\r
 }\r
 \r
+VOID\r
+PlayTellSound()\r
+{\r
+  MyPlaySound(&textAttribs[ColorTell].sound);\r
+}\r
+\r
 \r
 VOID\r
 EchoOn()\r
@@ -7452,9 +8655,12 @@ 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
+    safeStrCpy(buf, _("User"), sizeof(buf)/sizeof(buf[0]) );\r
   }\r
   return buf;\r
 }\r
@@ -7467,7 +8673,7 @@ HostName()
 \r
   if (!GetComputerName(buf, &bufsiz)) {\r
     /*DisplayError("Error getting host name", GetLastError());*/\r
-    strcpy(buf, "Unknown");\r
+    safeStrCpy(buf, _("Unknown"), sizeof(buf)/sizeof(buf[0]) );\r
   }\r
   return buf;\r
 }\r
@@ -7499,9 +8705,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
@@ -7519,9 +8729,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
@@ -7566,10 +8780,10 @@ 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
+                    _("Save Game to File"), NULL, fileTitle, NULL);\r
   if (f != NULL) {\r
     SaveGame(f, 0, "");\r
     fclose(f);\r
@@ -7581,11 +8795,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
@@ -7612,6 +8827,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
@@ -7727,6 +8959,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
@@ -7757,7 +8994,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
@@ -7772,27 +9009,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
-
-    /* [AS] Special termination modes for misbehaving programs... */
-    if( signal == 9 ) {
-        if ( appData.debugMode) {
-            fprintf( debugFP, "Terminating process %u\n", cp->pid );
-        }
-
-        TerminateProcess( cp->hProcess, 0 );
-    }
-    else if( signal == 10 ) {
-        DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
-
-        if( dw != WAIT_OBJECT_0 ) {
-            if ( appData.debugMode) {
-                fprintf( debugFP, "Process %u still alive after timeout, killing...\n", cp->pid );
-            }
-
-            TerminateProcess( cp->hProcess, 0 );
-        }
-    }
-
+\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
@@ -7849,9 +9087,9 @@ OpenTelnet(char *host, char *port, ProcRef *pr)
   char cmdLine[MSG_SIZ];\r
 \r
   if (port[0] == NULLCHAR) {\r
-    sprintf(cmdLine, "%s %s", appData.telnetProgram, host);\r
+    snprintf(cmdLine, MSG_SIZ, "%s %s", appData.telnetProgram, host);\r
   } else {\r
-    sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);\r
+    snprintf(cmdLine, MSG_SIZ, "%s %s %s", appData.telnetProgram, host, port);\r
   }\r
   return StartChildProcess(cmdLine, "", pr);\r
 }\r
@@ -7950,9 +9188,9 @@ OpenCommPort(char *name, ProcRef *pr)
   char fullname[MSG_SIZ];\r
 \r
   if (*name != '\\')\r
-    sprintf(fullname, "\\\\.\\%s", name);\r
+    snprintf(fullname, MSG_SIZ, "\\\\.\\%s", name);\r
   else\r
-    strcpy(fullname, name);\r
+    safeStrCpy(fullname, name, sizeof(fullname)/sizeof(fullname[0]) );\r
 \r
   h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,\r
                 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);\r
@@ -7984,7 +9222,7 @@ OpenCommPort(char *name, ProcRef *pr)
 int\r
 OpenLoopback(ProcRef *pr)\r
 {\r
-  DisplayFatalError("Not implemented", 0, 1);\r
+  DisplayFatalError(_("Not implemented"), 0, 1);\r
   return NO_ERROR;\r
 }\r
 \r
@@ -8122,7 +9360,7 @@ OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
     break;\r
   }\r
   prevStderrPort = fromPort; // remember port used\r
-  sprintf(stderrPortStr, "%d", fromPort);\r
+  snprintf(stderrPortStr, MSG_SIZ, "%d", fromPort);\r
 \r
   if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {\r
     err = WSAGetLastError();\r
@@ -8179,7 +9417,7 @@ InputSourceRef
 AddInputSource(ProcRef pr, int lineByLine,\r
               InputCallback func, VOIDSTAR closure)\r
 {\r
-  InputSource *is, *is2 = NULL;
+  InputSource *is, *is2 = NULL;\r
   ChildProc *cp = (ChildProc *) pr;\r
 \r
   is = (InputSource *) calloc(1, sizeof(InputSource));\r
@@ -8193,18 +9431,18 @@ AddInputSource(ProcRef pr, int lineByLine,
     consoleInputSource = is;\r
   } else {\r
     is->kind = cp->kind;\r
-    /*
-        [AS] Try to avoid a race condition if the thread is given control too early:
-        we create all threads suspended so that the is->hThread variable can be
-        safely assigned, then let the threads start with ResumeThread.
-    */
+    /* \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, CREATE_SUSPENDED, &is->id);
+                    (LPVOID) is, CREATE_SUSPENDED, &is->id);\r
       break;\r
 \r
     case CPComm:\r
@@ -8212,14 +9450,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, CREATE_SUSPENDED, &is->id);
+                    (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, CREATE_SUSPENDED, &is->id);
+                    (LPVOID) is, CREATE_SUSPENDED, &is->id);\r
       break;\r
 \r
     case CPRcmd:\r
@@ -8231,22 +9469,22 @@ AddInputSource(ProcRef pr, int lineByLine,
       is2->second = is2;\r
       is->hThread =\r
        CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,\r
-                    (LPVOID) is, CREATE_SUSPENDED, &is->id);
+                    (LPVOID) is, CREATE_SUSPENDED, &is->id);\r
       is2->hThread =\r
        CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,\r
-                    (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
+                    (LPVOID) is2, CREATE_SUSPENDED, &is2->id);\r
       break;\r
     }\r
-
-    if( is->hThread != NULL ) {
-        ResumeThread( is->hThread );
+\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
-
-    if( is2 != NULL && is2->hThread != NULL ) {
-        ResumeThread( is2->hThread );
-    }
-  }
-
+\r
   return (InputSourceRef) is;\r
 }\r
 \r
@@ -8264,6 +9502,11 @@ RemoveInputSource(InputSourceRef isr)
   }\r
 }\r
 \r
+int no_wrap(char *message, int count)\r
+{\r
+    ConsoleOutput(message, count, FALSE);\r
+    return count;\r
+}\r
 \r
 int\r
 OutputToProcess(ProcRef pr, char *message, int count, int *outError)\r
@@ -8272,11 +9515,32 @@ OutputToProcess(ProcRef pr, char *message, int count, int *outError)
   int outCount = SOCKET_ERROR;\r
   ChildProc *cp = (ChildProc *) pr;\r
   static OVERLAPPED ovl;\r
+  static int line = 0;\r
 \r
-  if (pr == NoProc) {\r
-    ConsoleOutput(message, count, FALSE);\r
-    return count;\r
-  } \r
+  if (pr == NoProc)\r
+  {\r
+    if (appData.noJoin || !appData.useInternalWrap)\r
+      return no_wrap(message, count);\r
+    else\r
+    {\r
+      int width = get_term_width();\r
+      int len = wrap(NULL, message, count, width, &line);\r
+      char *msg = malloc(len);\r
+      int dbgchk;\r
+\r
+      if (!msg)\r
+        return no_wrap(message, count);\r
+      else\r
+      {\r
+        dbgchk = wrap(msg, message, count, width, &line);\r
+        if (dbgchk != len && appData.debugMode)\r
+            fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);\r
+        ConsoleOutput(msg, len, FALSE);\r
+        free(msg);\r
+        return len;\r
+      }\r
+    }\r
+  }\r
 \r
   if (ovl.hEvent == NULL) {\r
     ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);\r
@@ -8328,7 +9592,7 @@ void
 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,\r
                        char *buf, int count, int error)\r
 {\r
-  DisplayFatalError("Not implemented", 0, 1);\r
+  DisplayFatalError(_("Not implemented"), 0, 1);\r
 }\r
 \r
 /* see wgamelist.c for Game List functions */\r
@@ -8360,122 +9624,6 @@ StartAnalysisClock()
                                        (UINT) 2000, NULL);\r
 }\r
 \r
-LRESULT CALLBACK\r
-AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
-{\r
-  static HANDLE hwndText;\r
-  RECT rect;\r
-  static int sizeX, sizeY;\r
-  int newSizeX, newSizeY, flags;\r
-  MINMAXINFO *mmi;\r
-\r
-  switch (message) {\r
-  case WM_INITDIALOG: /* message: initialize dialog box */\r
-    /* Initialize the dialog items */\r
-    hwndText = GetDlgItem(hDlg, OPT_AnalysisText);\r
-    SetWindowText(hDlg, analysisTitle);\r
-    SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);\r
-    /* Size and position the dialog */\r
-    if (!analysisDialog) {\r
-      analysisDialog = hDlg;\r
-      flags = SWP_NOZORDER;\r
-      GetClientRect(hDlg, &rect);\r
-      sizeX = rect.right;\r
-      sizeY = rect.bottom;\r
-      if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&\r
-         analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {\r
-       WINDOWPLACEMENT wp;\r
-       EnsureOnScreen(&analysisX, &analysisY);\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 = analysisX;\r
-       wp.rcNormalPosition.right = analysisX + analysisW;\r
-       wp.rcNormalPosition.top = analysisY;\r
-       wp.rcNormalPosition.bottom = analysisY + analysisH;\r
-       SetWindowPlacement(hDlg, &wp);\r
-\r
-       GetClientRect(hDlg, &rect);\r
-       newSizeX = rect.right;\r
-       newSizeY = rect.bottom;\r
-        ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,\r
-                             newSizeX, newSizeY);\r
-       sizeX = newSizeX;\r
-       sizeY = newSizeY;\r
-      }\r
-    }\r
-    return FALSE;\r
-\r
-  case WM_COMMAND: /* message: received a command */\r
-    switch (LOWORD(wParam)) {\r
-    case IDCANCEL:\r
-      EditGameEvent();\r
-      return TRUE;\r
-    default:\r
-      break;\r
-    }\r
-    break;\r
-\r
-  case WM_SIZE:\r
-    newSizeX = LOWORD(lParam);\r
-    newSizeY = HIWORD(lParam);\r
-    ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);\r
-    sizeX = newSizeX;\r
-    sizeY = newSizeY;\r
-    break;\r
-\r
-  case WM_GETMINMAXINFO:\r
-    /* Prevent resizing window too small */\r
-    mmi = (MINMAXINFO *) lParam;\r
-    mmi->ptMinTrackSize.x = 100;\r
-    mmi->ptMinTrackSize.y = 100;\r
-    break;\r
-  }\r
-  return FALSE;\r
-}\r
-\r
-VOID\r
-AnalysisPopUp(char* title, char* str)\r
-{\r
-  FARPROC lpProc;\r
-  char *p, *q;\r
-\r
-  if (str == NULL) str = "";\r
-  p = (char *) malloc(2 * strlen(str) + 2);\r
-  q = p;\r
-  while (*str) {\r
-    if (*str == '\n') *q++ = '\r';\r
-    *q++ = *str++;\r
-  }\r
-  *q = NULLCHAR;\r
-  if (analysisText != NULL) free(analysisText);\r
-  analysisText = p;\r
-\r
-  if (analysisDialog) {\r
-    SetWindowText(analysisDialog, title);\r
-    SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);\r
-    ShowWindow(analysisDialog, SW_SHOW);\r
-  } else {\r
-    analysisTitle = title;\r
-    lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);\r
-    CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),\r
-                hwndMain, (DLGPROC)lpProc);\r
-    FreeProcInstance(lpProc);\r
-  }\r
-  analysisDialogUp = TRUE;  \r
-}\r
-\r
-VOID\r
-AnalysisPopDown()\r
-{\r
-  if (analysisDialog) {\r
-    ShowWindow(analysisDialog, SW_HIDE);\r
-  }\r
-  analysisDialogUp = FALSE;  \r
-}\r
-\r
-\r
 VOID\r
 SetHighlights(int fromX, int fromY, int toX, int toY)\r
 {\r
@@ -8535,6 +9683,24 @@ static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
 #define kFactor 4\r
 \r
 void\r
+AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)\r
+{      // [HGM] atomic: animate blast wave\r
+       int i;\r
+\r
+       explodeInfo.fromX = fromX;\r
+       explodeInfo.fromY = fromY;\r
+       explodeInfo.toX = toX;\r
+       explodeInfo.toY = toY;\r
+       for(i=1; i<4*kFactor; i++) {\r
+           explodeInfo.radius = (i*180)/(4*kFactor-1);\r
+           DrawPosition(FALSE, board);\r
+           Sleep(appData.animSpeed);\r
+       }\r
+       explodeInfo.radius = 0;\r
+       DrawPosition(TRUE, board);\r
+}\r
+\r
+void\r
 AnimateMove(board, fromX, fromY, toX, toY)\r
      Board board;\r
      int fromX;\r
@@ -8556,17 +9722,17 @@ AnimateMove(board, fromX, fromY, toX, toY)
   ScreenSquare(fromX, fromY, &start);\r
   ScreenSquare(toX, toY, &finish);\r
 \r
-  /* All pieces except knights move in straight line */\r
-  if (piece != WhiteKnight && piece != BlackKnight) {\r
+  /* All moves except knight jumps move in straight line */\r
+  if (!(abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1)) {\r
     mid.x = start.x + (finish.x - start.x) / 2;\r
     mid.y = start.y + (finish.y - start.y) / 2;\r
   } else {\r
-    /* Knight: make diagonal movement then straight */\r
+    /* Knight: make straight movement then diagonal */\r
     if (abs(toY - fromY) < abs(toX - fromX)) {\r
        mid.x = start.x + (finish.x - start.x) / 2;\r
-       mid.y = finish.y;\r
+       mid.y = start.y;\r
      } else {\r
-       mid.x = finish.x;\r
+       mid.x = start.x;\r
        mid.y = start.y + (finish.y - start.y) / 2;\r
      }\r
   }\r
@@ -8592,6 +9758,7 @@ AnimateMove(board, fromX, fromY, toX, toY)
   animInfo.pos = finish;\r
   DrawPosition(FALSE, NULL);\r
   animInfo.piece = EmptySquare;\r
+  Explode(board, fromX, fromY, toX, toY);\r
 }\r
 \r
 /*      Convert board position to corner of screen rect and color       */\r
@@ -8601,11 +9768,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
@@ -8653,16 +9820,33 @@ Tween(start, mid, finish, factor, frames, nFrames)
 }\r
 \r
 void\r
-HistorySet(char movelist[][2*MOVE_LEN], int first, int last, int current)\r
+HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )\r
 {\r
-  /* Currently not implemented in WinBoard */\r
-#if 1
-    /* [AS] Let's see what this function is for... */
-    char buf[256];
+    MoveHistorySet( movelist, first, last, current, pvInfoList );\r
+\r
+    EvalGraphSet( first, last, current, pvInfoList );\r
+\r
+    MakeEngineOutputTitle();\r
+}\r
 \r
-    sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
-        first, last, current, current >= 0 ? movelist[current] : "n/a" );
+void\r
+SettingsPopUp(ChessProgramState *cps)\r
+{     // [HGM] wrapper needed because handles must not be passed through back-end\r
+      EngineOptionsPopup(savedHwnd, cps);\r
+}\r
 \r
-    OutputDebugString( buf );
-#endif
-}
+int flock(int fid, int code)\r
+{\r
+    HANDLE hFile = (HANDLE) _get_osfhandle(fid);\r
+    OVERLAPPED ov;\r
+    ov.hEvent = NULL;\r
+    ov.Offset = 0;\r
+    ov.OffsetHigh = 0;\r
+    switch(code) {\r
+      case 1: LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1024, 0, &ov); break;   // LOCK_SH\r
+      case 2: LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1024, 0, &ov); break;   // LOCK_EX\r
+      case 3: UnlockFileEx(hFile, 0, 1024, 0, &ov); break; // LOCK_UN\r
+      default: return -1;\r
+    }\r
+    return 0;\r
+}\r