Refactor move type-in code
[xboard.git] / winboard / winboard.c
index 6f1d434..07e4bd2 100644 (file)
@@ -5,7 +5,7 @@
  * Massachusetts. \r
  *\r
  * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,\r
- * 2007, 2008, 2009 Free Software Foundation, Inc.\r
+ * 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.\r
  *\r
  * Enhancements Copyright 2005 Alessandro Scotti\r
  *\r
@@ -105,10 +105,9 @@ void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
 VOID NewVariantPopup(HWND hwnd);\r
 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,\r
                   /*char*/int promoChar));\r
-void AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames);\r
 void DisplayMove P((int moveNumber));\r
 Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen));\r
-void ChatPopUp P(());\r
+void ChatPopUp P((char *s));\r
 typedef struct {\r
   ChessSquare piece;  \r
   POINT pos;      /* window coordinates of current pos */\r
@@ -124,9 +123,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
@@ -134,6 +134,8 @@ 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
@@ -151,14 +153,15 @@ char szConsoleTitle[] = "I C S Interaction";
 \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
+Boolean chessProgram;\r
 //static int boardX, boardY;\r
 int  minX, minY; // [HGM] placement: volatile limits on upper-left corner\r
-static int squareSize, lineGap, minorSize;\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
@@ -174,24 +177,24 @@ char *icsNames;
 char *firstChessProgramNames;\r
 char *secondChessProgramNames;\r
 \r
-#define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */\r
-\r
 #define PALETTESIZE 256\r
 \r
 HINSTANCE hInst;          /* current instance */\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) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */\r
 static HBRUSH lightSquareBrush, darkSquareBrush,\r
   blackSquareBrush, /* [HGM] for band between board and holdings */\r
   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
@@ -206,11 +209,6 @@ static int lastSizing = 0;
 static int prevStderrPort;\r
 static HBITMAP userLogo;\r
 \r
-/* [AS] Support for background textures */\r
-#define BACK_TEXTURE_MODE_DISABLED      0\r
-#define BACK_TEXTURE_MODE_PLAIN         1\r
-#define BACK_TEXTURE_MODE_FULL_RANDOM   2\r
-\r
 static HBITMAP liteBackTexture = NULL;\r
 static HBITMAP darkBackTexture = NULL;\r
 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;\r
@@ -228,13 +226,264 @@ static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_RANKS][BOA
 #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_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
@@ -312,10 +561,10 @@ MyButtonDesc buttonDesc[N_BUTTONS] =
 };\r
 \r
 int tinyLayout = 0, smallLayout = 0;\r
-#define MENU_BAR_ITEMS 7\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
@@ -323,17 +572,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
@@ -404,7 +653,6 @@ 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
 \r
@@ -519,6 +767,7 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
   }\r
 \r
   JAWS_INIT\r
+  TranslateMenus(1);\r
 \r
 //  InitCommonControlsEx(&ex);\r
   InitCommonControls();\r
@@ -644,9 +893,11 @@ SetUserLogo()
     if(appData.autoLogo) {\r
          curName = UserName();\r
          if(strcmp(curName, oldUserName)) {\r
-               sprintf(oldUserName, "logos\\%s.bmp", curName);\r
+           snprintf(oldUserName, MSG_SIZ, "logos\\%s.bmp", curName);\r
                userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );    \r
-               strcpy(oldUserName, curName);\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
          }\r
     }\r
 }\r
@@ -712,6 +963,7 @@ 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
@@ -721,11 +973,24 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
   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");\r
     setbuf(debugFP, NULL);\r
   }\r
 \r
+  LoadLanguageFile(appData.language);\r
+\r
   InitBackEnd1();\r
 \r
 //  InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()\r
@@ -753,7 +1018,7 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
   } else if(appData.autoLogo) {\r
       if(appData.firstDirectory && appData.firstDirectory[0]) {\r
        char buf[MSG_SIZ];\r
-       sprintf(buf, "%s/logo.bmp", appData.firstDirectory);\r
+         snprintf(buf, MSG_SIZ, "%s/logo.bmp", appData.firstDirectory);\r
        first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );   \r
       }\r
   }\r
@@ -767,11 +1032,11 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
   } else if(appData.autoLogo) {\r
       char buf[MSG_SIZ];\r
       if(appData.icsActive) { // [HGM] logo: in ICS mode second can be used for ICS\r
-       sprintf(buf, "logos\\%s.bmp", appData.icsHost);\r
+       snprintf(buf, MSG_SIZ, "logos\\%s.bmp", appData.icsHost);\r
        second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );\r
       } else\r
       if(appData.secondDirectory && appData.secondDirectory[0]) {\r
-       sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);\r
+       snprintf(buf, MSG_SIZ, "%s\\logo.bmp", appData.secondDirectory);\r
        second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );  \r
       }\r
   }\r
@@ -836,8 +1101,6 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
       EngineOutputPopUp();\r
   }\r
 \r
-  InitBackEnd2();\r
-\r
   /* Make the window visible; update its client area; and return "success" */\r
   EnsureOnScreen(&wpMain.x, &wpMain.y, minX, minY);\r
   wp.length = sizeof(WINDOWPLACEMENT);\r
@@ -850,6 +1113,8 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
   wp.rcNormalPosition.bottom = wpMain.y + wpMain.height;\r
   SetWindowPlacement(hwndMain, &wp);\r
 \r
+  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
@@ -859,6 +1124,16 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
                  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
   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
@@ -867,584 +1142,81 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
 \r
 }\r
 \r
+VOID\r
+InitMenuChecks()\r
+{\r
+  HMENU hmenu = GetMenu(hwndMain);\r
 \r
-typedef enum {\r
-  ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone, \r
-  ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,\r
-  ArgSettingsFilename,\r
-  ArgX, ArgY, ArgZ // [HGM] placement: for window-placement options stored relative to main window\r
-} ArgType;\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 void *ArgIniType;\r
-#define INVALID (ArgIniType) 6915 /* Some number unlikely to be needed as default for anything */\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
-  ArgIniType defaultValue;\r
-} ArgDescriptor;\r
-\r
-int junk;\r
-\r
-ArgDescriptor argDescriptors[] = {\r
-  /* positional arguments */\r
-  { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE, INVALID },\r
-  { "", ArgNone, NULL, FALSE, INVALID },\r
-  /* keyword arguments */\r
-  JAWS_ARGS\r
-  { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE, INVALID },\r
-  { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE, INVALID },\r
-  { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE, INVALID },\r
-  { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE, INVALID },\r
-  { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE, INVALID },\r
-  { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE, INVALID },\r
-  { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE, INVALID },\r
-  { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE, INVALID },\r
-  { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE, INVALID },\r
-  { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE, INVALID },\r
-  { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE, INVALID },\r
-  { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE, INVALID },\r
-  { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE, (ArgIniType) MOVES_PER_SESSION },\r
-  { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE, INVALID },\r
-  { "initString", ArgString, (LPVOID) &appData.initString, FALSE, INVALID },\r
-  { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE, (ArgIniType) INIT_STRING },\r
-  { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE, (ArgIniType) INIT_STRING },\r
-  { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,\r
-    FALSE, (ArgIniType) COMPUTER_STRING },\r
-  { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,\r
-    FALSE, (ArgIniType) COMPUTER_STRING },\r
-  { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,\r
-    FALSE, (ArgIniType) FIRST_CHESS_PROGRAM },\r
-  { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE, INVALID },\r
-  { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,\r
-    FALSE, (ArgIniType) SECOND_CHESS_PROGRAM },\r
-  { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE, INVALID },\r
-  { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE, FALSE },\r
-  { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE, FALSE },\r
-  { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE, INVALID },\r
-  { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE, INVALID },\r
-  { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE, FALSE },\r
-  { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE, INVALID },\r
-  { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE, INVALID },\r
-  { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE, INVALID },\r
-  { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE, (ArgIniType) FIRST_HOST },\r
-  { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE, INVALID },\r
-  { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE, (ArgIniType) SECOND_HOST },\r
-  { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE, INVALID },\r
-  { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE, (ArgIniType) FIRST_DIRECTORY },\r
-  { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE, INVALID },\r
-  { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE, (ArgIniType) SECOND_DIRECTORY },\r
-  { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE, INVALID },\r
-  /*!!bitmapDirectory?*/\r
-  { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE, (ArgIniType) REMOTE_SHELL },\r
-  { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE, INVALID },\r
-  { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE, INVALID },\r
-  { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE, INVALID },\r
-  { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE, INVALID },\r
-  { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE, INVALID },\r
-  { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE, (ArgIniType) TIME_CONTROL },\r
-  { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE, INVALID },\r
-  { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE, (ArgIniType) TIME_INCREMENT },\r
-  { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE, INVALID },\r
-  { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE, INVALID },\r
-  { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE, (ArgIniType) FALSE },\r
-  { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE, INVALID },\r
-  { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE, INVALID },\r
-  { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE, (ArgIniType) "" },\r
-  { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE, INVALID },\r
-  { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE, (ArgIniType) ICS_PORT },\r
-  { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE, INVALID },\r
-  { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE, (ArgIniType) ICS_COMM_PORT },\r
-  { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE, INVALID },\r
-  { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE, INVALID },\r
-  { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE, INVALID },\r
-  { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE, (ArgIniType) ICS_LOGON },\r
-  { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE, INVALID },\r
-  { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE, INVALID },\r
-  { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE, INVALID },\r
-  { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE, INVALID },\r
-  { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE, INVALID },\r
-  { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE, (ArgIniType) TELNET_PROGRAM },\r
-  { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE, (ArgIniType) "" },\r
-  { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE, (ArgIniType) "" },\r
-  { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE, (ArgIniType) "" },\r
-  { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE, INVALID },\r
-  { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE, (ArgIniType) 0 },\r
-  { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE, INVALID },\r
-  { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE, (ArgIniType) "" },\r
-  { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE, INVALID },\r
-  { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE, (ArgIniType) FALSE },\r
-  { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE, INVALID },\r
-  { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE, INVALID },\r
-  { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE, INVALID },\r
-  { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE, (ArgIniType) "" },\r
-  { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE, INVALID },\r
-  { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE, (ArgIniType) 1 },\r
-  { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE, INVALID },\r
-  { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE, (ArgIniType) "" },\r
-  { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE, INVALID },\r
-  { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE, (ArgIniType) FALSE },\r
-  { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE, INVALID },\r
-  { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE, INVALID },\r
-  { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE, INVALID },\r
-  { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE, (ArgIniType) 0 },\r
-  { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE, INVALID },\r
-  { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE, (ArgIniType) FALSE },\r
-  { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE, INVALID },\r
-  { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE, INVALID },\r
-  { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE, INVALID },\r
-  { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE, (ArgIniType) FALSE },\r
-  { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE, INVALID },\r
-  { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE, INVALID },\r
-  { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE, INVALID },\r
-  { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE, (ArgIniType) TRUE },\r
-  { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE, INVALID },\r
-  { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE, INVALID },\r
-  { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE, INVALID },\r
-  { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE, (ArgIniType) "" },\r
-  { "st", ArgString, (LPVOID) &appData.searchTime, FALSE, INVALID },\r
-  { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE, (ArgIniType) 0 },\r
-  { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE, INVALID },\r
-  { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE, (ArgIniType) FALSE },\r
-  { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE, INVALID },\r
-  { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE, INVALID },\r
-  { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE, INVALID },\r
-  { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE, (ArgIniType) FALSE },\r
-  { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE, INVALID },\r
-  { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE, INVALID },\r
-  { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE, INVALID },\r
-  { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE, (ArgIniType) TRUE },\r
-  { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE, INVALID },\r
-  { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE, INVALID },\r
-  { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE, INVALID },\r
-  { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE, (ArgIniType) TRUE },\r
-  { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE, INVALID },\r
-  { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE, INVALID },\r
-  { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE, INVALID },\r
-  { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE, (ArgIniType) TRUE },\r
-  { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE, INVALID },\r
-  { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE, INVALID },\r
-  { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE, INVALID },\r
-  { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE, (ArgIniType) FALSE },\r
-  { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE, INVALID },\r
-  { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE, INVALID },\r
-  { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE, INVALID },\r
-  { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, \r
-    FALSE, INVALID }, /* only so that old WinBoard.ini files from betas can be read */\r
-  { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE, INVALID },\r
-  { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE, INVALID },\r
-  { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE, INVALID },\r
-  { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE, INVALID },\r
-  { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE, INVALID },\r
-  { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE, INVALID },\r
-  { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE, INVALID }, /* [AS] */\r
-  { "boardSize", ArgBoardSize, (LPVOID) &boardSize,\r
-    TRUE, (ArgIniType) -1 }, /* must come after all fonts */\r
-  { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE, INVALID },\r
-  { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,\r
-    FALSE, (ArgIniType) TRUE }, /* historical; kept only so old winboard.ini files will parse */\r
-  { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE, INVALID },\r
-  { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE, INVALID },\r
-  { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE, INVALID },\r
-  { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE, INVALID },\r
-  { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE, (ArgIniType) FALSE },\r
-  { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE, INVALID },\r
-  { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE, INVALID },\r
-  { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE, INVALID },\r
-  { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE, (ArgIniType) FALSE },\r
-  { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE, INVALID },\r
-  { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE, INVALID },\r
-  { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE, INVALID },\r
-  { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE, (ArgIniType) FALSE },\r
-  { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE, INVALID },\r
-  { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE, INVALID },\r
-  { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE, INVALID },\r
-  { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE, (ArgIniType) FALSE },\r
-  { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE, INVALID },\r
-  { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE, INVALID },\r
-  { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE, INVALID },\r
-  { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE, (ArgIniType) TRUE },\r
-  { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE, INVALID },\r
-  { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE, INVALID },\r
-  { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE, INVALID },\r
-  { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE, (ArgIniType) TRUE },\r
-  { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE, INVALID },\r
-  { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE, INVALID },\r
-  { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE, INVALID },\r
-  { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE, (ArgIniType) FALSE },\r
-  { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE, INVALID },\r
-  { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE, INVALID },\r
-  { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE, INVALID },\r
-  { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE, (ArgIniType) FALSE },\r
-  { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE, INVALID },\r
-  { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE, INVALID },\r
-  { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE, INVALID },\r
-  { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE, (ArgIniType) FALSE },\r
-  { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE, INVALID },\r
-  { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE, INVALID },\r
-  { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE, INVALID },\r
-  { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE, (ArgIniType) TRUE },\r
-  { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE, INVALID },\r
-  { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE, INVALID },\r
-  { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE, INVALID },\r
-  { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE, (ArgIniType) TRUE },\r
-  { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE, INVALID },\r
-  { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE, INVALID },\r
-  { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE, INVALID },\r
-  { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE, (ArgIniType) TRUE },\r
-  { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE, INVALID },\r
-  { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE, INVALID },\r
-  { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE, INVALID },\r
-  { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE, (ArgIniType) FALSE },\r
-  { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE, INVALID },\r
-  { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE, INVALID },\r
-  { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE, INVALID },\r
-  { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE, (ArgIniType) "" },\r
-  { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE, (ArgIniType) FALSE },\r
-  { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE, INVALID },\r
-  { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE, INVALID },\r
-  { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE, INVALID },\r
-  { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE, (ArgIniType) "" },\r
-  { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE, (ArgIniType) 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, (ArgIniType) 5000},\r
-  { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE, (ArgIniType) TRUE},\r
-  { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE, INVALID },\r
-  { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE, INVALID },\r
-  { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE, INVALID },\r
-  { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE, (ArgIniType) TRUE },\r
-  { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE, INVALID },\r
-  { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE, INVALID },\r
-  { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE, INVALID },\r
-  { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE, (ArgIniType) 10 },\r
-  { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE, (ArgIniType) TRUE },\r
-  { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE, INVALID },\r
-  { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE, INVALID },\r
-  { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE, INVALID },\r
-  { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE, (ArgIniType) FALSE },\r
-  { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE, INVALID },\r
-  { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE, INVALID },\r
-  { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE, INVALID },\r
-  { "highlightLastMove", ArgBoolean,\r
-    (LPVOID) &appData.highlightLastMove, TRUE, (ArgIniType) TRUE },\r
-  { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE, INVALID },\r
-  { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE, INVALID },\r
-  { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE, INVALID },\r
-  { "highlightDragging", ArgBoolean,\r
-    (LPVOID) &appData.highlightDragging, TRUE, INVALID },\r
-  { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE, INVALID },\r
-  { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE, INVALID },\r
-  { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE, INVALID },\r
-  { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE, (ArgIniType) TRUE },\r
-  { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE, INVALID },\r
-  { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE, INVALID },\r
-  { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE, INVALID },\r
-  { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE, INVALID },\r
-  { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE, INVALID },\r
-  { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE, INVALID },\r
-  { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE, INVALID },\r
-  { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE, INVALID },\r
-  { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE, INVALID },\r
-  { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE, INVALID },\r
-  { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE, INVALID },\r
-  { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE, INVALID },\r
-  { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE, INVALID },\r
-  { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE, INVALID },\r
-  { "soundShout", ArgFilename,\r
-    (LPVOID) &textAttribs[ColorShout].sound.name, TRUE, INVALID },\r
-  { "soundSShout", ArgFilename,\r
-    (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE, INVALID },\r
-  { "soundChannel1", ArgFilename,\r
-    (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE, INVALID },\r
-  { "soundChannel", ArgFilename,\r
-    (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE, INVALID },\r
-  { "soundKibitz", ArgFilename,\r
-    (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE, INVALID },\r
-  { "soundTell", ArgFilename,\r
-    (LPVOID) &textAttribs[ColorTell].sound.name, TRUE, INVALID },\r
-  { "soundChallenge", ArgFilename,\r
-    (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE, INVALID },\r
-  { "soundRequest", ArgFilename,\r
-    (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE, INVALID },\r
-  { "soundSeek", ArgFilename,\r
-    (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE, INVALID },\r
-  { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE, INVALID },\r
-  { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE, INVALID },\r
-  { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name, TRUE, INVALID },\r
-  { "soundIcsLoss", ArgFilename, \r
-    (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE, INVALID },\r
-  { "soundIcsDraw", ArgFilename, \r
-    (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE, INVALID },\r
-  { "soundIcsUnfinished", ArgFilename, \r
-    (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE, INVALID },\r
-  { "soundIcsAlarm", ArgFilename, \r
-    (LPVOID) &sounds[(int)SoundAlarm].name, TRUE, INVALID },\r
-  { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE, (ArgIniType) TRUE },\r
-  { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE, INVALID },\r
-  { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE, INVALID },\r
-  { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE, INVALID },\r
-  { "reuseChessPrograms", ArgBoolean,\r
-    (LPVOID) &appData.reuseFirst, FALSE, INVALID }, /* backward compat only */\r
-  { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE, (ArgIniType) TRUE },\r
-  { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE, INVALID },\r
-  { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE, INVALID },\r
-  { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE, INVALID },\r
-  { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE, INVALID },\r
-  { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE, (ArgIniType) SETTINGS_FILE },\r
-  { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE, INVALID },\r
-  { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE, (ArgIniType) TRUE },\r
-  { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE, (ArgIniType) FALSE },\r
-  { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE, INVALID },\r
-  { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE, INVALID },\r
-  { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE, INVALID },\r
-  { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE, (ArgIniType) ICS_TEXT_MENU_DEFAULT },\r
-  { "icsNames", ArgString, (LPVOID) &icsNames, TRUE, (ArgIniType) ICS_NAMES },\r
-  { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,\r
-    TRUE, (ArgIniType) FCP_NAMES },\r
-  { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,\r
-    TRUE, (ArgIniType) SCP_NAMES },\r
-  { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE, (ArgIniType) "" },\r
-  { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE, INVALID },\r
-  { "variant", ArgString, (LPVOID) &appData.variant, FALSE, (ArgIniType) "normal" },\r
-  { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE, (ArgIniType) PROTOVER },\r
-  { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE, (ArgIniType) PROTOVER },\r
-  { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE, (ArgIniType) TRUE },\r
-  { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE, INVALID },\r
-  { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE, INVALID },\r
-  { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE, INVALID },\r
-\r
-  /* [AS] New features */\r
-  { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE, (ArgIniType) FALSE },\r
-  { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE, (ArgIniType) FALSE },\r
-  { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE, (ArgIniType) FALSE },\r
-  { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE, (ArgIniType) FALSE },\r
-  { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE, (ArgIniType) "" },\r
-  { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE, (ArgIniType) "" },\r
-  { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE, (ArgIniType) BACK_TEXTURE_MODE_PLAIN },\r
-  { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE, (ArgIniType) BACK_TEXTURE_MODE_PLAIN },\r
-  { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE, (ArgIniType) "" },\r
-  { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE, (ArgIniType) "" },\r
-  { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE, (ArgIniType) 0 },\r
-  { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE, (ArgIniType) 0 },\r
-  { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE, (ArgIniType) 0 },\r
-  { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE, (ArgIniType) 0 },\r
-  { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE, (ArgIniType) 80 },\r
-  { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE, (ArgIniType) 1 },\r
-  { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE, (ArgIniType) 0 },\r
-  { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE, (ArgIniType) 0 },\r
-  { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE, (ArgIniType) 0 },\r
-  { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE, (ArgIniType) "winboard.debug" },\r
-  { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE, INVALID },\r
-  { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE, (ArgIniType) "Computer Chess Game" },\r
-  { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE, (ArgIniType) -1 },\r
-  { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE, (ArgIniType) GLT_DEFAULT_TAGS },\r
-  { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE, (ArgIniType) TRUE },\r
-  { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE, (ArgIniType) TRUE },\r
-  { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE, INVALID },\r
-  { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE, INVALID },\r
-  { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE, (ArgIniType) FALSE },\r
-  { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE, INVALID },\r
-  { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE, (ArgIniType) TRUE },\r
-  { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE, (ArgIniType) TRUE },\r
-  { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE, (ArgIniType) TRUE },\r
-  { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE, (ArgIniType) TRUE },\r
-  { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE, (ArgIniType) FALSE },\r
-  { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE, INVALID },\r
-  { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE, (ArgIniType) FALSE },\r
-  { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE, INVALID },\r
-  { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE, (ArgIniType) TRUE },\r
-  { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE, INVALID },\r
-  { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE, INVALID },\r
-  { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE, (ArgIniType) TRUE },\r
-  { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE, INVALID },\r
-  { "secondXBook", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE, INVALID },\r
-  { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE, (ArgIniType) "" },\r
-  { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE, (ArgIniType) FALSE },\r
-  { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE, (ArgIniType) "" },\r
-  { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE, (ArgIniType) 64 }, \r
-  { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE, (ArgIniType) 4 },\r
-  { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE, (ArgIniType) "c:\\egtb" },\r
-\r
-  /* [HGM] board-size, adjudication and misc. options */\r
-  { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE, (ArgIniType) -1 },\r
-  { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE, (ArgIniType) -1 },\r
-  { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE, (ArgIniType) -1 },\r
-  { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE, (ArgIniType) 10000 },\r
-  { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE, INVALID },\r
-  { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE, (ArgIniType) FALSE },\r
-  { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE, (ArgIniType) FALSE },\r
-  { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE, (ArgIniType) FALSE },\r
-  { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE, (ArgIniType) FALSE },\r
-  { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE, (ArgIniType) FALSE },\r
-  { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE, (ArgIniType) FALSE },\r
-  { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE, (ArgIniType) FALSE },\r
-  { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE, (ArgIniType) FALSE },\r
-  { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE, (ArgIniType) FALSE },\r
-  { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE, (ArgIniType) 51 },\r
-  { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE, (ArgIniType) 6 },\r
-  { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE, INVALID },\r
-  { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE, (ArgIniType) 1 },\r
-  { "userName", ArgString, (LPVOID) &appData.userName, FALSE, INVALID },\r
-  { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE, INVALID },\r
-  { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE, INVALID },\r
-  { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE, (ArgIniType) 1 },\r
-  { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE, (ArgIniType) "" },\r
-  { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE, INVALID },\r
-  { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE, INVALID },\r
-  { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE, INVALID },\r
-  { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE, INVALID },\r
-  { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE, (ArgIniType) "" },\r
-  { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE, (ArgIniType) "" },\r
-  { "firstNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride1, FALSE, (ArgIniType) "" },\r
-  { "secondNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride2, FALSE, (ArgIniType) "" },\r
-  { "keepAlive", ArgInt, (LPVOID) &appData.keepAlive, FALSE, INVALID },\r
-  { "icstype", ArgInt, (LPVOID) &ics_type, FALSE, INVALID },\r
-  { "forceIllegalMoves", ArgTrue, (LPVOID) &appData.forceIllegal, FALSE, INVALID },\r
-\r
-#ifdef ZIPPY\r
-  { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE, (ArgIniType) ZIPPY_TALK },\r
-  { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE, INVALID },\r
-  { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE, INVALID },\r
-  { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE, INVALID },\r
-  { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE, (ArgIniType) ZIPPY_PLAY },\r
-  { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE, INVALID },\r
-  { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE, INVALID },\r
-  { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE, INVALID },\r
-  { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE, (ArgIniType) ZIPPY_LINES },\r
-  { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE, (ArgIniType) ZIPPY_PINHEAD },\r
-  { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE, (ArgIniType) ZIPPY_PASSWORD },\r
-  { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE, (ArgIniType) ZIPPY_PASSWORD2 },\r
-  { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,\r
-    FALSE, (ArgIniType) ZIPPY_WRONG_PASSWORD },\r
-  { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE, (ArgIniType) ZIPPY_ACCEPT_ONLY },\r
-  { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE, (ArgIniType) ZIPPY_USE_I },\r
-  { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE, INVALID },\r
-  { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE, INVALID },\r
-  { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE, INVALID },\r
-  { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE, (ArgIniType) ZIPPY_BUGHOUSE },\r
-  { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,\r
-    FALSE, (ArgIniType) ZIPPY_NOPLAY_CRAFTY },\r
-  { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE, INVALID },\r
-  { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE, INVALID },\r
-  { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE, INVALID },\r
-  { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE, (ArgIniType) ZIPPY_GAME_END },\r
-  { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE, (ArgIniType) ZIPPY_GAME_START },\r
-  { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE, (ArgIniType) ZIPPY_ADJOURN },\r
-  { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE, INVALID },\r
-  { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE, INVALID },\r
-  { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE, INVALID },\r
-  { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE, (ArgIniType) ZIPPY_ABORT },\r
-  { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE, INVALID },\r
-  { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE, INVALID },\r
-  { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE, INVALID },\r
-  { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE, (ArgIniType) ZIPPY_VARIANTS },\r
-  { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE, (ArgIniType) ZIPPY_MAX_GAMES},\r
-  { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE, (ArgIniType) ZIPPY_REPLAY_TIMEOUT },\r
-  { "zippyShortGame", ArgInt, (LPVOID)&appData.zippyShortGame, FALSE, INVALID },\r
-  /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */\r
-  { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE, INVALID },\r
-#endif\r
-  /* [HGM] options for broadcasting and time odds */\r
-  { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE, (ArgIniType) NULL },\r
-  { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE, (ArgIniType) FALSE },\r
-  { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE, (ArgIniType) 15 },\r
-  { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE, (ArgIniType) 1 },\r
-  { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE, (ArgIniType) 1 },\r
-  { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE, INVALID },\r
-  { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE, (ArgIniType) 1 },\r
-  { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE, (ArgIniType) 1 },\r
-  { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE, (ArgIniType) -1 },\r
-  { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE, (ArgIniType) -1 },\r
-  { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE, INVALID },\r
-  { "keepLineBreaksICS", ArgBoolean, (LPVOID) &appData.noJoin, TRUE, INVALID },\r
-  { "wrapContinuationSequence", ArgString, (LPVOID) &appData.wrapContSeq, FALSE, INVALID },\r
-  { "useInternalWrap", ArgTrue, (LPVOID) &appData.useInternalWrap, FALSE, INVALID }, /* noJoin usurps this if set */\r
-  \r
-  // [HGM] placement: put all window layouts last in ini file, but man X,Y before all others\r
-  { "minX", ArgZ, (LPVOID) &minX, FALSE, INVALID }, // [HGM] placement: to make suer auxialary windows can be placed\r
-  { "minY", ArgZ, (LPVOID) &minY, FALSE, INVALID },\r
-  { "winWidth",  ArgInt, (LPVOID) &wpMain.width,  TRUE, INVALID }, // [HGM] placement: dummies to remember right & bottom\r
-  { "winHeight", ArgInt, (LPVOID) &wpMain.height, TRUE, INVALID }, //       for attaching auxiliary windows to them\r
-  { "x", ArgInt, (LPVOID) &wpMain.x, TRUE, (ArgIniType) CW_USEDEFAULT },\r
-  { "y", ArgInt, (LPVOID) &wpMain.y, TRUE, (ArgIniType) CW_USEDEFAULT },\r
-  { "icsX", ArgX,   (LPVOID) &wpConsole.x, TRUE, (ArgIniType) CW_USEDEFAULT },\r
-  { "icsY", ArgY,   (LPVOID) &wpConsole.y, TRUE, (ArgIniType) CW_USEDEFAULT },\r
-  { "icsW", ArgInt, (LPVOID) &wpConsole.width, TRUE, (ArgIniType) CW_USEDEFAULT },\r
-  { "icsH", ArgInt, (LPVOID) &wpConsole.height, TRUE, (ArgIniType) CW_USEDEFAULT },\r
-  { "analysisX", ArgX,   (LPVOID) &dummy, FALSE, INVALID }, // [HGM] placement: analysis window no longer exists\r
-  { "analysisY", ArgY,   (LPVOID) &dummy, FALSE, INVALID }, //       provided for compatibility with old ini files\r
-  { "analysisW", ArgInt, (LPVOID) &dummy, FALSE, INVALID },\r
-  { "analysisH", ArgInt, (LPVOID) &dummy, FALSE, INVALID },\r
-  { "commentX", ArgX,   (LPVOID) &wpComment.x, TRUE, (ArgIniType) CW_USEDEFAULT },\r
-  { "commentY", ArgY,   (LPVOID) &wpComment.y, TRUE, (ArgIniType) CW_USEDEFAULT },\r
-  { "commentW", ArgInt, (LPVOID) &wpComment.width, TRUE, (ArgIniType) CW_USEDEFAULT },\r
-  { "commentH", ArgInt, (LPVOID) &wpComment.height, TRUE, (ArgIniType) CW_USEDEFAULT },\r
-  { "tagsX", ArgX,   (LPVOID) &wpTags.x, TRUE, (ArgIniType) CW_USEDEFAULT },\r
-  { "tagsY", ArgY,   (LPVOID) &wpTags.y, TRUE, (ArgIniType) CW_USEDEFAULT },\r
-  { "tagsW", ArgInt, (LPVOID) &wpTags.width, TRUE, (ArgIniType) CW_USEDEFAULT },\r
-  { "tagsH", ArgInt, (LPVOID) &wpTags.height, TRUE, (ArgIniType) CW_USEDEFAULT },\r
-  { "gameListX", ArgX,   (LPVOID) &wpGameList.x, TRUE, (ArgIniType) CW_USEDEFAULT },\r
-  { "gameListY", ArgY,   (LPVOID) &wpGameList.y, TRUE, (ArgIniType) CW_USEDEFAULT },\r
-  { "gameListW", ArgInt, (LPVOID) &wpGameList.width, TRUE, (ArgIniType) CW_USEDEFAULT },\r
-  { "gameListH", ArgInt, (LPVOID) &wpGameList.height, TRUE, (ArgIniType) CW_USEDEFAULT },\r
-  /* [AS] Layout stuff */\r
-  { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE, (ArgIniType) TRUE },\r
-  { "moveHistoryX", ArgX,   (LPVOID) &wpMoveHistory.x, TRUE, (ArgIniType) CW_USEDEFAULT },\r
-  { "moveHistoryY", ArgY,   (LPVOID) &wpMoveHistory.y, TRUE, (ArgIniType) CW_USEDEFAULT },\r
-  { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE, (ArgIniType) CW_USEDEFAULT },\r
-  { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE, (ArgIniType) CW_USEDEFAULT },\r
-\r
-  { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE, (ArgIniType) TRUE },\r
-  { "evalGraphX", ArgX,   (LPVOID) &wpEvalGraph.x, TRUE, (ArgIniType) CW_USEDEFAULT },\r
-  { "evalGraphY", ArgY,   (LPVOID) &wpEvalGraph.y, TRUE, (ArgIniType) CW_USEDEFAULT },\r
-  { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE, (ArgIniType) CW_USEDEFAULT },\r
-  { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE, (ArgIniType) CW_USEDEFAULT },\r
-\r
-  { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE, (ArgIniType) TRUE },\r
-  { "engineOutputX", ArgX,   (LPVOID) &wpEngineOutput.x, TRUE, (ArgIniType) CW_USEDEFAULT },\r
-  { "engineOutputY", ArgY,   (LPVOID) &wpEngineOutput.y, TRUE, (ArgIniType) CW_USEDEFAULT },\r
-  { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE, (ArgIniType) CW_USEDEFAULT },\r
-  { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE, (ArgIniType) CW_USEDEFAULT },\r
-\r
-  { NULL, ArgNone, NULL, FALSE, INVALID }\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
@@ -1459,7 +1231,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);\r
     memcpy(mfp->faceName, p, q - p);\r
     mfp->faceName[q - p] = NULLCHAR;\r
     p = q + 1;\r
@@ -1468,12 +1240,12 @@ 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);\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);\r
   mfp->pointSize = (float) atof(p);\r
   mfp->bold = (strchr(p, 'b') != NULL);\r
   mfp->italic = (strchr(p, 'i') != NULL);\r
@@ -1485,6 +1257,36 @@ ParseFontName(char *name, MyFontParams *mfp)
     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
@@ -1500,15 +1302,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
@@ -1525,466 +1333,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 == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely\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
-  int ok; char buf[MSG_SIZ];\r
-\r
-  ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);\r
-  if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed\r
-    sprintf(buf, "%s.ini", name);\r
-    ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);\r
-  }\r
-  if (ok) {\r
-    f = fopen(fullname, "r");\r
-    if (f != NULL) {\r
-      ParseArgs(FileGet, f);\r
-      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 ArgX:\r
-      *(int *) ad->argLoc = atoi(argValue) + wpMain.x; // [HGM] placement: translate stored relative to absolute \r
-      break;\r
-\r
-    case ArgY:\r
-      *(int *) ad->argLoc = atoi(argValue) + wpMain.y; // (this is really kludgey, it should be done where used...)\r
-      break;\r
-\r
-    case ArgZ:\r
-      *(int *) ad->argLoc = atoi(argValue);\r
-      EnsureOnScreen(&wpMain.x, &wpMain.y, minX, minY); \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
-    case ArgTrue:\r
-    case ArgFalse: ;\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 = 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
-  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);\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
-SetDefaultsFromList()\r
-{ // [HGM] ini: take defaults from argDescriptor list\r
-  int i;\r
-\r
-  for(i=0; argDescriptors[i].argName != NULL; i++) {\r
-    if(argDescriptors[i].defaultValue != INVALID)\r
-      switch(argDescriptors[i].argType) {\r
-        case ArgBoolean:\r
-        case ArgTrue:\r
-        case ArgFalse:\r
-          *(Boolean *) argDescriptors[i].argLoc = (int)argDescriptors[i].defaultValue;\r
-          break;\r
-        case ArgInt:\r
-        case ArgX:\r
-        case ArgY:\r
-        case ArgZ:\r
-          *(int *) argDescriptors[i].argLoc = (int)argDescriptors[i].defaultValue;\r
-          break;\r
-        case ArgString:\r
-        case ArgFilename:\r
-        case ArgSettingsFilename:\r
-          *(char **) argDescriptors[i].argLoc = (char *)argDescriptors[i].defaultValue;\r
-          break;\r
-        case ArgBoardSize:\r
-          *(BoardSize *) argDescriptors[i].argLoc = (BoardSize)argDescriptors[i].defaultValue;\r
-          break;\r
-        case ArgFloat: // floats cannot be casted to int without precision loss\r
-        default: ; // some arg types cannot be initialized through table\r
-    }\r
-  }\r
-}\r
-\r
-VOID\r
-InitAppData(LPSTR lpCmdLine)\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
-  SetDefaultsFromList(); // this sets most defaults\r
-\r
-  // some parameters for which there are no options!\r
-  appData.Iconic = FALSE; /*unused*/\r
-  appData.cmailGameName = "";\r
-  appData.icsEngineAnalyze = FALSE;\r
-\r
-  // float: casting to int is not harmless, so default cannot be contained in table\r
-  appData.timeDelay = TIME_DELAY;\r
-\r
-  // colors have platform-dependent option format and internal representation\r
-  // their setting and parsing must remain in front-end\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
-  // the following must be moved out of appData to front-end variables\r
-  appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );\r
-  appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );\r
-  appData.highlightArrowColor = ParseColorName( "#FFFF80" );\r
-\r
-  // some complex, platform-dependent stuff\r
-  SetDefaultTextAttribs();\r
-  SetDefaultSounds();\r
-\r
-  memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +\r
+   memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +\r
   dcb.DCBlength = sizeof(DCB);\r
   dcb.BaudRate = 9600;\r
   dcb.fBinary = TRUE;\r
@@ -2002,134 +1396,6 @@ InitAppData(LPSTR lpCmdLine)
   dcb.ByteSize = 7;\r
   dcb.Parity = SPACEPARITY;\r
   dcb.StopBits = ONESTOPBIT;\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
-    }\r
-  }\r
-  \r
-  /* Parse default settings file if any */\r
-  if (ParseSettingsFile(settingsFileName, buf)) {\r
-    settingsFileName = strdup(buf);\r
-  }\r
-\r
-  /* Parse command line */\r
-  ParseArgs(StringGet, &lpCmdLine);\r
-\r
-  /* [HGM] make sure board size is acceptable */\r
-  if(appData.NrFiles > BOARD_FILES ||\r
-     appData.NrRanks > BOARD_RANKS   )\r
-      DisplayFatalError("Recompile with BOARD_RANKS or BOARD_FILES, to support this size", 0, 2);\r
-\r
-  /* [HGM] After parsing the options from the .ini file, and overruling them\r
-   * with options from the command line, we now make an even higher priority\r
-   * overrule by WB options attached to the engine command line. This so that\r
-   * tournament managers can use WB options (such as /timeOdds) that follow\r
-   * the engines.\r
-   */\r
-  if(appData.firstChessProgram != NULL) {\r
-      char *p = StrStr(appData.firstChessProgram, "WBopt");\r
-      static char *f = "first";\r
-      char buf[MSG_SIZ], *q = buf;\r
-      if(p != NULL) { // engine command line contains WinBoard options\r
-          sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"\r
-          ParseArgs(StringGet, &q);\r
-          p[-1] = 0; // cut them offengine command line\r
-      }\r
-  }\r
-  // now do same for second chess program\r
-  if(appData.secondChessProgram != NULL) {\r
-      char *p = StrStr(appData.secondChessProgram, "WBopt");\r
-      static char *s = "second";\r
-      char buf[MSG_SIZ], *q = buf;\r
-      if(p != NULL) { // engine command line contains WinBoard options\r
-          sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"\r
-          ParseArgs(StringGet, &q);\r
-          p[-1] = 0; // cut them offengine command line\r
-      }\r
-  }\r
-\r
-\r
-  /* Propagate options that affect others */\r
-  if (appData.matchMode || appData.matchGames) chessProgram = TRUE;\r
-  if (appData.icsActive || appData.noChessProgram) {\r
-     chessProgram = FALSE;  /* not local chess program mode */\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
-    FARPROC lpProc;\r
-    \r
-    lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);\r
-    DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);\r
-    FreeProcInstance(lpProc);\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
-  /* 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
-    }\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
-\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
-    }\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
-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
 // [HGM] args: these three cases taken out to stay in front-end\r
@@ -2154,6 +1420,17 @@ SaveFontArg(FILE *f, ArgDescriptor *ad)
       }\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
@@ -2169,141 +1446,84 @@ SaveAttribsArg(FILE *f, ArgDescriptor *ad)
 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 *)ad->argLoc;\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
-int\r
-MainWindowUp()\r
-{ // [HGM] args: allows testing if main window is realized from back-end\r
-  return hwndMain != NULL;\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
-SaveSettings(char* name)\r
-{\r
-  FILE *f;\r
-  ArgDescriptor *ad;\r
-  char dir[MSG_SIZ];\r
-\r
-  if (!MainWindowUp()) return;\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 Save Settings file\n", PACKAGE_STRING);\r
-  fprintf(f, ";\n");\r
-  fprintf(f, "; You can edit the values of options that are already set in this file,\n");\r
-  fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");\r
-  fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");\r
-  fprintf(f, ";\n");\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
-\r
-  /* [AS] Move history */\r
-  wpMoveHistory.visible = MoveHistoryIsUp();\r
   GetActualPlacement(moveHistoryDialog, &wpMoveHistory);\r
-\r
-  /* [AS] Eval graph */\r
-  wpEvalGraph.visible = EvalGraphIsUp();\r
   GetActualPlacement(evalGraphDialog, &wpEvalGraph);\r
-\r
-  /* [AS] Engine output */\r
-  wpEngineOutput.visible = EngineOutputIsUp();\r
   GetActualPlacement(engineOutputDialog, &wpEngineOutput);\r
+}\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
-    case ArgZ:\r
-      fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);\r
-      break;\r
-    case ArgX:\r
-      fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - wpMain.x); // [HGM] placement: stor relative value\r
-      break;\r
-    case ArgY:\r
-      fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - wpMain.y);\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
-      SaveColor(f, ad);\r
-      break;\r
-    case ArgAttribs:\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
-      SaveFontArg(f, ad);\r
-      break;\r
-    case ArgCommSettings:\r
-      PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);\r
-    case ArgNone:\r
-    case ArgSettingsFilename: ;\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
-  fclose(f);\r
+  return (int) SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);\r
 }\r
 \r
+int\r
+MyGetFullPathName(char *name, char *fullname)\r
+{\r
+  char *dummy;\r
+  return (int) GetFullPathName(name, MSG_SIZ, fullname, &dummy);\r
+}\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
+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
  *\r
@@ -2854,11 +2074,11 @@ DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
 {\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
@@ -2875,7 +2095,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
@@ -2922,6 +2142,7 @@ InitDrawingColors()
   blackPieceBrush = CreateSolidBrush(blackPieceColor);\r
   iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));\r
   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
@@ -2963,6 +2184,7 @@ 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
@@ -3002,7 +2224,7 @@ InitDrawingSizes(BoardSize boardSize, int flags)
   }\r
 \r
   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
@@ -3011,11 +2233,11 @@ 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
@@ -3026,14 +2248,14 @@ InitDrawingSizes(BoardSize boardSize, int flags)
   /* 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
@@ -3072,6 +2294,8 @@ InitDrawingSizes(BoardSize boardSize, int flags)
     blackRect.right = blackRect.left + boardWidth/2 - 1;\r
     blackRect.top = whiteRect.top;\r
     blackRect.bottom = whiteRect.bottom;\r
+\r
+    logoHeight = 0; // [HGM] logo: suppress logo after change to tiny layout!\r
   }\r
 \r
   messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;\r
@@ -3096,6 +2320,7 @@ InitDrawingSizes(BoardSize boardSize, int flags)
   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
@@ -3157,7 +2382,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
@@ -3166,7 +2391,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
@@ -3247,7 +2472,7 @@ InitDrawingSizes(BoardSize boardSize, int flags)
   pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");\r
   pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");\r
   pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");\r
-  if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {\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
@@ -3274,14 +2499,24 @@ InitDrawingSizes(BoardSize boardSize, int flags)
       pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");\r
       pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");\r
     } else { // Smirf-like\r
-      pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");\r
-      pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");\r
-      pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");\r
+      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
@@ -3542,23 +2777,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
@@ -3575,7 +2801,7 @@ DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y,
   if (appData.blindfold) return;\r
 \r
   /* [AS] Use font-based pieces if needed */\r
-  if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {\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
@@ -3584,6 +2810,9 @@ DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y,
 \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
@@ -3593,6 +2822,9 @@ DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y,
 \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
@@ -3702,7 +2934,13 @@ VOID RebuildTextureSquareInfo()
             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
@@ -3710,7 +2948,13 @@ VOID RebuildTextureSquareInfo()
             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
@@ -3721,7 +2965,7 @@ VOID RebuildTextureSquareInfo()
 \r
 /* [AS] Arrow highlighting support */\r
 \r
-static int A_WIDTH = 5; /* Width of arrow body */\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
@@ -3745,50 +2989,50 @@ VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
     if( d_x == s_x ) {\r
         int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;\r
 \r
-        arrow[0].x = s_x + A_WIDTH;\r
+        arrow[0].x = s_x + A_WIDTH + 0.5;\r
         arrow[0].y = s_y;\r
 \r
-        arrow[1].x = s_x + A_WIDTH;\r
+        arrow[1].x = s_x + A_WIDTH + 0.5;\r
         arrow[1].y = d_y - h;\r
 \r
-        arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;\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[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;\r
-        arrow[4].y = d_y - h;\r
-\r
-        arrow[5].x = s_x - A_WIDTH;\r
+        arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;\r
         arrow[5].y = d_y - h;\r
 \r
-        arrow[6].x = s_x - A_WIDTH;\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;\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;\r
+        arrow[1].y = s_y + A_WIDTH + 0.5;\r
 \r
         arrow[2].x = d_x - w;\r
-        arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;\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[4].x = d_x - w;\r
-        arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;\r
-\r
         arrow[5].x = d_x - w;\r
-        arrow[5].y = s_y - A_WIDTH;\r
+        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 = s_y - A_WIDTH;\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
@@ -3805,8 +3049,8 @@ VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
         arrow[0].x = Round(x - j);\r
         arrow[0].y = Round(y + j*dx);\r
 \r
-        arrow[1].x = Round(x + j);\r
-        arrow[1].y = Round(y - j*dx);\r
+        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
@@ -3817,20 +3061,22 @@ VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
             y = (double) d_y + k*dy;\r
         }\r
 \r
-        arrow[2].x = Round(x + j);\r
-        arrow[2].y = Round(y - j*dx);\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(x + j*A_WIDTH_FACTOR);\r
-        arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);\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(x - j*A_WIDTH_FACTOR);\r
-        arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);\r
-\r
-        arrow[6].x = Round(x - j);\r
-        arrow[6].y = Round(y + j*dx);\r
+        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
@@ -3855,20 +3101,20 @@ VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_ro
     SquareToPos( d_row, d_col, &d_x, &d_y);\r
 \r
     if( d_y > s_y ) {\r
-        d_y += squareSize / 4;\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 += 3 * squareSize / 4;\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 / 4;\r
+        d_x += squareSize / 2 - squareSize / 4;\r
     }\r
     else if( d_x < s_x ) {\r
-        d_x += 3 * squareSize / 4;\r
+        d_x += squareSize / 2 + squareSize / 4;\r
     }\r
     else {\r
         d_x += squareSize / 2;\r
@@ -3878,7 +3124,7 @@ VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_ro
     s_y += squareSize / 2;\r
 \r
     /* Adjust width */\r
-    A_WIDTH = squareSize / 14;\r
+    A_WIDTH = squareSize / 14.; //[HGM] make float\r
 \r
     /* Draw */\r
     stLB.lbStyle = BS_SOLID;\r
@@ -4150,12 +3396,110 @@ DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
 }\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
+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
@@ -4164,6 +3508,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
@@ -4175,18 +3520,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
@@ -4225,23 +3572,24 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
             if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )\r
         board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;\r
     } else \r
-        board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;\r
+        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
+  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[row][column] != board[row][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
@@ -4282,6 +3630,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
@@ -4341,7 +3713,7 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
         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. [HGM] moved until after setting lastDrawn */\r
-      lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;\r
+      lastDrawn[0][animInfo.to.y][animInfo.to.x] = animInfo.piece;\r
     }\r
   }\r
 \r
@@ -4362,6 +3734,7 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
   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
@@ -4371,50 +3744,36 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
          ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);\r
        }\r
        DrawGridOnDC(hdcmem);\r
-       DrawHighlightsOnDC(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
-    DrawHighlightsOnDC(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(logoHeight) {\r
-       HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;\r
-       if(appData.autoLogo) {\r
-         \r
-         switch(gameMode) { // pick logos based on game mode\r
-           case IcsObserving:\r
-               whiteLogo = second.programLogo; // ICS logo\r
-               blackLogo = second.programLogo;\r
-           default:\r
-               break;\r
-           case IcsPlayingWhite:\r
-               if(!appData.zippyPlay) whiteLogo = userLogo;\r
-               blackLogo = second.programLogo; // ICS logo\r
-               break;\r
-           case IcsPlayingBlack:\r
-               whiteLogo = second.programLogo; // ICS logo\r
-               blackLogo = appData.zippyPlay ? first.programLogo : userLogo;\r
-               break;\r
-           case TwoMachinesPlay:\r
-               if(first.twoMachinesColor[0] == 'b') {\r
-                   whiteLogo = second.programLogo;\r
-                   blackLogo = first.programLogo;\r
-               }\r
-               break;\r
-           case MachinePlaysWhite:\r
-               blackLogo = userLogo;\r
-               break;\r
-           case MachinePlaysBlack:\r
-               whiteLogo = userLogo;\r
-               blackLogo = first.programLogo;\r
-         }\r
+  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
-       DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);\r
-       DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);\r
+    }\r
   }\r
 \r
   if( appData.highlightMoveWithArrow ) {\r
@@ -4423,7 +3782,7 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
 \r
   DrawCoordsOnDC(hdcmem);\r
 \r
-  CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */\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
@@ -4437,8 +3796,8 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
     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
@@ -4460,6 +3819,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
@@ -4471,7 +3837,7 @@ 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
@@ -4559,7 +3925,7 @@ 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
@@ -4570,7 +3936,7 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
   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
@@ -4611,6 +3977,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
@@ -4618,6 +3989,7 @@ PaintProc(HWND hwnd)
                 &messageRect, messageText, strlen(messageText), NULL);\r
       SelectObject(hdc, oldFont);\r
       DisplayBothClocks();\r
+      DisplayLogos();\r
     }\r
     EndPaint(hwnd,&ps);\r
   }\r
@@ -4655,11 +4027,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
@@ -4675,7 +4047,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
@@ -4691,6 +4063,7 @@ void DragPieceBegin(int x, int y)
       dragInfo.lastpos.y = boardRect.top + y;\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
@@ -4703,11 +4076,16 @@ void DragPieceEnd(int x, int y)
     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
@@ -4736,26 +4114,14 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     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
       if (PtInRect((LPRECT) &whiteRect, pt)) {\r
-        if (gameMode == EditPosition) {\r
-         SetWhiteToPlayEvent();\r
-       } else if (gameMode == IcsPlayingBlack ||\r
-                  gameMode == MachinePlaysWhite) {\r
-         CallFlagEvent();\r
-        } else if (gameMode == EditGame) {\r
-          AdjustClock(flipClock, -1);\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
-        } else if (gameMode == EditGame) {\r
-          AdjustClock(!flipClock, -1);\r
-       }\r
+       ClockClick(!flipClock);\r
       }\r
       dragInfo.start.x = dragInfo.start.y = -1;\r
       dragInfo.from = dragInfo.start;\r
@@ -4774,6 +4140,9 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     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
@@ -4801,16 +4170,22 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
        /* Mouse Wheel is being rolled forward\r
         * Play moves forward\r
         */\r
-       if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove) \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((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
@@ -4826,19 +4201,17 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     if(y == -2) {\r
       /* [HGM] right mouse button in clock area edit-game mode ups clock */\r
       if (PtInRect((LPRECT) &whiteRect, pt)) {\r
-          if (gameMode == EditGame) AdjustClock(flipClock, 1);\r
+          if (gameMode == EditGame || GetKeyState(VK_SHIFT) < 0) AdjustClock(flipClock, 1);\r
       } else if (PtInRect((LPRECT) &blackRect, pt)) {\r
-          if (gameMode == EditGame) AdjustClock(!flipClock, 1);\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
@@ -4855,21 +4228,13 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
             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
@@ -4883,7 +4248,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
@@ -4914,7 +4279,7 @@ ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
        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
@@ -4933,21 +4298,23 @@ 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 == 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' &&\r
+       ((PieceToChar(WhiteAngel) >= 'A' && WhiteOnMove(currentMove) &&\r
          PieceToChar(WhiteAngel) != '~') ||\r
-        (PieceToChar(BlackAngel) >= 'A' &&\r
+        (PieceToChar(BlackAngel) >= 'A' && !WhiteOnMove(currentMove) &&\r
          PieceToChar(BlackAngel) != '~')   ) ?\r
               SW_SHOW : SW_HIDE);\r
     ShowWindow(GetDlgItem(hDlg, PB_Chancellor), \r
-       ((PieceToChar(WhiteMarshall) >= 'A' &&\r
+       ((PieceToChar(WhiteMarshall) >= 'A' && WhiteOnMove(currentMove) &&\r
          PieceToChar(WhiteMarshall) != '~') ||\r
-        (PieceToChar(BlackMarshall) >= 'A' &&\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
@@ -4957,12 +4324,11 @@ Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
     ShowWindow(GetDlgItem(hDlg, PB_Bishop), \r
        gameInfo.variant != VariantShogi ?\r
               SW_SHOW : SW_HIDE);\r
-    ShowWindow(GetDlgItem(hDlg, IDC_Yes), \r
-       gameInfo.variant == VariantShogi ?\r
-              SW_SHOW : SW_HIDE);\r
-    ShowWindow(GetDlgItem(hDlg, IDC_No), \r
-       gameInfo.variant == VariantShogi ?\r
-              SW_SHOW : SW_HIDE);\r
+    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
@@ -4979,31 +4345,30 @@ Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
       promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);\r
       break;\r
     case PB_Queen:\r
-      promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);\r
+      promoChar = gameInfo.variant == VariantShogi ? '+' : ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteQueen : BlackQueen));\r
       break;\r
     case PB_Rook:\r
-      promoChar = PieceToChar(BlackRook);\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 = PieceToChar(BlackBishop);\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 = PieceToChar(BlackMarshall);\r
+      promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteMarshall : BlackMarshall));\r
       break;\r
     case PB_Archbishop:\r
-      promoChar = PieceToChar(BlackAngel);\r
+      promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteAngel : BlackAngel));\r
       break;\r
     case PB_Knight:\r
-      promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);\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
-    /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we\r
-       only show the popup when we are already sure the move is valid or\r
-       legal. We pass a faulty move type, but the kludge is that FinishMove\r
-       will figure out it is a promotion from the promoChar. */\r
     UserMoveEvent(fromX, fromY, toX, toY, promoChar);\r
     fromX = fromY = -1;\r
     if (!appData.highlightLastMove) {\r
@@ -5057,7 +4422,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
@@ -5113,11 +4478,11 @@ void UpdateICSWidth(HWND hText)
     LONG old_width, new_width;\r
 \r
     new_width = get_term_width(hText, FALSE);\r
-    old_width = GetWindowLong(hText, GWL_USERDATA);\r
+    old_width = GetWindowLongPtr(hText, GWLP_USERDATA);\r
     if (new_width != old_width)\r
     {\r
         ics_update_width(new_width);\r
-        SetWindowLong(hText, GWL_USERDATA, new_width);\r
+        SetWindowLongPtr(hText, GWLP_USERDATA, new_width);\r
     }\r
 }\r
 \r
@@ -5133,7 +4498,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
@@ -5222,7 +4588,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
        SendMessage(h, message, wParam, lParam);\r
     } else if(lParam != KF_REPEAT) {\r
        if (isalpha((char)wParam) || isdigit((char)wParam)) {\r
-               PopUpMoveDialog((char)wParam);\r
+               TypeInEvent((char)wParam);\r
        } else if((char)wParam == 003) CopyGameToClipboard();\r
         else if((char)wParam == 026) PasteGameOrFENFromClipboard();\r
     }\r
@@ -5279,7 +4645,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       break;\r
 \r
     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
@@ -5302,7 +4668,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       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
@@ -5325,7 +4691,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       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
@@ -5336,7 +4702,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       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
@@ -5347,7 +4713,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       f = OpenFileDialog(hwnd, "wb", defName,\r
                         "bmp",\r
                         DIAGRAM_FILT,\r
-                        "Save Diagram to File", NULL, fileTitle, NULL);\r
+                        _("Save Diagram to File"), NULL, fileTitle, NULL);\r
       if (f != NULL) {\r
        SaveDiagram(f);\r
       }\r
@@ -5420,7 +4786,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       break;\r
 \r
     case IDM_NewChat:\r
-      ChatPopUp();\r
+      ChatPopUp(NULL);\r
       break;\r
 \r
     case IDM_CopyPosition:\r
@@ -5476,6 +4842,14 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       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
+      if(gameMode != BeginningOfGame) { // allow menu item to remain enabled for better mode highligting\r
+        DisplayError(_("You can only start a match from the initial position."), 0); break;\r
+      }\r
+      appData.matchGames = appData.defaultMatchGames;
+      MatchEvent(2); // distinguish from command-line-triggered case (matchMode=1)\r
+      break;\r
+\r
     case IDM_TwoMachines:\r
       TwoMachinesEvent();\r
       /*\r
@@ -5487,19 +4861,19 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
          TagsPopUp(tags, CmailMsg());\r
          free(tags);\r
       }\r
-      SAY("programs start playing each other");\r
+      SAY("computer starts playing both sides");\r
       break;\r
 \r
     case IDM_AnalysisMode:\r
       if (!first.analysisSupport) {\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
-                       sprintf(buf, "You are not observing a game");\r
+                snprintf(buf, MSG_SIZ, "You are not observing a game");\r
                        DisplayError(buf, 0);\r
                        /* secure check */\r
                        if (appData.icsEngineAnalyze) {\r
@@ -5529,12 +4903,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
@@ -5544,13 +4918,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("to set up a position type a FEN");\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
@@ -5561,11 +4937,25 @@ 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
+      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_EditComment:\r
+    case IDM_Comment:\r
       if (commentUp && editComment) {\r
        CommentPopDown();\r
       } else {\r
@@ -5617,8 +5007,12 @@ 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
@@ -5648,7 +5042,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
@@ -5671,7 +5069,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     case IDM_FlipClock:\r
       flipClock = !flipClock;\r
       DisplayBothClocks();\r
-      DrawPosition(FALSE, NULL);\r
+      DisplayLogos();\r
       break;\r
 \r
     case IDM_MuteSounds:\r
@@ -5698,6 +5096,8 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       break;\r
 \r
     case IDM_Engine2Options:\r
+      savedHwnd = hwnd;\r
+      if(WaitForSecond(SettingsMenuIfReady)) break;\r
       EngineOptionsPopup(hwnd, &second);\r
       break;\r
 \r
@@ -5775,7 +5175,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       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
+                   _("Unable to activate help"),\r
                    szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);\r
       }\r
       break;\r
@@ -5784,7 +5184,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
         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
@@ -5792,7 +5192,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
@@ -5806,12 +5206,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
@@ -5989,7 +5389,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
@@ -6228,7 +5644,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
@@ -6294,6 +5710,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
@@ -6313,6 +5730,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
@@ -6338,12 +5756,12 @@ OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] dia
 \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
@@ -6376,13 +5794,13 @@ OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] dia
     /* open the file */\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
@@ -6400,6 +5818,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
@@ -6542,7 +5961,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
@@ -6550,7 +5969,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
@@ -6621,10 +6040,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
@@ -6645,6 +6064,7 @@ 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
@@ -6654,7 +6074,7 @@ StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
                  secondChessProgramNames);\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
@@ -6684,23 +6104,23 @@ 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, "/scp=", sizeof(buf)/sizeof(buf[0]) );\r
        GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));\r
         p = buf;\r
        ParseArgs(StringGet, &p);\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
@@ -6709,8 +6129,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
@@ -6728,7 +6148,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
@@ -6757,6 +6177,7 @@ About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
     /* Center the dialog over the application window */\r
     CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));\r
     SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);\r
+    Translate(hDlg, ABOUTBOX);\r
     JAWS_COPYRIGHT\r
     return (TRUE);\r
 \r
@@ -6790,6 +6211,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
@@ -6835,6 +6257,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
@@ -6879,6 +6302,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
@@ -6903,7 +6362,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
@@ -6944,15 +6403,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
     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
@@ -6961,39 +6418,11 @@ TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
 \r
   case WM_COMMAND:\r
     switch (LOWORD(wParam)) {\r
-    case IDOK:\r
-      GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));\r
-      { int n; Board board;\r
-       // [HGM] FENedit\r
-       if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {\r
-               EditPositionPasteFEN(move);\r
-               EndDialog(hDlg, TRUE);\r
-               return TRUE;\r
-       }\r
-       // [HGM] movenum: allow move number to be typed in any mode\r
-       if(sscanf(move, "%d", &n) == 1 && n != 0 ) {\r
-         ToNrEvent(2*n-1);\r
-         EndDialog(hDlg, TRUE);\r
-         return TRUE;\r
-       }\r
-      }\r
-      if (gameMode != EditGame && currentMove != forwardMostMove && \r
-       gameMode != Training) {\r
-       DisplayMoveError("Displayed move is not current");\r
-      } else {\r
-//     GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream\r
-       int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove, \r
-         &moveType, &fromX, &fromY, &toX, &toY, &promoChar);\r
-       if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized\r
-       if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove, \r
-         &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {\r
-         if (gameMode != Training)\r
-             forwardMostMove = currentMove;\r
-         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
@@ -7011,21 +6440,11 @@ 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
-       isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes\r
-               ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||\r
-                 gameMode == IcsObserving || gameMode == TwoMachinesPlay    ) ||\r
-       gameMode == Training) {\r
+\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
@@ -7045,6 +6464,7 @@ TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
     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
@@ -7057,6 +6477,12 @@ TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
       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
@@ -7135,6 +6561,7 @@ ErrorPopDown()
   if (errorDialog == NULL) return;\r
   DestroyWindow(errorDialog);\r
   errorDialog = NULL;\r
+  if(errorExitStatus) ExitEvent(errorExitStatus);\r
 }\r
 \r
 LRESULT CALLBACK\r
@@ -7160,6 +6587,7 @@ ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
         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
@@ -7297,76 +6725,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
@@ -7379,13 +6738,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
@@ -7450,11 +6810,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
@@ -7472,6 +6834,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
@@ -7505,12 +6868,22 @@ ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       SendMessage(hInput, message, wParam, lParam);\r
     }\r
     return 0;\r
-   } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu\r
-  case WM_RBUTTONUP:\r
-    if (GetKeyState(VK_SHIFT) & ~1) {\r
-      SendDlgItemMessage(hwndConsole, OPT_ConsoleText, \r
-        WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);\r
-    } else {\r
+   } // [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
+      POINT pt;\r
+      pt.x = LOWORD(lParam);\r
+      pt.y = HIWORD(lParam);\r
+      SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);\r
+      if (sel.cpMin == sel.cpMax) {\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
+{ // [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
@@ -7521,9 +6894,17 @@ 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
@@ -7532,21 +6913,6 @@ ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     return SendMessage(hInput, message, wParam, lParam);\r
   case WM_MBUTTONDOWN:\r
     return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);\r
-  case WM_RBUTTONDOWN:\r
-    if (!(GetKeyState(VK_SHIFT) & ~1)) {\r
-      /* Move selection here if it was empty */\r
-      POINT pt;\r
-      pt.x = LOWORD(lParam);\r
-      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
-       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_COMMAND:\r
     switch (LOWORD(wParam)) {\r
     case IDM_QuickPaste:\r
@@ -7789,10 +7155,10 @@ ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
     hwndConsole = hDlg;\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
@@ -7838,7 +7204,7 @@ ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
    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
-   SetWindowLong(hText, GWL_USERDATA, 79); // initialize the text window's width\r
+   SetWindowLongPtr(hText, GWLP_USERDATA, 79); // initialize the text window's width\r
 \r
     return FALSE;\r
 \r
@@ -8018,7 +7384,8 @@ DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
   HFONT oldFont;\r
   RECT rect;\r
 \r
-  if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;\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
@@ -8051,9 +7418,9 @@ DisplayAClock(HDC hdc, int timeRemaining, int highlight,
 \r
   if (appData.clockMode) {\r
     if (tinyLayout)\r
-      sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);\r
+      snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%c %s %s", color[0], TimeString(timeRemaining), flagFell);\r
     else\r
-      sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);\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
@@ -8075,7 +7442,7 @@ DisplayAClock(HDC hdc, int timeRemaining, int highlight,
             rect, str, strlen(str), NULL);\r
   if(logoHeight > 0 && appData.clockMode) {\r
       RECT r;\r
-      sprintf(buf, "%s %s", buf+7, flagFell);\r
+      str += strlen(color)+2;\r
       r.top = rect->top + logoHeight/2;\r
       r.left = rect->left;\r
       r.right = rect->right;\r
@@ -8354,6 +7721,7 @@ GreyRevert(Boolean grey)
 { // [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
@@ -8375,7 +7743,9 @@ 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
   { -1, -1 }\r
 };\r
@@ -8386,6 +7756,7 @@ Enables icsEnables[] = {
   { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_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
@@ -8396,10 +7767,11 @@ Enables icsEnables[] = {
   { 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
   { -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
@@ -8415,11 +7787,13 @@ 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
@@ -8429,11 +7803,13 @@ Enables ncpEnables[] = {
   { 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
@@ -8446,6 +7822,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
@@ -8482,6 +7859,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
@@ -8501,6 +7879,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
@@ -8542,7 +7921,7 @@ ModeHighlight()
     nowChecked = IDM_MachineWhite;\r
     break;\r
   case TwoMachinesPlay:\r
-    nowChecked = IDM_TwoMachines;\r
+    nowChecked = matchMode ? IDM_Match : IDM_TwoMachines; // [HGM] match\r
     break;\r
   case AnalyzeMode:\r
     nowChecked = IDM_AnalysisMode;\r
@@ -8600,6 +7979,7 @@ ModeHighlight()
                        MF_BYCOMMAND|MF_UNCHECKED);\r
        }\r
   }\r
+  DisplayLogos(); // [HGM] logos: mode change could have altered logos\r
 }\r
 \r
 VOID\r
@@ -8607,9 +7987,9 @@ 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
@@ -8630,8 +8010,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
@@ -8683,7 +8061,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
@@ -8693,17 +8071,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
@@ -8758,25 +8136,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
@@ -8787,7 +8165,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
@@ -8799,21 +8177,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
@@ -8832,14 +8210,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
@@ -8859,6 +8237,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
@@ -8867,14 +8246,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
@@ -8916,6 +8295,7 @@ LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM
         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
@@ -8942,7 +8322,7 @@ LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM
             }\r
             return TRUE;\r
         case IDC_NFG_Random:\r
-            sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */\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
@@ -8968,104 +8348,42 @@ int NewGameFRC()
     return result;\r
 }\r
 \r
-/* [AS] Game list options */\r
-typedef struct {\r
-    char id;\r
-    char * name;\r
-} GLT_Item;\r
-\r
-static GLT_Item GLT_ItemInfo[] = {\r
-    { GLT_EVENT,      "Event" },\r
-    { GLT_SITE,       "Site" },\r
-    { GLT_DATE,       "Date" },\r
-    { GLT_ROUND,      "Round" },\r
-    { GLT_PLAYERS,    "Players" },\r
-    { GLT_RESULT,     "Result" },\r
-    { GLT_WHITE_ELO,  "White Rating" },\r
-    { GLT_BLACK_ELO,  "Black Rating" },\r
-    { GLT_TIME_CONTROL,"Time Control" },\r
-    { GLT_VARIANT,    "Variant" },\r
-    { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },\r
-    { GLT_RESULT_COMMENT, "Result Comment" }, // [HGM] rescom\r
-    { 0, 0 }\r
-};\r
-\r
-const char * GLT_FindItem( char id )\r
-{\r
-    const char * result = 0;\r
+/* [AS] Game list options. Refactored by HGM */\r
 \r
-    GLT_Item * list = GLT_ItemInfo;\r
+HWND gameListOptionsDialog;\r
 \r
-    while( list->id != 0 ) {\r
-        if( list->id == id ) {\r
-            result = list->name;\r
-            break;\r
-        }\r
-\r
-        list++;\r
-    }\r
-\r
-    return result;\r
+// 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
-void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )\r
+// low-level front-end: clear text edit / list widget\r
+void\r
+GLT_DeSelectList()\r
 {\r
-    const char * name = GLT_FindItem( id );\r
-\r
-    if( name != 0 ) {\r
-        if( index >= 0 ) {\r
-            SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );\r
-        }\r
-        else {\r
-            SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );\r
-        }\r
-    }\r
+    SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_SETCURSEL, 0, 0 );\r
 }\r
 \r
-void GLT_TagsToList( HWND hDlg, char * tags )\r
+// low-level front-end: append line to text edit / list widget\r
+void\r
+GLT_AddToList( char *name )\r
 {\r
-    char * pc = tags;\r
-\r
-    SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );\r
-\r
-    while( *pc ) {\r
-        GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );\r
-        pc++;\r
-    }\r
-\r
-    SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );\r
-\r
-    pc = GLT_ALL_TAGS;\r
-\r
-    while( *pc ) {\r
-        if( strchr( tags, *pc ) == 0 ) {\r
-            GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );\r
-        }\r
-        pc++;\r
+    if( name != 0 ) {\r
+            SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) name );\r
     }\r
-\r
-    SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );\r
 }\r
 \r
-char GLT_ListItemToTag( HWND hDlg, int index )\r
+// low-level front-end: get line from text edit / list widget\r
+Boolean\r
+GLT_GetFromList( int index, char *name )\r
 {\r
-    char result = '\0';\r
-    char name[128];\r
-\r
-    GLT_Item * list = GLT_ItemInfo;\r
-\r
-    if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {\r
-        while( list->id != 0 ) {\r
-            if( strcmp( list->name, name ) == 0 ) {\r
-                result = list->id;\r
-                break;\r
-            }\r
-\r
-            list++;\r
-        }\r
+    if( name != 0 ) {\r
+           if( SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR )\r
+               return TRUE;\r
     }\r
-\r
-    return result;\r
+    return FALSE;\r
 }\r
 \r
 void GLT_MoveSelection( HWND hDlg, int delta )\r
@@ -9086,20 +8404,16 @@ void GLT_MoveSelection( HWND hDlg, int delta )
 \r
 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
 {\r
-    static char glt[64];\r
-    static char * lpUserGLT;\r
-\r
     switch( message )\r
     {\r
     case WM_INITDIALOG:\r
-        lpUserGLT = (char *) lParam;\r
+       gameListOptionsDialog = hDlg; // [HGM] pass through global to keep out off back-end\r
         \r
-        strcpy( glt, lpUserGLT );\r
-\r
         CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));\r
+        Translate(hDlg, DLG_GameListOptions);\r
 \r
         /* Initialize list */\r
-        GLT_TagsToList( hDlg, glt );\r
+        GLT_TagsToList( lpUserGLT );\r
 \r
         SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );\r
 \r
@@ -9108,19 +8422,7 @@ LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LP
     case WM_COMMAND:\r
         switch( LOWORD(wParam) ) {\r
         case IDOK:\r
-            {\r
-                char * pc = lpUserGLT;\r
-                int idx = 0;\r
-//                int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );\r
-                char id;\r
-\r
-                do {\r
-                    id = GLT_ListItemToTag( hDlg, idx );\r
-\r
-                    *pc++ = id;\r
-                    idx++;\r
-                } while( id != '\0' );\r
-            }\r
+           GLT_ParseList();\r
             EndDialog( hDlg, 0 );\r
             return TRUE;\r
         case IDCANCEL:\r
@@ -9128,13 +8430,11 @@ LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LP
             return TRUE;\r
 \r
         case IDC_GLT_Default:\r
-            strcpy( glt, GLT_DEFAULT_TAGS );\r
-            GLT_TagsToList( hDlg, glt );\r
+            GLT_TagsToList( GLT_DEFAULT_TAGS );\r
             return TRUE;\r
 \r
         case IDC_GLT_Restore:\r
-            strcpy( glt, lpUserGLT );\r
-            GLT_TagsToList( hDlg, glt );\r
+            GLT_TagsToList( appData.gameListTags );\r
             return TRUE;\r
 \r
         case IDC_GLT_Up:\r
@@ -9154,29 +8454,27 @@ LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LP
 \r
 int GameListOptions()\r
 {\r
-    char glt[64];\r
     int result;\r
     FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );\r
 \r
-    strcpy( glt, appData.gameListTags );\r
+      safeStrCpy( lpUserGLT, appData.gameListTags ,LPUSERGLT_SIZE ); \r
 \r
-    result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );\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( glt ); \r
+        appData.gameListTags = strdup( lpUserGLT ); \r
     }\r
 \r
     return result;\r
 }\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
@@ -9205,6 +8503,7 @@ ResetFrontEnd()
     ReleaseCapture();\r
     DrawPosition(TRUE, NULL);\r
   }\r
+  TagsPopDown();\r
 }\r
 \r
 \r
@@ -9212,7 +8511,7 @@ 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
@@ -9220,7 +8519,7 @@ CommentPopUp(char *title, char *str)
 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
@@ -9314,7 +8613,7 @@ UserName()
   }\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
@@ -9327,7 +8626,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
@@ -9365,7 +8664,7 @@ DisplayWhiteClock(long timeRemaining, int highlight)
   hdc = GetDC(hwndMain);\r
   if (!IsIconic(hwndMain)) {\r
     DisplayAClock(hdc, timeRemaining, highlight, \r
-                       flipClock ? &blackRect : &whiteRect, "White", flag);\r
+                       flipClock ? &blackRect : &whiteRect, _("White"), flag);\r
   }\r
   if (highlight && iconCurrent == iconBlack) {\r
     iconCurrent = iconWhite;\r
@@ -9389,7 +8688,7 @@ DisplayBlackClock(long timeRemaining, int highlight)
   hdc = GetDC(hwndMain);\r
   if (!IsIconic(hwndMain)) {\r
     DisplayAClock(hdc, timeRemaining, highlight, \r
-                       flipClock ? &whiteRect : &blackRect, "Black", flag);\r
+                       flipClock ? &whiteRect : &blackRect, _("Black"), flag);\r
   }\r
   if (highlight && iconCurrent == iconWhite) {\r
     iconCurrent = iconBlack;\r
@@ -9437,7 +8736,7 @@ AutoSaveGame()
   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
@@ -9741,9 +9040,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
@@ -9842,9 +9141,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
@@ -9876,7 +9175,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
@@ -10014,7 +9313,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
@@ -10246,7 +9545,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
@@ -10334,26 +9633,26 @@ static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
      POINT frames[], int * nFrames);\r
 \r
 \r
+#define kFactor 4\r
+\r
 void\r
-AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)\r
+AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)\r
 {      // [HGM] atomic: animate blast wave\r
        int i;\r
-if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);\r
+\r
        explodeInfo.fromX = fromX;\r
        explodeInfo.fromY = fromY;\r
        explodeInfo.toX = toX;\r
        explodeInfo.toY = toY;\r
-       for(i=1; i<nFrames; i++) {\r
-           explodeInfo.radius = (i*180)/(nFrames-1);\r
-           DrawPosition(FALSE, NULL);\r
+       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, NULL);\r
+       DrawPosition(TRUE, board);\r
 }\r
 \r
-#define kFactor 4\r
-\r
 void\r
 AnimateMove(board, fromX, fromY, toX, toY)\r
      Board board;\r
@@ -10376,17 +9675,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
@@ -10412,9 +9711,7 @@ AnimateMove(board, fromX, fromY, toX, toY)
   animInfo.pos = finish;\r
   DrawPosition(FALSE, NULL);\r
   animInfo.piece = EmptySquare;\r
-  if(gameInfo.variant == VariantAtomic && \r
-     (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )\r
-       AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);\r
+  Explode(board, fromX, fromY, toX, toY);\r
 }\r
 \r
 /*      Convert board position to corner of screen rect and color       */\r
@@ -10482,3 +9779,9 @@ HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
 \r
     EvalGraphSet( first, last, current, pvInfoList );\r
 }\r
+\r
+void\r
+SettingsPopUp(ChessProgramState *cps)\r
+{     // [HGM] wrapper needed because handles must not be passed through back-end\r
+      EngineOptionsPopup(savedHwnd, cps);\r
+}\r