Give WinBoard Game List its own font
[xboard.git] / winboard / winboard.c
index 55802b4..e2ba141 100644 (file)
@@ -1,11 +1,13 @@
 /*\r
  * WinBoard.c -- Windows NT front end to XBoard\r
- * $Id: winboard.c,v 2.3 2003/11/25 05:25:20 mann Exp $\r
  *\r
  * Copyright 1991 by Digital Equipment Corporation, Maynard,\r
- * Massachusetts.  Enhancements Copyright\r
- * 1992-2001,2002,2003,2004,2005,2006,2007,2008,2009 Free Software\r
- * Foundation, Inc.\r
+ * Massachusetts. \r
+ *\r
+ * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,\r
+ * 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.\r
+ *\r
+ * Enhancements Copyright 2005 Alessandro Scotti\r
  *\r
  * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,\r
  * which was written and is copyrighted by Wayne Christopher.\r
@@ -57,6 +59,7 @@
 #include <windows.h>\r
 #include <winuser.h>\r
 #include <winsock.h>\r
+#include <commctrl.h>\r
 \r
 #include <stdio.h>\r
 #include <stdlib.h>\r
@@ -69,6 +72,8 @@
 #include <dlgs.h>\r
 #include <richedit.h>\r
 #include <mmsystem.h>\r
+#include <ctype.h>\r
+#include <io.h>\r
 \r
 #if __GNUC__\r
 #include <errno.h>\r
 #endif\r
 \r
 #include "common.h"\r
-#include "winboard.h"\r
 #include "frontend.h"\r
 #include "backend.h"\r
+#include "winboard.h"\r
 #include "moves.h"\r
 #include "wclipbrd.h"\r
-#include "wgamelist.h"\r
-#include "wedittags.h"\r
 #include "woptions.h"\r
 #include "wsockerr.h"\r
 #include "defaults.h"\r
-\r
+#include "help.h"\r
 #include "wsnap.h"\r
 \r
 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );\r
 \r
 extern int whiteFlag, blackFlag;\r
 Boolean flipClock = FALSE;\r
+extern HANDLE chatHandle[];\r
+extern int ics_type;\r
 \r
 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);\r
-\r
+VOID NewVariantPopup(HWND hwnd);\r
+int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,\r
+                  /*char*/int promoChar));\r
+void DisplayMove P((int moveNumber));\r
+Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen));\r
+void ChatPopUp P((char *s));\r
 typedef struct {\r
   ChessSquare piece;  \r
   POINT pos;      /* window coordinates of current pos */\r
@@ -114,9 +124,10 @@ typedef struct {
   POINT pos;      /* window coordinates of current pos */\r
   POINT lastpos;  /* window coordinates of last pos - used for clipping */\r
   POINT from;     /* board coordinates of the piece's orig pos */\r
+  ChessSquare piece;\r
 } DragInfo;\r
 \r
-static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };\r
+static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, EmptySquare };\r
 \r
 typedef struct {\r
   POINT sq[2];   /* board coordinates of from, to squares */\r
@@ -124,6 +135,14 @@ typedef struct {
 \r
 static HighlightInfo highlightInfo        = { {{-1, -1}, {-1, -1}} };\r
 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };\r
+static HighlightInfo partnerHighlightInfo = { {{-1, -1}, {-1, -1}} };\r
+static HighlightInfo oldPartnerHighlight  = { {{-1, -1}, {-1, -1}} };\r
+\r
+typedef struct { // [HGM] atomic\r
+  int fromX, fromY, toX, toY, radius;\r
+} ExplodeInfo;\r
+\r
+static ExplodeInfo explodeInfo;\r
 \r
 /* Window class names */\r
 char szAppName[] = "WinBoard";\r
@@ -131,18 +150,20 @@ char szConsoleName[] = "WBConsole";
 \r
 /* Title bar text */\r
 char szTitle[] = "WinBoard";\r
-char szConsoleTitle[] = "ICS Interaction";\r
+char szConsoleTitle[] = "I C S Interaction";\r
 \r
 char *programName;\r
 char *settingsFileName;\r
-BOOLEAN saveSettingsOnExit;\r
+Boolean saveSettingsOnExit;\r
 char installDir[MSG_SIZ];\r
+int errorExitStatus;\r
 \r
 BoardSize boardSize;\r
-BOOLEAN chessProgram;\r
-static int boardX, boardY, consoleX, consoleY, consoleW, consoleH;\r
-static int squareSize, lineGap, minorSize;\r
-static int winWidth, winHeight;\r
+Boolean chessProgram;\r
+//static int boardX, boardY;\r
+int  minX, minY; // [HGM] placement: volatile limits on upper-left corner\r
+int squareSize, lineGap, minorSize;\r
+static int winW, winH;\r
 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo\r
 static int logoHeight = 0;\r
 static char messageText[MESSAGE_TEXT_MAX];\r
@@ -157,28 +178,27 @@ 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
-HWND hwndMain = NULL;        /* root window*/\r
-HWND hwndConsole = NULL;\r
-BOOLEAN alwaysOnTop = FALSE;\r
+Boolean alwaysOnTop = FALSE;\r
 RECT boardRect;\r
 COLORREF lightSquareColor, darkSquareColor, whitePieceColor, \r
   blackPieceColor, highlightSquareColor, premoveHighlightColor;\r
 HPALETTE hPal;\r
 ColorClass currentColorClass;\r
 \r
+static HWND savedHwnd;\r
 HWND hCommPort = NULL;    /* currently open comm port */\r
 static HWND hwndPause;    /* pause button */\r
 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */\r
 static HBRUSH lightSquareBrush, darkSquareBrush,\r
   blackSquareBrush, /* [HGM] for band between board and holdings */\r
-  whitePieceBrush, blackPieceBrush, iconBkgndBrush, outlineBrush;\r
-static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];\r
-static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];\r
+  explodeBrush,     /* [HGM] atomic */\r
+  markerBrush,      /* [HGM] markers */\r
+  whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;\r
+static POINT gridEndpoints[(BOARD_RANKS + BOARD_FILES + 2) * 2];\r
+static DWORD gridVertexCounts[BOARD_RANKS + BOARD_FILES + 2];\r
 static HPEN gridPen = NULL;\r
 static HPEN highlightPen = NULL;\r
 static HPEN premovePen = NULL;\r
@@ -188,32 +208,284 @@ static HICON iconWhite, iconBlack, iconCurrent;
 static int doingSizing = FALSE;\r
 static int lastSizing = 0;\r
 static int prevStderrPort;\r
-\r
-/* [AS] Support for background textures */\r
-#define BACK_TEXTURE_MODE_DISABLED      0\r
-#define BACK_TEXTURE_MODE_PLAIN         1\r
-#define BACK_TEXTURE_MODE_FULL_RANDOM   2\r
+static HBITMAP userLogo;\r
 \r
 static HBITMAP liteBackTexture = NULL;\r
 static HBITMAP darkBackTexture = NULL;\r
 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;\r
 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;\r
 static int backTextureSquareSize = 0;\r
-static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];\r
+static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_RANKS][BOARD_FILES];\r
 \r
 #if __GNUC__ && !defined(_winmajor)\r
 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */\r
 #else\r
+#if defined(_winmajor)\r
 #define oldDialog (_winmajor < 4)\r
+#else\r
+#define oldDialog 0\r
+#endif\r
 #endif\r
 \r
-char *defaultTextAttribs[] = \r
-{\r
-  COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,\r
-  COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,\r
-  COLOR_NONE\r
+#define INTERNATIONAL\r
+\r
+#ifdef INTERNATIONAL\r
+#  define _(s) T_(s)\r
+#  define N_(s) s\r
+#else\r
+#  define _(s) s\r
+#  define N_(s) s\r
+#  define T_(s) s\r
+#  define Translate(x, y)\r
+#  define LoadLanguageFile(s)\r
+#endif\r
+\r
+#ifdef INTERNATIONAL\r
+\r
+Boolean barbaric; // flag indicating if translation is needed\r
+\r
+// list of item numbers used in each dialog (used to alter language at run time)\r
+\r
+#define ABOUTBOX -1  /* not sure why these are needed */\r
+#define ABOUTBOX2 -1\r
+\r
+int dialogItems[][40] = {\r
+{ ABOUTBOX, IDOK, OPT_MESS, 400 }, \r
+{ DLG_TimeControl, IDC_Babble, OPT_TCUseMoves, OPT_TCUseInc, OPT_TCUseFixed, \r
+  OPT_TCtext1, OPT_TCtext2, OPT_TCitext1, OPT_TCitext2, OPT_TCftext, GPB_Factors,   IDC_Factor1, IDC_Factor2, IDOK, IDCANCEL }, \r
+{ DLG_LoadOptions, OPT_Autostep, OPT_AStext1, IDOK, IDCANCEL }, \r
+{ DLG_SaveOptions, OPT_Autosave, OPT_AVPrompt, OPT_AVToFile, OPT_AVBrowse,\r
+  801, OPT_PGN, OPT_Old, OPT_OutOfBookInfo, IDOK, IDCANCEL }, \r
+{ 1536, 1090, IDC_Directories, 1089, 1091, IDOK, IDCANCEL, 1038, IDC_IndexNr, 1037 }, \r
+{ DLG_CommPort, IDOK, IDCANCEL, IDC_Port, IDC_Rate, IDC_Bits, IDC_Parity,\r
+  IDC_Stop, IDC_Flow, OPT_SerialHelp }, \r
+{ DLG_EditComment, IDOK, OPT_CancelComment, OPT_ClearComment, OPT_EditComment }, \r
+{ DLG_PromotionKing, PB_Chancellor, PB_Archbishop, PB_Queen, PB_Rook, \r
+  PB_Bishop, PB_Knight, PB_King, IDCANCEL, IDC_Yes, IDC_No, IDC_Centaur }, \r
+{ ABOUTBOX2, IDC_ChessBoard }, \r
+{ DLG_GameList, OPT_GameListLoad, OPT_GameListPrev, OPT_GameListNext, \r
+  OPT_GameListClose, IDC_GameListDoFilter }, \r
+{ DLG_EditTags, IDOK, OPT_TagsCancel, OPT_EditTags }, \r
+{ DLG_Error, IDOK }, \r
+{ DLG_Colorize, IDOK, IDCANCEL, OPT_ChooseColor, OPT_Bold, OPT_Italic,\r
+  OPT_Underline, OPT_Strikeout, OPT_Sample }, \r
+{ DLG_Question, IDOK, IDCANCEL, OPT_QuestionText }, \r
+{ DLG_Startup, IDC_Welcome, OPT_ChessEngine, OPT_ChessServer, OPT_View,\r
+  IDC_SPECIFY_ENG_STATIC, IDC_SPECIFY_SERVER_STATIC, OPT_AnyAdditional,\r
+  IDOK, IDCANCEL, IDM_HELPCONTENTS }, \r
+{ DLG_IndexNumber, IDC_Index }, \r
+{ DLG_TypeInMove, IDOK, IDCANCEL }, \r
+{ DLG_TypeInName, IDOK, IDCANCEL }, \r
+{ DLG_Sound, IDC_Event, OPT_NoSound, OPT_DefaultBeep, OPT_BuiltInSound,\r
+  OPT_WavFile, OPT_BrowseSound, OPT_DefaultSounds, IDOK, IDCANCEL, OPT_PlaySound }, \r
+{ DLG_GeneralOptions, IDOK, IDCANCEL, OPT_AlwaysOnTop, OPT_HighlightLastMove,\r
+  OPT_AlwaysQueen, OPT_PeriodicUpdates, OPT_AnimateDragging, OPT_PonderNextMove,\r
+  OPT_AnimateMoving, OPT_PopupExitMessage, OPT_AutoFlag, OPT_PopupMoveErrors,\r
+  OPT_AutoFlipView, OPT_ShowButtonBar, OPT_AutoRaiseBoard, OPT_ShowCoordinates,\r
+  OPT_Blindfold, OPT_ShowThinking, OPT_HighlightDragging, OPT_TestLegality,\r
+  OPT_SaveExtPGN, OPT_HideThinkFromHuman, OPT_ExtraInfoInMoveHistory,\r
+  OPT_HighlightMoveArrow, OPT_AutoLogo ,OPT_SmartMove }, \r
+{ DLG_IcsOptions, IDOK, IDCANCEL, OPT_AutoComment, OPT_AutoKibitz, OPT_AutoObserve,\r
+  OPT_GetMoveList, OPT_LocalLineEditing, OPT_QuietPlay, OPT_SeekGraph, OPT_AutoRefresh,\r
+  OPT_BgObserve, OPT_DualBoard, OPT_Premove, OPT_PremoveWhite, OPT_PremoveBlack,\r
+  OPT_SmartMove, OPT_IcsAlarm, IDC_Sec, OPT_ChooseShoutColor, OPT_ChooseSShoutColor,\r
+  OPT_ChooseChannel1Color, OPT_ChooseChannelColor, OPT_ChooseKibitzColor,\r
+  OPT_ChooseTellColor, OPT_ChooseChallengeColor, OPT_ChooseRequestColor,\r
+  OPT_ChooseSeekColor, OPT_ChooseNormalColor, OPT_ChooseBackgroundColor,\r
+  OPT_DefaultColors, OPT_DontColorize, IDC_Boxes, GPB_Colors, GPB_Premove,\r
+  GPB_General, GPB_Alarm }, \r
+{ DLG_BoardOptions, IDOK, IDCANCEL, OPT_SizeTiny, OPT_SizeTeeny, OPT_SizeDinky,\r
+  OPT_SizePetite, OPT_SizeSlim, OPT_SizeSmall, OPT_SizeMediocre, OPT_SizeMiddling,\r
+  OPT_SizeAverage, OPT_SizeModerate, OPT_SizeMedium, OPT_SizeBulky, OPT_SizeLarge,\r
+  OPT_SizeBig, OPT_SizeHuge, OPT_SizeGiant, OPT_SizeColossal, OPT_SizeTitanic,\r
+  OPT_ChooseLightSquareColor, OPT_ChooseDarkSquareColor, OPT_ChooseWhitePieceColor,\r
+  OPT_ChooseBlackPieceColor, OPT_ChooseHighlightSquareColor, OPT_ChoosePremoveHighlightColor,\r
+  OPT_Monochrome, OPT_AllWhite, OPT_UpsideDown, OPT_DefaultBoardColors, GPB_Colors,\r
+  IDC_Light, IDC_Dark, IDC_White, IDC_Black, IDC_High, IDC_PreHigh, GPB_Size }, \r
+{ DLG_NewVariant, IDOK, IDCANCEL, OPT_VariantNormal, OPT_VariantFRC, OPT_VariantWildcastle,\r
+  OPT_VariantNocastle, OPT_VariantLosers, OPT_VariantGiveaway, OPT_VariantSuicide,\r
+  OPT_Variant3Check, OPT_VariantTwoKings, OPT_VariantAtomic, OPT_VariantCrazyhouse,\r
+  OPT_VariantBughouse, OPT_VariantTwilight, OPT_VariantShogi, OPT_VariantSuper,\r
+  OPT_VariantKnightmate, OPT_VariantBerolina, OPT_VariantCylinder, OPT_VariantFairy,\r
+  OPT_VariantMakruk, OPT_VariantGothic, OPT_VariantCapablanca, OPT_VariantJanus,\r
+  OPT_VariantCRC, OPT_VariantFalcon, OPT_VariantCourier, OPT_VariantGreat, OPT_VariantSChess,\r
+  OPT_VariantShatranj, OPT_VariantXiangqi, GPB_Variant, GPB_Board, IDC_Height,\r
+  IDC_Width, IDC_Hand, IDC_Pieces, IDC_Def }, \r
+{ DLG_Fonts, IDOK, IDCANCEL, OPT_ChooseClockFont, OPT_ChooseMessageFont,\r
+  OPT_ChooseCoordFont, OPT_ChooseTagFont, OPT_ChooseCommentsFont,  OPT_ChooseConsoleFont, OPT_ChooseMoveHistoryFont, OPT_DefaultFonts,\r
+  OPT_ClockFont, OPT_MessageFont, OPT_CoordFont, OPT_EditTagsFont,\r
+  OPT_SampleGameListFont, OPT_ChooseGameListFont, OPT_MessageFont7, \r
+  OPT_CommentsFont, OPT_MessageFont5, GPB_Current, GPB_All, OPT_MessageFont6 }, \r
+{ DLG_NewGameFRC, IDC_NFG_Label, IDC_NFG_Random, IDOK, IDCANCEL }, \r
+{ DLG_GameListOptions, IDC_GLT, IDC_GLT_Up, IDC_GLT_Down, IDC_GLT_Restore,\r
+  IDC_GLT_Default, IDOK, IDCANCEL, IDC_GLT_RestoreTo }, \r
+{ DLG_MoveHistory }, \r
+{ DLG_EvalGraph }, \r
+{ DLG_EngineOutput, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineLabel2, IDC_Engine2_NPS }, \r
+{ DLG_Chat, IDC_Partner, IDC_Clear, IDC_Send,  }, \r
+{ DLG_EnginePlayOptions, IDC_EpPonder, IDC_EpShowThinking, IDC_EpHideThinkingHuman,\r
+  IDC_EpPeriodicUpdates, GPB_Adjudications, IDC_Draw, IDC_Moves, IDC_Threshold,\r
+  IDC_Centi, IDC_TestClaims, IDC_DetectMates, IDC_MaterialDraws, IDC_TrivialDraws,\r
+  GPB_Apply, IDC_Rule, IDC_Repeats, IDC_ScoreAbs1, IDC_ScoreAbs2, IDOK, IDCANCEL }, \r
+{ DLG_OptionsUCI, IDC_PolyDir, IDC_BrowseForPolyglotDir, IDC_Hash, IDC_Path,\r
+  IDC_BrowseForEGTB, IDC_Cache, IDC_UseBook, IDC_BrowseForBook, IDC_CPU, IDC_OwnBook1,\r
+  IDC_OwnBook2, IDC_Depth, IDC_Variation, IDC_DefGames, IDOK, IDCANCEL },\r
+{ 0 }\r
 };\r
 \r
+static char languageBuf[50000], *foreign[1000], *english[1000], *languageFile[MSG_SIZ];\r
+static int lastChecked;\r
+static char oldLanguage[MSG_SIZ], *menuText[10][30];\r
+extern int tinyLayout;\r
+extern char * menuBarText[][10];\r
+\r
+void\r
+LoadLanguageFile(char *name)\r
+{   //load the file with translations, and make a list of the strings to be translated, and their translations\r
+    FILE *f;\r
+    int i=0, j=0, n=0, k;\r
+    char buf[MSG_SIZ];\r
+\r
+    if(!name || name[0] == NULLCHAR) return;\r
+      snprintf(buf, MSG_SIZ, "%s%s", name, strchr(name, '.') ? "" : ".lng"); // auto-append lng extension\r
+    appData.language = oldLanguage;\r
+    if(!strcmp(buf, oldLanguage)) { barbaric = 1; return; } // this language already loaded; just switch on\r
+    if((f = fopen(buf, "r")) == NULL) return;\r
+    while((k = fgetc(f)) != EOF) {\r
+        if(i >= sizeof(languageBuf)) { DisplayError("Language file too big", 0); return; }\r
+        languageBuf[i] = k;\r
+        if(k == '\n') {\r
+            if(languageBuf[n] == '"' && languageBuf[i-1] == '"') {\r
+                char *p;\r
+                if(p = strstr(languageBuf + n + 1, "\" === \"")) {\r
+                    if(p > languageBuf+n+2 && p+8 < languageBuf+i) {\r
+                        if(j >= sizeof(english)) { DisplayError("Too many translated strings", 0); return; }\r
+                        english[j] = languageBuf + n + 1; *p = 0;\r
+                        foreign[j++] = p + 7; languageBuf[i-1] = 0;\r
+//if(appData.debugMode) fprintf(debugFP, "translation: replace '%s' by '%s'\n", english[j-1], foreign[j-1]);\r
+                    }\r
+                }\r
+            }\r
+            n = i + 1;\r
+        } else if(i > 0 && languageBuf[i-1] == '\\') {\r
+            switch(k) {\r
+              case 'n': k = '\n'; break;\r
+              case 'r': k = '\r'; break;\r
+              case 't': k = '\t'; break;\r
+            }\r
+            languageBuf[--i] = k;\r
+        }\r
+        i++;\r
+    }\r
+    fclose(f);\r
+    barbaric = (j != 0);\r
+    safeStrCpy(oldLanguage, buf, sizeof(oldLanguage)/sizeof(oldLanguage[0]) );\r
+}\r
+\r
+char *\r
+T_(char *s)\r
+{   // return the translation of the given string\r
+    // efficiency can be improved a lot...\r
+    int i=0;\r
+//if(appData.debugMode) fprintf(debugFP, "T_(%s)\n", s);\r
+    if(!barbaric) return s;\r
+    if(!s) return ""; // sanity\r
+    while(english[i]) {\r
+        if(!strcmp(s, english[i])) return foreign[i];\r
+        i++;\r
+    }\r
+    return s;\r
+}\r
+\r
+void\r
+Translate(HWND hDlg, int dialogID)\r
+{   // translate all text items in the given dialog\r
+    int i=0, j, k;\r
+    char buf[MSG_SIZ], *s;\r
+    if(!barbaric) return;\r
+    while(dialogItems[i][0] && dialogItems[i][0] != dialogID) i++; // find the dialog description\r
+    if(dialogItems[i][0] != dialogID) return; // unknown dialog, should not happen\r
+    GetWindowText( hDlg, buf, MSG_SIZ );\r
+    s = T_(buf);\r
+    if(strcmp(buf, s)) SetWindowText(hDlg, s); // replace by translated string (if different)\r
+    for(j=1; k=dialogItems[i][j]; j++) { // translate all listed dialog items\r
+        GetDlgItemText(hDlg, k, buf, MSG_SIZ);\r
+        if(strlen(buf) == 0) continue;\r
+        s = T_(buf);\r
+        if(strcmp(buf, s)) SetDlgItemText(hDlg, k, s); // replace by translated string (if different)\r
+    }\r
+}\r
+\r
+HMENU\r
+TranslateOneMenu(int i, HMENU subMenu)\r
+{\r
+    int j;\r
+    static MENUITEMINFO info;\r
+\r
+    info.cbSize = sizeof(MENUITEMINFO);\r
+    info.fMask = MIIM_STATE | MIIM_TYPE;\r
+          for(j=GetMenuItemCount(subMenu)-1; j>=0; j--){\r
+            char buf[MSG_SIZ];\r
+            info.dwTypeData = buf;\r
+            info.cch = sizeof(buf);\r
+            GetMenuItemInfo(subMenu, j, TRUE, &info);\r
+            if(i < 10) {
+                if(menuText[i][j]) safeStrCpy(buf, menuText[i][j], sizeof(buf)/sizeof(buf[0]) );\r
+                else menuText[i][j] = strdup(buf); // remember original on first change\r
+            }\r
+            if(buf[0] == NULLCHAR) continue;\r
+            info.dwTypeData = T_(buf);\r
+            info.cch = strlen(buf)+1;\r
+            SetMenuItemInfo(subMenu, j, TRUE, &info);\r
+          }\r
+    return subMenu;\r
+}\r
+\r
+void\r
+TranslateMenus(int addLanguage)\r
+{\r
+    int i;\r
+    WIN32_FIND_DATA fileData;\r
+    HANDLE hFind;\r
+#define IDM_English 1970\r
+    if(1) {\r
+        HMENU mainMenu = GetMenu(hwndMain);\r
+        for (i=GetMenuItemCount(mainMenu)-1; i>=0; i--) {\r
+          HMENU subMenu = GetSubMenu(mainMenu, i);\r
+          ModifyMenu(mainMenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP|EnableMenuItem(mainMenu, i, MF_BYPOSITION),\r
+                                                                  (UINT) subMenu, T_(menuBarText[tinyLayout][i]));\r
+          TranslateOneMenu(i, subMenu);\r
+        }\r
+        DrawMenuBar(hwndMain);\r
+    }\r
+\r
+    if(!addLanguage) return;\r
+    if((hFind = FindFirstFile("*.LNG", &fileData)) != INVALID_HANDLE_VALUE) {\r
+        HMENU mainMenu = GetMenu(hwndMain);\r
+        HMENU subMenu = GetSubMenu(mainMenu, GetMenuItemCount(mainMenu)-1);\r
+        AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);\r
+        AppendMenu(subMenu, MF_ENABLED|MF_STRING|(barbaric?MF_UNCHECKED:MF_CHECKED), (UINT_PTR) IDM_English, (LPCTSTR) "English");\r
+        i = 0; lastChecked = IDM_English;\r
+        do {\r
+            char *p, *q = fileData.cFileName;\r
+            int checkFlag = MF_UNCHECKED;\r
+            languageFile[i] = strdup(q);\r
+            if(barbaric && !strcmp(oldLanguage, q)) {\r
+                checkFlag = MF_CHECKED;\r
+                lastChecked = IDM_English + i + 1;\r
+                CheckMenuItem(mainMenu, IDM_English, MF_BYCOMMAND|MF_UNCHECKED);\r
+            }\r
+            *q = ToUpper(*q); while(*++q) *q = ToLower(*q);\r
+            p = strstr(fileData.cFileName, ".lng");\r
+            if(p) *p = 0;\r
+            AppendMenu(subMenu, MF_ENABLED|MF_STRING|checkFlag, (UINT_PTR) IDM_English + ++i, (LPCTSTR) fileData.cFileName);\r
+        } while(FindNextFile(hFind, &fileData));\r
+        FindClose(hFind);\r
+    }\r
+}\r
+\r
+#endif\r
+\r
 typedef struct {\r
   char *name;\r
   int squareSize;\r
@@ -246,27 +518,27 @@ SizeInfo sizeInfo[] =
   { NULL, 0, 0, 0, 0, 0, 0 }\r
 };\r
 \r
-#define MF(x) {x, {0, }, {0, }, 0}\r
+#define MF(x) {x, {{0,}, 0. }, {0, }, 0}\r
 MyFont fontRec[NUM_SIZES][NUM_FONTS] =\r
 {\r
-  { MF(CLOCK_FONT_TINY), MF(MESSAGE_FONT_TINY), MF(COORD_FONT_TINY), MF(CONSOLE_FONT_TINY), MF(COMMENT_FONT_TINY), MF(EDITTAGS_FONT_TINY), MF(MOVEHISTORY_FONT_ALL) },\r
-  { MF(CLOCK_FONT_TEENY), MF(MESSAGE_FONT_TEENY), MF(COORD_FONT_TEENY), MF(CONSOLE_FONT_TEENY), MF(COMMENT_FONT_TEENY), MF(EDITTAGS_FONT_TEENY), MF(MOVEHISTORY_FONT_ALL) },\r
-  { MF(CLOCK_FONT_DINKY), MF(MESSAGE_FONT_DINKY), MF(COORD_FONT_DINKY), MF(CONSOLE_FONT_DINKY), MF(COMMENT_FONT_DINKY), MF(EDITTAGS_FONT_DINKY), MF(MOVEHISTORY_FONT_ALL) },\r
-  { MF(CLOCK_FONT_PETITE), MF(MESSAGE_FONT_PETITE), MF(COORD_FONT_PETITE), MF(CONSOLE_FONT_PETITE), MF(COMMENT_FONT_PETITE), MF(EDITTAGS_FONT_PETITE), MF(MOVEHISTORY_FONT_ALL) },\r
-  { MF(CLOCK_FONT_SLIM), MF(MESSAGE_FONT_SLIM), MF(COORD_FONT_SLIM), MF(CONSOLE_FONT_SLIM), MF(COMMENT_FONT_SLIM), MF(EDITTAGS_FONT_SLIM), MF(MOVEHISTORY_FONT_ALL) },\r
-  { MF(CLOCK_FONT_SMALL), MF(MESSAGE_FONT_SMALL), MF(COORD_FONT_SMALL), MF(CONSOLE_FONT_SMALL), MF(COMMENT_FONT_SMALL), MF(EDITTAGS_FONT_SMALL), MF(MOVEHISTORY_FONT_ALL) },\r
-  { MF(CLOCK_FONT_MEDIOCRE), MF(MESSAGE_FONT_MEDIOCRE), MF(COORD_FONT_MEDIOCRE), MF(CONSOLE_FONT_MEDIOCRE), MF(COMMENT_FONT_MEDIOCRE), MF(EDITTAGS_FONT_MEDIOCRE), MF(MOVEHISTORY_FONT_ALL) },\r
-  { MF(CLOCK_FONT_MIDDLING), MF(MESSAGE_FONT_MIDDLING), MF(COORD_FONT_MIDDLING), MF(CONSOLE_FONT_MIDDLING), MF(COMMENT_FONT_MIDDLING), MF(EDITTAGS_FONT_MIDDLING), MF(MOVEHISTORY_FONT_ALL) },\r
-  { MF(CLOCK_FONT_AVERAGE), MF(MESSAGE_FONT_AVERAGE), MF(COORD_FONT_AVERAGE), MF(CONSOLE_FONT_AVERAGE), MF(COMMENT_FONT_AVERAGE), MF(EDITTAGS_FONT_AVERAGE), MF(MOVEHISTORY_FONT_ALL) },\r
-  { MF(CLOCK_FONT_MODERATE), MF(MESSAGE_FONT_MODERATE), MF(COORD_FONT_MODERATE), MF(CONSOLE_FONT_MODERATE), MF(COMMENT_FONT_MODERATE), MF(EDITTAGS_FONT_MODERATE), MF(MOVEHISTORY_FONT_ALL) },\r
-  { MF(CLOCK_FONT_MEDIUM), MF(MESSAGE_FONT_MEDIUM), MF(COORD_FONT_MEDIUM), MF(CONSOLE_FONT_MEDIUM), MF(COMMENT_FONT_MEDIUM), MF(EDITTAGS_FONT_MEDIUM), MF(MOVEHISTORY_FONT_ALL) },\r
-  { MF(CLOCK_FONT_BULKY), MF(MESSAGE_FONT_BULKY), MF(COORD_FONT_BULKY), MF(CONSOLE_FONT_BULKY), MF(COMMENT_FONT_BULKY), MF(EDITTAGS_FONT_BULKY), MF(MOVEHISTORY_FONT_ALL) },\r
-  { MF(CLOCK_FONT_LARGE), MF(MESSAGE_FONT_LARGE), MF(COORD_FONT_LARGE), MF(CONSOLE_FONT_LARGE), MF(COMMENT_FONT_LARGE), MF(EDITTAGS_FONT_LARGE), MF(MOVEHISTORY_FONT_ALL) },\r
-  { MF(CLOCK_FONT_BIG), MF(MESSAGE_FONT_BIG), MF(COORD_FONT_BIG), MF(CONSOLE_FONT_BIG), MF(COMMENT_FONT_BIG), MF(EDITTAGS_FONT_BIG), MF(MOVEHISTORY_FONT_ALL) },\r
-  { MF(CLOCK_FONT_HUGE), MF(MESSAGE_FONT_HUGE), MF(COORD_FONT_HUGE), MF(CONSOLE_FONT_HUGE), MF(COMMENT_FONT_HUGE), MF(EDITTAGS_FONT_HUGE), MF(MOVEHISTORY_FONT_ALL) },\r
-  { MF(CLOCK_FONT_GIANT), MF(MESSAGE_FONT_GIANT), MF(COORD_FONT_GIANT), MF(CONSOLE_FONT_GIANT), MF(COMMENT_FONT_GIANT), MF(EDITTAGS_FONT_GIANT), MF(MOVEHISTORY_FONT_ALL) },\r
-  { MF(CLOCK_FONT_COLOSSAL), MF(MESSAGE_FONT_COLOSSAL), MF(COORD_FONT_COLOSSAL), MF(CONSOLE_FONT_COLOSSAL), MF(COMMENT_FONT_COLOSSAL), MF(EDITTAGS_FONT_COLOSSAL), MF(MOVEHISTORY_FONT_ALL) },\r
-  { MF(CLOCK_FONT_TITANIC), MF(MESSAGE_FONT_TITANIC), MF(COORD_FONT_TITANIC), MF(CONSOLE_FONT_TITANIC), MF(COMMENT_FONT_TITANIC), MF(EDITTAGS_FONT_TITANIC), MF(MOVEHISTORY_FONT_ALL) },\r
+  { MF(CLOCK_FONT_TINY), MF(MESSAGE_FONT_TINY), MF(COORD_FONT_TINY), MF(CONSOLE_FONT_TINY), MF(COMMENT_FONT_TINY), MF(EDITTAGS_FONT_TINY), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },\r
+  { MF(CLOCK_FONT_TEENY), MF(MESSAGE_FONT_TEENY), MF(COORD_FONT_TEENY), MF(CONSOLE_FONT_TEENY), MF(COMMENT_FONT_TEENY), MF(EDITTAGS_FONT_TEENY), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },\r
+  { MF(CLOCK_FONT_DINKY), MF(MESSAGE_FONT_DINKY), MF(COORD_FONT_DINKY), MF(CONSOLE_FONT_DINKY), MF(COMMENT_FONT_DINKY), MF(EDITTAGS_FONT_DINKY), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },\r
+  { MF(CLOCK_FONT_PETITE), MF(MESSAGE_FONT_PETITE), MF(COORD_FONT_PETITE), MF(CONSOLE_FONT_PETITE), MF(COMMENT_FONT_PETITE), MF(EDITTAGS_FONT_PETITE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },\r
+  { MF(CLOCK_FONT_SLIM), MF(MESSAGE_FONT_SLIM), MF(COORD_FONT_SLIM), MF(CONSOLE_FONT_SLIM), MF(COMMENT_FONT_SLIM), MF(EDITTAGS_FONT_SLIM), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },\r
+  { MF(CLOCK_FONT_SMALL), MF(MESSAGE_FONT_SMALL), MF(COORD_FONT_SMALL), MF(CONSOLE_FONT_SMALL), MF(COMMENT_FONT_SMALL), MF(EDITTAGS_FONT_SMALL), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },\r
+  { MF(CLOCK_FONT_MEDIOCRE), MF(MESSAGE_FONT_MEDIOCRE), MF(COORD_FONT_MEDIOCRE), MF(CONSOLE_FONT_MEDIOCRE), MF(COMMENT_FONT_MEDIOCRE), MF(EDITTAGS_FONT_MEDIOCRE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },\r
+  { MF(CLOCK_FONT_MIDDLING), MF(MESSAGE_FONT_MIDDLING), MF(COORD_FONT_MIDDLING), MF(CONSOLE_FONT_MIDDLING), MF(COMMENT_FONT_MIDDLING), MF(EDITTAGS_FONT_MIDDLING), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },\r
+  { MF(CLOCK_FONT_AVERAGE), MF(MESSAGE_FONT_AVERAGE), MF(COORD_FONT_AVERAGE), MF(CONSOLE_FONT_AVERAGE), MF(COMMENT_FONT_AVERAGE), MF(EDITTAGS_FONT_AVERAGE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },\r
+  { MF(CLOCK_FONT_MODERATE), MF(MESSAGE_FONT_MODERATE), MF(COORD_FONT_MODERATE), MF(CONSOLE_FONT_MODERATE), MF(COMMENT_FONT_MODERATE), MF(EDITTAGS_FONT_MODERATE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },\r
+  { MF(CLOCK_FONT_MEDIUM), MF(MESSAGE_FONT_MEDIUM), MF(COORD_FONT_MEDIUM), MF(CONSOLE_FONT_MEDIUM), MF(COMMENT_FONT_MEDIUM), MF(EDITTAGS_FONT_MEDIUM), MF(MOVEHISTORY_FONT_ALL),  MF(GAMELIST_FONT_ALL) },\r
+  { MF(CLOCK_FONT_BULKY), MF(MESSAGE_FONT_BULKY), MF(COORD_FONT_BULKY), MF(CONSOLE_FONT_BULKY), MF(COMMENT_FONT_BULKY), MF(EDITTAGS_FONT_BULKY), MF(MOVEHISTORY_FONT_ALL),  MF(GAMELIST_FONT_ALL) },\r
+  { MF(CLOCK_FONT_LARGE), MF(MESSAGE_FONT_LARGE), MF(COORD_FONT_LARGE), MF(CONSOLE_FONT_LARGE), MF(COMMENT_FONT_LARGE), MF(EDITTAGS_FONT_LARGE), MF(MOVEHISTORY_FONT_ALL),  MF(GAMELIST_FONT_ALL) },\r
+  { MF(CLOCK_FONT_BIG), MF(MESSAGE_FONT_BIG), MF(COORD_FONT_BIG), MF(CONSOLE_FONT_BIG), MF(COMMENT_FONT_BIG), MF(EDITTAGS_FONT_BIG), MF(MOVEHISTORY_FONT_ALL),  MF(GAMELIST_FONT_ALL) },\r
+  { MF(CLOCK_FONT_HUGE), MF(MESSAGE_FONT_HUGE), MF(COORD_FONT_HUGE), MF(CONSOLE_FONT_HUGE), MF(COMMENT_FONT_HUGE), MF(EDITTAGS_FONT_HUGE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },\r
+  { MF(CLOCK_FONT_GIANT), MF(MESSAGE_FONT_GIANT), MF(COORD_FONT_GIANT), MF(CONSOLE_FONT_GIANT), MF(COMMENT_FONT_GIANT), MF(EDITTAGS_FONT_GIANT), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },\r
+  { MF(CLOCK_FONT_COLOSSAL), MF(MESSAGE_FONT_COLOSSAL), MF(COORD_FONT_COLOSSAL), MF(CONSOLE_FONT_COLOSSAL), MF(COMMENT_FONT_COLOSSAL), MF(EDITTAGS_FONT_COLOSSAL), MF(MOVEHISTORY_FONT_ALL), MF (GAMELIST_FONT_ALL) },\r
+  { MF(CLOCK_FONT_TITANIC), MF(MESSAGE_FONT_TITANIC), MF(COORD_FONT_TITANIC), MF(CONSOLE_FONT_TITANIC), MF(COMMENT_FONT_TITANIC), MF(EDITTAGS_FONT_TITANIC), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },\r
 };\r
 \r
 MyFont *font[NUM_SIZES][NUM_FONTS];\r
@@ -291,10 +563,10 @@ MyButtonDesc buttonDesc[N_BUTTONS] =
 };\r
 \r
 int tinyLayout = 0, smallLayout = 0;\r
-#define MENU_BAR_ITEMS 6\r
+#define MENU_BAR_ITEMS 9\r
 char *menuBarText[2][MENU_BAR_ITEMS+1] = {\r
-  { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },\r
-  { "&F", "&M", "&A", "&S", "&O", "&H", NULL },\r
+  { N_("&File"), N_("&Edit"), N_("&View"), N_("&Mode"), N_("&Action"), N_("E&ngine"), N_("&Options"), N_("&Help"), NULL },\r
+  { N_("&F"), N_("&E"), N_("&V"), N_("&M"), N_("&A"), N_("&N"), N_("&O"), N_("&H"), NULL },\r
 };\r
 \r
 \r
@@ -302,17 +574,17 @@ MySound sounds[(int)NSoundClasses];
 MyTextAttribs textAttribs[(int)NColorClasses];\r
 \r
 MyColorizeAttribs colorizeAttribs[] = {\r
-  { (COLORREF)0, 0, "Shout Text" },\r
-  { (COLORREF)0, 0, "SShout/CShout" },\r
-  { (COLORREF)0, 0, "Channel 1 Text" },\r
-  { (COLORREF)0, 0, "Channel Text" },\r
-  { (COLORREF)0, 0, "Kibitz Text" },\r
-  { (COLORREF)0, 0, "Tell Text" },\r
-  { (COLORREF)0, 0, "Challenge Text" },\r
-  { (COLORREF)0, 0, "Request Text" },\r
-  { (COLORREF)0, 0, "Seek Text" },\r
-  { (COLORREF)0, 0, "Normal Text" },\r
-  { (COLORREF)0, 0, "None" }\r
+  { (COLORREF)0, 0, N_("Shout Text") },\r
+  { (COLORREF)0, 0, N_("SShout/CShout") },\r
+  { (COLORREF)0, 0, N_("Channel 1 Text") },\r
+  { (COLORREF)0, 0, N_("Channel Text") },\r
+  { (COLORREF)0, 0, N_("Kibitz Text") },\r
+  { (COLORREF)0, 0, N_("Tell Text") },\r
+  { (COLORREF)0, 0, N_("Challenge Text") },\r
+  { (COLORREF)0, 0, N_("Request Text") },\r
+  { (COLORREF)0, 0, N_("Seek Text") },\r
+  { (COLORREF)0, 0, N_("Normal Text") },\r
+  { (COLORREF)0, 0, N_("None") }\r
 };\r
 \r
 \r
@@ -321,15 +593,7 @@ static char *commentTitle;
 static char *commentText;\r
 static int commentIndex;\r
 static Boolean editComment = FALSE;\r
-HWND commentDialog = NULL;\r
-BOOLEAN commentDialogUp = FALSE;\r
-static int commentX, commentY, commentH, commentW;\r
 \r
-static char *analysisTitle;\r
-static char *analysisText;\r
-HWND analysisDialog = NULL;\r
-BOOLEAN analysisDialogUp = FALSE;\r
-static int analysisX, analysisY, analysisH, analysisW;\r
 \r
 char errorTitle[MSG_SIZ];\r
 char errorMessage[2*MSG_SIZ];\r
@@ -391,7 +655,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
@@ -399,35 +662,29 @@ VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
 int NewGameFRC();\r
 int GameListOptions();\r
 \r
-HWND moveHistoryDialog = NULL;\r
-BOOLEAN moveHistoryDialogUp = FALSE;\r
-\r
-WindowPlacement wpMoveHistory;\r
+int dummy; // [HGM] for obsolete args\r
 \r
+HWND hwndMain = NULL;        /* root window*/\r
+HWND hwndConsole = NULL;\r
+HWND commentDialog = NULL;\r
+HWND moveHistoryDialog = NULL;\r
 HWND evalGraphDialog = NULL;\r
-BOOLEAN evalGraphDialogUp = FALSE;\r
-\r
-WindowPlacement wpEvalGraph;\r
-\r
 HWND engineOutputDialog = NULL;\r
-BOOLEAN engineOutputDialogUp = FALSE;\r
-\r
-WindowPlacement wpEngineOutput;\r
+HWND gameListDialog = NULL;\r
+HWND editTagsDialog = NULL;\r
 \r
-VOID MoveHistoryPopUp();\r
-VOID MoveHistoryPopDown();\r
-VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );\r
-BOOL MoveHistoryIsUp();\r
+int commentUp = FALSE;\r
 \r
-VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );\r
-VOID EvalGraphPopUp();\r
-VOID EvalGraphPopDown();\r
-BOOL EvalGraphIsUp();\r
+WindowPlacement wpMain;\r
+WindowPlacement wpConsole;\r
+WindowPlacement wpComment;\r
+WindowPlacement wpMoveHistory;\r
+WindowPlacement wpEvalGraph;\r
+WindowPlacement wpEngineOutput;\r
+WindowPlacement wpGameList;\r
+WindowPlacement wpTags;\r
 \r
-VOID EngineOutputPopUp();\r
-VOID EngineOutputPopDown();\r
-BOOL EngineOutputIsUp();\r
-VOID EngineOutputUpdate( FrontEndProgramStats * stats );\r
+VOID EngineOptionsPopup(); // [HGM] settings\r
 \r
 VOID GothicPopUp(char *title, VariantClass variant);\r
 /*\r
@@ -465,6 +722,26 @@ void ThawUI()
   DrawMenuBar(hwndMain);\r
 }\r
 \r
+/*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them\r
+\r
+/* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */\r
+#ifdef JAWS\r
+#include "jaws.c"\r
+#else\r
+#define JAWS_INIT\r
+#define JAWS_ARGS\r
+#define JAWS_ALT_INTERCEPT\r
+#define JAWS_KB_NAVIGATION\r
+#define JAWS_MENU_ITEMS\r
+#define JAWS_SILENCE\r
+#define JAWS_REPLAY\r
+#define JAWS_ACCEL\r
+#define JAWS_COPYRIGHT\r
+#define JAWS_DELETE(X) X\r
+#define SAYMACHINEMOVE()\r
+#define SAY(X)\r
+#endif\r
+\r
 /*---------------------------------------------------------------------------*\\r
  *\r
  * WinMain\r
@@ -477,6 +754,7 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
 {\r
   MSG msg;\r
   HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;\r
+//  INITCOMMONCONTROLSEX ex;\r
 \r
   debugFP = stderr;\r
 \r
@@ -490,6 +768,12 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
     return (FALSE);\r
   }\r
 \r
+  JAWS_INIT\r
+  TranslateMenus(1);\r
+\r
+//  InitCommonControlsEx(&ex);\r
+  InitCommonControls();\r
+\r
   hAccelMain = LoadAccelerators (hInstance, szAppName);\r
   hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");\r
   hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */\r
@@ -501,6 +785,77 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    0,    /* lowest message to examine */\r
                    0))   /* highest message to examine */\r
     {\r
+\r
+      if(msg.message == WM_CHAR && msg.wParam == '\t') {\r
+       // [HGM] navigate: switch between all windows with tab\r
+       HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;\r
+       int i, currentElement = 0;\r
+\r
+       // first determine what element of the chain we come from (if any)\r
+       if(appData.icsActive) {\r
+           hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);\r
+           hText  = GetDlgItem(hwndConsole, OPT_ConsoleText);\r
+       }\r
+       if(engineOutputDialog && EngineOutputIsUp()) {\r
+           e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);\r
+           e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);\r
+       }\r
+       if(moveHistoryDialog && MoveHistoryIsUp()) {\r
+           mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);\r
+       }\r
+       if(msg.hwnd == hwndMain) currentElement = 7 ; else\r
+       if(msg.hwnd == engineOutputDialog) currentElement = 2; else\r
+       if(msg.hwnd == e1)                 currentElement = 2; else\r
+       if(msg.hwnd == e2)                 currentElement = 3; else\r
+       if(msg.hwnd == moveHistoryDialog) currentElement = 4; else\r
+       if(msg.hwnd == mh)                currentElement = 4; else\r
+       if(msg.hwnd == evalGraphDialog)    currentElement = 6; else\r
+       if(msg.hwnd == hText)  currentElement = 5; else\r
+       if(msg.hwnd == hInput) currentElement = 6; else\r
+       for (i = 0; i < N_BUTTONS; i++) {\r
+           if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }\r
+       }\r
+\r
+       // determine where to go to\r
+       if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;\r
+         do {\r
+           currentElement = (currentElement + direction) % 7;\r
+           switch(currentElement) {\r
+               case 0:\r
+                 h = hwndMain; break; // passing this case always makes the loop exit\r
+               case 1:\r
+                 h = buttonDesc[0].hwnd; break; // could be NULL\r
+               case 2:\r
+                 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows\r
+                 h = e1; break;\r
+               case 3:\r
+                 if(!EngineOutputIsUp()) continue;\r
+                 h = e2; break;\r
+               case 4:\r
+                 if(!MoveHistoryIsUp()) continue;\r
+                 h = mh; break;\r
+//             case 6: // input to eval graph does not seem to get here!\r
+//               if(!EvalGraphIsUp()) continue;\r
+//               h = evalGraphDialog; break;\r
+               case 5:\r
+                 if(!appData.icsActive) continue;\r
+                 SAY("display");\r
+                 h = hText; break;\r
+               case 6:\r
+                 if(!appData.icsActive) continue;\r
+                 SAY("input");\r
+                 h = hInput; break;\r
+           }\r
+         } while(h == 0);\r
+\r
+         if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);\r
+         if(currentElement < 5 && IsIconic(hwndMain))    ShowWindow(hwndMain, SW_RESTORE); // all open together\r
+         SetFocus(h);\r
+\r
+         continue; // this message now has been processed\r
+       }\r
+      }\r
+\r
       if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&\r
           !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&\r
           !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&\r
@@ -508,9 +863,15 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
          !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&\r
          !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&\r
          !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&\r
-         !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) &&\r
+         !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL\r
           !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&\r
          !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {\r
+       int done = 0, i; // [HGM] chat: dispatch cat-box messages\r
+       for(i=0; i<MAX_CHAT; i++) \r
+           if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {\r
+               done = 1; break;\r
+       }\r
+       if(done) continue; // [HGM] chat: end patch\r
        TranslateMessage(&msg); /* Translates virtual key codes */\r
        DispatchMessage(&msg);  /* Dispatches message to window */\r
       }\r
@@ -526,6 +887,26 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  *\r
 \*---------------------------------------------------------------------------*/\r
 \r
+void\r
+SetUserLogo()\r
+{   // update user logo if necessary\r
+    static char oldUserName[MSG_SIZ], dir[MSG_SIZ], *curName;\r
+\r
+    if(appData.autoLogo) {\r
+         curName = UserName();\r
+         if(strcmp(curName, oldUserName)) {\r
+               GetCurrentDirectory(MSG_SIZ, dir);\r
+               SetCurrentDirectory(installDir);\r
+               snprintf(oldUserName, MSG_SIZ, "logos\\%s.bmp", curName);\r
+               userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );    \r
+               safeStrCpy(oldUserName, curName, sizeof(oldUserName)/sizeof(oldUserName[0]) );\r
+               if(userLogo == NULL)\r
+                   userLogo = LoadImage( 0, "logos\\dummy.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ); \r
+               SetCurrentDirectory(dir); /* return to prev directory */\r
+         }\r
+    }\r
+}\r
+\r
 BOOL\r
 InitApplication(HINSTANCE hInstance)\r
 {\r
@@ -568,16 +949,39 @@ InitApplication(HINSTANCE hInstance)
 int screenHeight, screenWidth;\r
 \r
 void\r
-EnsureOnScreen(int *x, int *y)\r
+EnsureOnScreen(int *x, int *y, int minX, int minY)\r
 {\r
 //  int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);\r
   /* Be sure window at (x,y) is not off screen (or even mostly off screen) */\r
   if (*x > screenWidth - 32) *x = 0;\r
   if (*y > screenHeight - 32) *y = 0;\r
-  if (*x < 0) *x = 0;\r
-  if (*y < 0) *y = 0;\r
-//  if (*x < 10) *x = 10;\r
-//  if (*y < gap) *y = gap;\r
+  if (*x < minX) *x = minX;\r
+  if (*y < minY) *y = minY;\r
+}\r
+\r
+VOID\r
+LoadLogo(ChessProgramState *cps, int n, Boolean ics)\r
+{\r
+  char buf[MSG_SIZ], dir[MSG_SIZ];\r
+  GetCurrentDirectory(MSG_SIZ, dir);\r
+  SetCurrentDirectory(installDir);\r
+  if( appData.logo[n] && appData.logo[n][0] != NULLCHAR) {\r
+      cps->programLogo = LoadImage( 0, appData.logo[n], IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );\r
+\r
+      if (cps->programLogo == NULL && appData.debugMode) {\r
+          fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.logo[n] );\r
+      }\r
+  } else if(appData.autoLogo) {\r
+      if(ics) { // [HGM] logo: in ICS mode second can be used for ICS\r
+       sprintf(buf, "logos\\%s.bmp", appData.icsHost);\r
+       cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );\r
+      } else\r
+      if(appData.directory[n] && appData.directory[n][0]) {\r
+        SetCurrentDirectory(appData.directory[n]);\r
+       cps->programLogo = LoadImage( 0, "logo.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );     \r
+      }\r
+  }\r
+  SetCurrentDirectory(dir); /* return to prev directory */\r
 }\r
 \r
 BOOL\r
@@ -589,6 +993,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
@@ -596,12 +1001,26 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
     GetCurrentDirectory(MSG_SIZ, installDir);\r
   }\r
   gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise\r
+  screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData\r
   InitAppData(lpCmdLine);      /* Get run-time parameters */\r
+  /* xboard, and older WinBoards, controlled the move sound with the\r
+     appData.ringBellAfterMoves option.  In the current WinBoard, we\r
+     always turn the option on (so that the backend will call us),\r
+     then let the user turn the sound off by setting it to silence if\r
+     desired.  To accommodate old winboard.ini files saved by old\r
+     versions of WinBoard, we also turn off the sound if the option\r
+     was initially set to false. [HGM] taken out of InitAppData */\r
+  if (!appData.ringBellAfterMoves) {\r
+    sounds[(int)SoundMove].name = strdup("");\r
+    appData.ringBellAfterMoves = TRUE;\r
+  }\r
   if (appData.debugMode) {\r
     debugFP = fopen(appData.nameOfDebugFile, "w");\r
     setbuf(debugFP, NULL);\r
   }\r
 \r
+  LoadLanguageFile(appData.language);\r
+\r
   InitBackEnd1();\r
 \r
 //  InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()\r
@@ -620,33 +1039,10 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
   }\r
 \r
   /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */\r
-  if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {\r
-      first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );\r
+  LoadLogo(&first, 0, FALSE);\r
+  LoadLogo(&second, 1, appData.icsActive);\r
 \r
-      if (first.programLogo == NULL && appData.debugMode) {\r
-          fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );\r
-      }\r
-  } else if(appData.autoLogo) {\r
-      if(appData.firstDirectory && appData.firstDirectory[0]) {\r
-       char buf[MSG_SIZ];\r
-       sprintf(buf, "%s/logo.bmp", appData.firstDirectory);\r
-       first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );   \r
-      }\r
-  }\r
-\r
-  if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {\r
-      second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );\r
-\r
-      if (second.programLogo == NULL && appData.debugMode) {\r
-          fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );\r
-      }\r
-  } else if(appData.autoLogo) {\r
-      if(appData.secondDirectory && appData.secondDirectory[0]) {\r
-       char buf[MSG_SIZ];\r
-       sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);\r
-       second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );  \r
-      }\r
-  }\r
+  SetUserLogo();\r
 \r
   iconWhite = LoadIcon(hInstance, "icon_white");\r
   iconBlack = LoadIcon(hInstance, "icon_black");\r
@@ -657,11 +1053,11 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
   for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {\r
     /* Compute window size for each board size, and use the largest\r
        size that fits on this screen as the default. */\r
-    InitDrawingSizes((BoardSize)ibs, 0);\r
+    InitDrawingSizes((BoardSize)(ibs+1000), 0);\r
     if (boardSize == (BoardSize)-1 &&\r
-        winHeight <= screenHeight\r
+        winH <= screenHeight\r
            - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10\r
-        && winWidth <= screenWidth) {\r
+        && winW <= screenWidth) {\r
       boardSize = (BoardSize)ibs;\r
     }\r
   }\r
@@ -706,602 +1102,122 @@ 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(&boardX, &boardY);\r
+  EnsureOnScreen(&wpMain.x, &wpMain.y, minX, minY);\r
   wp.length = sizeof(WINDOWPLACEMENT);\r
   wp.flags = 0;\r
   wp.showCmd = nCmdShow;\r
   wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;\r
-  wp.rcNormalPosition.left = boardX;\r
-  wp.rcNormalPosition.right = boardX + winWidth;\r
-  wp.rcNormalPosition.top = boardY;\r
-  wp.rcNormalPosition.bottom = boardY + winHeight;\r
+  wp.rcNormalPosition.left = wpMain.x;\r
+  wp.rcNormalPosition.right = wpMain.x + wpMain.width;\r
+  wp.rcNormalPosition.top = wpMain.y;\r
+  wp.rcNormalPosition.bottom = wpMain.y + wpMain.height;\r
   SetWindowPlacement(hwndMain, &wp);\r
 \r
-  SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,\r
+  InitBackEnd2(); // [HGM] moved until after all windows placed, to save correct position if fatal error on engine start\r
+\r
+  if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,\r
                0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);\r
 \r
-#if 0\r
-  /* [AS] Disable the FRC stuff if not playing the proper variant */\r
-  if( gameInfo.variant != VariantFischeRandom ) {\r
-      EnableMenuItem( GetMenu(hwndMain), IDM_NewGameFRC, MF_GRAYED );\r
-  }\r
-#endif\r
   if (hwndConsole) {\r
 #if AOT_CONSOLE\r
     SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,\r
                  0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);\r
 #endif\r
     ShowWindow(hwndConsole, nCmdShow);\r
+    if(appData.chatBoxes) { // [HGM] chat: open chat boxes\r
+      char buf[MSG_SIZ], *p = buf, *q;\r
+       safeStrCpy(buf, appData.chatBoxes, sizeof(buf)/sizeof(buf[0]) );\r
+      do {\r
+       q = strchr(p, ';');\r
+       if(q) *q++ = 0;\r
+       if(*p) ChatPopUp(p);\r
+      } while(p=q);\r
+    }\r
+    SetActiveWindow(hwndConsole);\r
   }\r
-  UpdateWindow(hwnd);\r
+  if(!appData.noGUI)   UpdateWindow(hwnd);  else ShowWindow(hwnd, SW_MINIMIZE);\r
+  if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file\r
 \r
   return TRUE;\r
 \r
 }\r
 \r
+VOID\r
+InitMenuChecks()\r
+{\r
+  HMENU hmenu = GetMenu(hwndMain);\r
 \r
-typedef enum {\r
-  ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone, \r
-  ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,\r
-  ArgSettingsFilename\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 struct {\r
-  char *argName;\r
-  ArgType argType;\r
-  /***\r
-  union {\r
-    String *pString;       // ArgString\r
-    int *pInt;             // ArgInt\r
-    float *pFloat;         // ArgFloat\r
-    Boolean *pBoolean;     // ArgBoolean\r
-    COLORREF *pColor;      // ArgColor\r
-    ColorClass cc;         // ArgAttribs\r
-    String *pFilename;     // ArgFilename\r
-    BoardSize *pBoardSize; // ArgBoardSize\r
-    int whichFont;         // ArgFont\r
-    DCB *pDCB;             // ArgCommSettings\r
-    String *pFilename;     // ArgSettingsFilename\r
-  } argLoc;\r
-  ***/\r
-  LPVOID argLoc;\r
-  BOOL save;\r
-} ArgDescriptor;\r
-\r
-int junk;\r
-ArgDescriptor argDescriptors[] = {\r
-  /* positional arguments */\r
-  { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },\r
-  { "", ArgNone, NULL },\r
-  /* keyword arguments */\r
-  { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },\r
-  { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },\r
-  { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },\r
-  { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },\r
-  { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },\r
-  { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },\r
-  { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },\r
-  { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },\r
-  { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },\r
-  { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },\r
-  { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },\r
-  { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },\r
-  { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },\r
-  { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },\r
-  { "initString", ArgString, (LPVOID) &appData.initString, FALSE },\r
-  { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },\r
-  { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },\r
-  { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,\r
-    FALSE },\r
-  { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,\r
-    FALSE },\r
-  { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,\r
-    FALSE },\r
-  { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },\r
-  { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,\r
-    FALSE },\r
-  { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },\r
-  { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },\r
-  { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },\r
-  { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },\r
-  { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },\r
-  { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },\r
-  { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },\r
-  { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },\r
-  { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },\r
-  { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },\r
-  { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },\r
-  { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },\r
-  { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },\r
-  { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },\r
-  { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },\r
-  { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },\r
-  { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },\r
-  /*!!bitmapDirectory?*/\r
-  { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },\r
-  { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },\r
-  { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },\r
-  { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },\r
-  { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },\r
-  { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },\r
-  { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },\r
-  { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },\r
-  { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },\r
-  { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },\r
-  { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },\r
-  { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },\r
-  { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },\r
-  { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },\r
-  { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },\r
-  { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },\r
-  { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },\r
-  { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },\r
-  { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },\r
-  { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },\r
-  { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },\r
-  { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },\r
-  { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },\r
-  { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },\r
-  { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },\r
-  { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },\r
-  { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },\r
-  { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },\r
-  { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },\r
-  { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },\r
-  { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },\r
-  { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },\r
-  { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },\r
-  { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },\r
-  { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },\r
-  { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },\r
-  { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },\r
-  { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },\r
-  { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },\r
-  { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },\r
-  { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },\r
-  { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },\r
-  { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },\r
-  { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },\r
-  { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },\r
-  { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },\r
-  { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },\r
-  { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },\r
-  { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },\r
-  { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },\r
-  { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },\r
-  { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },\r
-  { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },\r
-  { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },\r
-  { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },\r
-  { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },\r
-  { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },\r
-  { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },\r
-  { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },\r
-  { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },\r
-  { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },\r
-  { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },\r
-  { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },\r
-  { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },\r
-  { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },\r
-  { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },\r
-  { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },\r
-  { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },\r
-  { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },\r
-  { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },\r
-  { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },\r
-  { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },\r
-  { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },\r
-  { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },\r
-  { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },\r
-  { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },\r
-  { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },\r
-  { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },\r
-  { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },\r
-  { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },\r
-  { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },\r
-  { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },\r
-  { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },\r
-  { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },\r
-  { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },\r
-  { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },\r
-  { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },\r
-  { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },\r
-  { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },\r
-  { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },\r
-  { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },\r
-  { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },\r
-  { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },\r
-  { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, \r
-    FALSE }, /* only so that old WinBoard.ini files from betas can be read */\r
-  { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },\r
-  { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },\r
-  { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },\r
-  { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },\r
-  { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },\r
-  { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },\r
-  { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */\r
-  { "boardSize", ArgBoardSize, (LPVOID) &boardSize,\r
-    TRUE }, /* must come after all fonts */\r
-  { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },\r
-  { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,\r
-    FALSE }, /* historical; kept only so old winboard.ini files will parse */\r
-  { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },\r
-  { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },\r
-  { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },\r
-  { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },\r
-  { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },\r
-  { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },\r
-  { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },\r
-  { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },\r
-  { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },\r
-  { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },\r
-  { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },\r
-  { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },\r
-  { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },\r
-  { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },\r
-  { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },\r
-  { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },\r
-  { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },\r
-  { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },\r
-  { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },\r
-  { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },\r
-  { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },\r
-  { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },\r
-  { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },\r
-  { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },\r
-  { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },\r
-  { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },\r
-  { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },\r
-  { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },\r
-#if 0\r
-  { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },\r
-  { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },\r
-#endif\r
-  { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },\r
-  { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },\r
-  { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },\r
-  { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },\r
-  { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },\r
-  { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },\r
-  { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },\r
-  { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },\r
-  { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },\r
-  { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },\r
-  { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },\r
-  { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },\r
-  { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },\r
-  { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },\r
-  { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },\r
-  { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },\r
-  { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },\r
-  { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },\r
-  { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },\r
-  { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },\r
-  { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },\r
-  { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },\r
-  { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },\r
-  { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },\r
-  { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },\r
-  { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },\r
-  { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },\r
-  { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },\r
-  { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },\r
-  { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },\r
-  { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },\r
-  { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },\r
-  { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },\r
-  { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },\r
-  { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},\r
-  { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},\r
-  { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},\r
-  { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},\r
-  { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},\r
-  { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},\r
-  { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},\r
-  { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },\r
-  { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },\r
-  { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },\r
-  { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },\r
-  { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },\r
-  { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },\r
-  { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },\r
-  { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },\r
-  { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },\r
-  { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },\r
-  { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },\r
-  { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },\r
-  { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },\r
-  { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },\r
-  { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },\r
-  { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },\r
-  { "highlightLastMove", ArgBoolean,\r
-    (LPVOID) &appData.highlightLastMove, TRUE },\r
-  { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },\r
-  { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },\r
-  { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },\r
-  { "highlightDragging", ArgBoolean,\r
-    (LPVOID) &appData.highlightDragging, TRUE },\r
-  { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },\r
-  { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },\r
-  { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },\r
-  { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },\r
-  { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },\r
-  { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },\r
-  { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },\r
-  { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },\r
-  { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },\r
-  { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },\r
-  { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },\r
-  { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },\r
-  { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },\r
-  { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },\r
-  { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },\r
-  { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },\r
-  { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },\r
-  { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },\r
-  { "soundShout", ArgFilename,\r
-    (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },\r
-  { "soundSShout", ArgFilename,\r
-    (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },\r
-  { "soundChannel1", ArgFilename,\r
-    (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },\r
-  { "soundChannel", ArgFilename,\r
-    (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },\r
-  { "soundKibitz", ArgFilename,\r
-    (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },\r
-  { "soundTell", ArgFilename,\r
-    (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },\r
-  { "soundChallenge", ArgFilename,\r
-    (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },\r
-  { "soundRequest", ArgFilename,\r
-    (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },\r
-  { "soundSeek", ArgFilename,\r
-    (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },\r
-  { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },\r
-  { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },\r
-  { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },\r
-  { "soundIcsLoss", ArgFilename, \r
-    (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },\r
-  { "soundIcsDraw", ArgFilename, \r
-    (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },\r
-  { "soundIcsUnfinished", ArgFilename, \r
-    (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},\r
-  { "soundIcsAlarm", ArgFilename, \r
-    (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },\r
-  { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },\r
-  { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },\r
-  { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },\r
-  { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },\r
-  { "reuseChessPrograms", ArgBoolean,\r
-    (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */\r
-  { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },\r
-  { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },\r
-  { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },\r
-  { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },\r
-  { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },\r
-  { "x", ArgInt, (LPVOID) &boardX, TRUE },\r
-  { "y", ArgInt, (LPVOID) &boardY, TRUE },\r
-  { "icsX", ArgInt, (LPVOID) &consoleX, TRUE },\r
-  { "icsY", ArgInt, (LPVOID) &consoleY, TRUE },\r
-  { "icsW", ArgInt, (LPVOID) &consoleW, TRUE },\r
-  { "icsH", ArgInt, (LPVOID) &consoleH, TRUE },\r
-  { "analysisX", ArgInt, (LPVOID) &analysisX, TRUE },\r
-  { "analysisY", ArgInt, (LPVOID) &analysisY, TRUE },\r
-  { "analysisW", ArgInt, (LPVOID) &analysisW, TRUE },\r
-  { "analysisH", ArgInt, (LPVOID) &analysisH, TRUE },\r
-  { "commentX", ArgInt, (LPVOID) &commentX, TRUE },\r
-  { "commentY", ArgInt, (LPVOID) &commentY, TRUE },\r
-  { "commentW", ArgInt, (LPVOID) &commentW, TRUE },\r
-  { "commentH", ArgInt, (LPVOID) &commentH, TRUE },\r
-  { "tagsX", ArgInt, (LPVOID) &editTagsX, TRUE },\r
-  { "tagsY", ArgInt, (LPVOID) &editTagsY, TRUE },\r
-  { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },\r
-  { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },\r
-  { "gameListX", ArgInt, (LPVOID) &gameListX, TRUE },\r
-  { "gameListY", ArgInt, (LPVOID) &gameListY, TRUE },\r
-  { "gameListW", ArgInt, (LPVOID) &gameListW, TRUE },\r
-  { "gameListH", ArgInt, (LPVOID) &gameListH, TRUE },\r
-  { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },\r
-  { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },\r
-  { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },\r
-  { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },\r
-  { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },\r
-  { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },\r
-  { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },\r
-  { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },\r
-  { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },\r
-  { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,\r
-    TRUE },\r
-  { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,\r
-    TRUE },\r
-  { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },\r
-  { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },\r
-  { "variant", ArgString, (LPVOID) &appData.variant, FALSE },\r
-  { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },\r
-  { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },\r
-  { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },\r
-  { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },\r
-  { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },\r
-  { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },\r
-  /* [AS] New features */\r
-  { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },\r
-  { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },\r
-  { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },\r
-  { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },\r
-  { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },\r
-  { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },\r
-  { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },\r
-  { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },\r
-  { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },\r
-  { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },\r
-  { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },\r
-  { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },\r
-  { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },\r
-  { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },\r
-  { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },\r
-  { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },\r
-  { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },\r
-  { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },\r
-  { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },\r
-  { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },\r
-  { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },\r
-  { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },\r
-  { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },\r
-  { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },\r
-  { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },\r
-  { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },\r
-  { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },\r
-  { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },\r
-  { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },\r
-  { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },\r
-  { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },\r
-  { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },\r
-  { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },\r
-  { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },\r
-  { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },\r
-  { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },\r
-  { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },\r
-  { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },\r
-  { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },\r
-  { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },\r
-  { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },\r
-  { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },\r
-  { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },\r
-  { "secondXBook", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },\r
-  { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },\r
-  { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },\r
-  { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },\r
-  { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE }, \r
-  { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },\r
-  { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },\r
-\r
-  /* [AS] Layout stuff */\r
-  { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },\r
-  { "moveHistoryX", ArgInt, (LPVOID) &wpMoveHistory.x, TRUE },\r
-  { "moveHistoryY", ArgInt, (LPVOID) &wpMoveHistory.y, TRUE },\r
-  { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },\r
-  { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },\r
-\r
-  { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },\r
-  { "evalGraphX", ArgInt, (LPVOID) &wpEvalGraph.x, TRUE },\r
-  { "evalGraphY", ArgInt, (LPVOID) &wpEvalGraph.y, TRUE },\r
-  { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },\r
-  { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },\r
-\r
-  { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },\r
-  { "engineOutputX", ArgInt, (LPVOID) &wpEngineOutput.x, TRUE },\r
-  { "engineOutputY", ArgInt, (LPVOID) &wpEngineOutput.y, TRUE },\r
-  { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },\r
-  { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },\r
-\r
-  /* [HGM] board-size, adjudication and misc. options */\r
-  { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },\r
-  { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },\r
-  { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },\r
-  { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },\r
-  { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },\r
-  { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },\r
-  { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },\r
-  { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },\r
-  { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE },\r
-  { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE },\r
-  { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },\r
-  { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },\r
-  { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },\r
-  { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },\r
-  { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },\r
-  { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },\r
-  { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },\r
-  { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },\r
-  { "userName", ArgString, (LPVOID) &appData.userName, FALSE },\r
-  { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE },\r
-  { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE },\r
-  { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE },\r
-  { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE },\r
-  { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE },\r
-  { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE },\r
-  { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE },\r
-  { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },\r
-  { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE },\r
-  { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE },\r
-\r
-#ifdef ZIPPY\r
-  { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },\r
-  { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },\r
-  { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },\r
-  { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },\r
-  { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },\r
-  { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },\r
-  { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },\r
-  { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },\r
-  { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },\r
-  { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },\r
-  { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },\r
-  { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },\r
-  { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,\r
-    FALSE },\r
-  { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },\r
-  { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },\r
-  { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },\r
-  { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },\r
-  { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },\r
-  { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },\r
-  { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,\r
-    FALSE },\r
-  { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },\r
-  { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },\r
-  { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },\r
-  { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },\r
-  { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },\r
-  { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },\r
-  { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },\r
-  { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },\r
-  { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },\r
-  { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },\r
-  { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },\r
-  { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },\r
-  { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },\r
-  { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },\r
-  { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },\r
-  { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },\r
-  /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */\r
-  { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },\r
-#endif\r
-  /* [HGM] options for broadcasting and time odds */\r
-  { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },\r
-  { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },\r
-  { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },\r
-  { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },\r
-  { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },\r
-  { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },\r
-  { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },\r
-  { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },\r
-  { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },\r
-  { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },\r
-  { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },\r
-  { NULL, ArgNone, NULL, FALSE }\r
-};\r
+//---------------------------------------------------------------------------------------------------------\r
+\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
@@ -1316,7 +1232,7 @@ ParseFontName(char *name, MyFontParams *mfp)
   q = strchr(p, ':');\r
   if (q) {\r
     if (q - p >= sizeof(mfp->faceName))\r
-      ExitArgError("Font name too long:", name);\r
+      ExitArgError(_("Font name too long:"), name, TRUE);\r
     memcpy(mfp->faceName, p, q - p);\r
     mfp->faceName[q - p] = NULLCHAR;\r
     p = q + 1;\r
@@ -1325,19 +1241,53 @@ ParseFontName(char *name, MyFontParams *mfp)
     while (*p && !isdigit(*p)) {\r
       *q++ = *p++;\r
       if (q - mfp->faceName >= sizeof(mfp->faceName))\r
-       ExitArgError("Font name too long:", name);\r
+       ExitArgError(_("Font name too long:"), name, TRUE);\r
     }\r
     while (q > mfp->faceName && q[-1] == ' ') q--;\r
     *q = NULLCHAR;\r
   }\r
-  if (!*p) ExitArgError("Font point size missing:", name);\r
+  if (!*p) ExitArgError(_("Font point size missing:"), name, TRUE);\r
   mfp->pointSize = (float) atof(p);\r
   mfp->bold = (strchr(p, 'b') != NULL);\r
   mfp->italic = (strchr(p, 'i') != NULL);\r
   mfp->underline = (strchr(p, 'u') != NULL);\r
   mfp->strikeout = (strchr(p, 's') != NULL);\r
+  mfp->charset = DEFAULT_CHARSET;\r
+  q = strchr(p, 'c');\r
+  if (q)\r
+    mfp->charset = (BYTE) atoi(q+1);\r
+}\r
+\r
+void\r
+ParseFont(char *name, int number)\r
+{ // wrapper to shield back-end from 'font'\r
+  ParseFontName(name, &font[boardSize][number]->mfp);\r
+}\r
+\r
+void\r
+SetFontDefaults()\r
+{ // in WB  we have a 2D array of fonts; this initializes their description\r
+  int i, j;\r
+  /* Point font array elements to structures and\r
+     parse default font names */\r
+  for (i=0; i<NUM_FONTS; i++) {\r
+    for (j=0; j<NUM_SIZES; j++) {\r
+      font[j][i] = &fontRec[j][i];\r
+      ParseFontName(font[j][i]->def, &font[j][i]->mfp);\r
+    }\r
+  }\r
 }\r
 \r
+void\r
+CreateFonts()\r
+{ // here we create the actual fonts from the selected descriptions\r
+  int i, j;\r
+  for (i=0; i<NUM_FONTS; i++) {\r
+    for (j=0; j<NUM_SIZES; j++) {\r
+      CreateFontInMF(font[j][i]);\r
+    }\r
+  }\r
+}\r
 /* Color name parser.\r
    X version accepts X color names, but this one\r
    handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */\r
@@ -1353,15 +1303,21 @@ ParseColorName(char *name)
       &red, &green, &blue);\r
   }\r
   if (count != 3) {\r
-    sprintf(buf, "Can't parse color name %s", name);\r
+    snprintf(buf, MSG_SIZ, _("Can't parse color name %s"), name);\r
     DisplayError(buf, 0);\r
     return RGB(0, 0, 0);\r
   }\r
   return PALETTERGB(red, green, blue);\r
 }\r
 \r
+void\r
+ParseColor(int n, char *name)\r
+{ // for WinBoard the color is an int, which needs to be derived from the string\r
+  if(colorVariable[n]) *(int*)colorVariable[n] = ParseColorName(name);\r
+}\r
 \r
-void ParseAttribs(COLORREF *color, int *effects, char* argValue)\r
+void\r
+ParseAttribs(COLORREF *color, int *effects, char* argValue)\r
 {\r
   char *e = argValue;\r
   int eff = 0;\r
@@ -1378,472 +1334,52 @@ void ParseAttribs(COLORREF *color, int *effects, char* argValue)
   *color   = ParseColorName(e);\r
 }\r
 \r
+void\r
+ParseTextAttribs(ColorClass cc, char *s)\r
+{   // [HGM] front-end wrapper that does the platform-dependent call\r
+    // for XBoard we would set (&appData.colorShout)[cc] = strdup(s);\r
+    ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, s);\r
+}\r
 \r
-BoardSize\r
-ParseBoardSize(char *name)\r
-{\r
+void\r
+ParseBoardSize(void *addr, char *name)\r
+{ // [HGM] rewritten with return-value ptr to shield back-end from BoardSize\r
   BoardSize bs = SizeTiny;\r
   while (sizeInfo[bs].name != NULL) {\r
-    if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;\r
-    bs++;\r
-  }\r
-  ExitArgError("Unrecognized board size value", name);\r
-  return bs; /* not reached */\r
-}\r
-\r
-\r
-char\r
-StringGet(void *getClosure)\r
-{\r
-  char **p = (char **) getClosure;\r
-  return *((*p)++);\r
-}\r
-\r
-char\r
-FileGet(void *getClosure)\r
-{\r
-  int c;\r
-  FILE* f = (FILE*) getClosure;\r
-\r
-  c = getc(f);\r
-  if (c == EOF)\r
-    return NULLCHAR;\r
-  else\r
-    return (char) c;\r
-}\r
-\r
-/* Parse settings file named "name". If file found, return the\r
-   full name in fullname and return TRUE; else return FALSE */\r
-BOOLEAN\r
-ParseSettingsFile(char *name, char fullname[MSG_SIZ])\r
-{\r
-  char *dummy;\r
-  FILE *f;\r
-\r
-  if (SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy)) {\r
-    f = fopen(fullname, "r");\r
-    if (f != NULL) {\r
-      ParseArgs(FileGet, f);\r
-      fclose(f);\r
-      return TRUE;\r
-    }\r
-  }\r
-  return FALSE;\r
-}\r
-\r
-VOID\r
-ParseArgs(GetFunc get, void *cl)\r
-{\r
-  char argName[ARG_MAX];\r
-  char argValue[ARG_MAX];\r
-  ArgDescriptor *ad;\r
-  char start;\r
-  char *q;\r
-  int i, octval;\r
-  char ch;\r
-  int posarg = 0;\r
-\r
-  ch = get(cl);\r
-  for (;;) {\r
-    while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);\r
-    if (ch == NULLCHAR) break;\r
-    if (ch == ';') {\r
-      /* Comment to end of line */\r
-      ch = get(cl);\r
-      while (ch != '\n' && ch != NULLCHAR) ch = get(cl);\r
-      continue;\r
-    } else if (ch == '/' || ch == '-') {\r
-      /* Switch */\r
-      q = argName;\r
-      while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&\r
-            ch != '\n' && ch != '\t') {\r
-       *q++ = ch;\r
-       ch = get(cl);\r
-      }\r
-      *q = NULLCHAR;\r
-\r
-      for (ad = argDescriptors; ad->argName != NULL; ad++)\r
-       if (strcmp(ad->argName, argName + 1) == 0) break;\r
-\r
-      if (ad->argName == NULL)\r
-       ExitArgError("Unrecognized argument", argName);\r
-\r
-    } else if (ch == '@') {\r
-      /* Indirection file */\r
-      ad = &argDescriptorIndirection;\r
-      ch = get(cl);\r
-    } else {\r
-      /* Positional argument */\r
-      ad = &argDescriptors[posarg++];\r
-      strcpy(argName, ad->argName);\r
-    }\r
-\r
-    if (ad->argType == ArgTrue) {\r
-      *(Boolean *) ad->argLoc = TRUE;\r
-      continue;\r
-    }\r
-    if (ad->argType == ArgFalse) {\r
-      *(Boolean *) ad->argLoc = FALSE;\r
-      continue;\r
-    }\r
-\r
-    while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);\r
-    if (ch == NULLCHAR || ch == '\n') {\r
-      ExitArgError("No value provided for argument", argName);\r
-    }\r
-    q = argValue;\r
-    if (ch == '{') {\r
-      // Quoting with { }.  No characters have to (or can) be escaped.\r
-      // Thus the string cannot contain a '}' character.\r
-      start = ch;\r
-      ch = get(cl);\r
-      while (start) {\r
-       switch (ch) {\r
-       case NULLCHAR:\r
-         start = NULLCHAR;\r
-         break;\r
-         \r
-       case '}':\r
-         ch = get(cl);\r
-         start = NULLCHAR;\r
-         break;\r
-\r
-       default:\r
-         *q++ = ch;\r
-         ch = get(cl);\r
-         break;\r
-       }\r
-      }          \r
-    } else if (ch == '\'' || ch == '"') {\r
-      // Quoting with ' ' or " ", with \ as escape character.\r
-      // Inconvenient for long strings that may contain Windows filenames.\r
-      start = ch;\r
-      ch = get(cl);\r
-      while (start) {\r
-       switch (ch) {\r
-       case NULLCHAR:\r
-         start = NULLCHAR;\r
-         break;\r
-\r
-       default:\r
-        not_special:\r
-         *q++ = ch;\r
-         ch = get(cl);\r
-         break;\r
-\r
-       case '\'':\r
-       case '\"':\r
-         if (ch == start) {\r
-           ch = get(cl);\r
-           start = NULLCHAR;\r
-           break;\r
-         } else {\r
-           goto not_special;\r
-         }\r
-\r
-       case '\\':\r
-          if (ad->argType == ArgFilename\r
-             || ad->argType == ArgSettingsFilename) {\r
-             goto not_special;\r
-         }\r
-         ch = get(cl);\r
-         switch (ch) {\r
-         case NULLCHAR:\r
-           ExitArgError("Incomplete \\ escape in value for", argName);\r
-           break;\r
-         case 'n':\r
-           *q++ = '\n';\r
-           ch = get(cl);\r
-           break;\r
-         case 'r':\r
-           *q++ = '\r';\r
-           ch = get(cl);\r
-           break;\r
-         case 't':\r
-           *q++ = '\t';\r
-           ch = get(cl);\r
-           break;\r
-         case 'b':\r
-           *q++ = '\b';\r
-           ch = get(cl);\r
-           break;\r
-         case 'f':\r
-           *q++ = '\f';\r
-           ch = get(cl);\r
-           break;\r
-         default:\r
-           octval = 0;\r
-           for (i = 0; i < 3; i++) {\r
-             if (ch >= '0' && ch <= '7') {\r
-               octval = octval*8 + (ch - '0');\r
-               ch = get(cl);\r
-             } else {\r
-               break;\r
-             }\r
-           }\r
-           if (i > 0) {\r
-             *q++ = (char) octval;\r
-           } else {\r
-             *q++ = ch;\r
-             ch = get(cl);\r
-           }\r
-           break;\r
-         }\r
-         break;\r
-       }\r
-      }\r
-    } else {\r
-      while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {\r
-       *q++ = ch;\r
-       ch = get(cl);\r
-      }\r
+    if (StrCaseCmp(name, sizeInfo[bs].name) == 0) {\r
+       *(BoardSize *)addr = bs;\r
+       return;\r
     }\r
-    *q = NULLCHAR;\r
-\r
-    switch (ad->argType) {\r
-    case ArgInt:\r
-      *(int *) ad->argLoc = atoi(argValue);\r
-      break;\r
-\r
-    case ArgFloat:\r
-      *(float *) ad->argLoc = (float) atof(argValue);\r
-      break;\r
-\r
-    case ArgString:\r
-    case ArgFilename:\r
-      *(char **) ad->argLoc = strdup(argValue);\r
-      break;\r
-\r
-    case ArgSettingsFilename:\r
-      {\r
-       char fullname[MSG_SIZ];\r
-       if (ParseSettingsFile(argValue, fullname)) {\r
-         if (ad->argLoc != NULL) {\r
-           *(char **) ad->argLoc = strdup(fullname);\r
-         }\r
-       } else {\r
-         if (ad->argLoc != NULL) {\r
-         } else {\r
-           ExitArgError("Failed to open indirection file", argValue);\r
-         }\r
-       }\r
-      }\r
-      break;\r
-\r
-    case ArgBoolean:\r
-      switch (argValue[0]) {\r
-      case 't':\r
-      case 'T':\r
-       *(Boolean *) ad->argLoc = TRUE;\r
-       break;\r
-      case 'f':\r
-      case 'F':\r
-       *(Boolean *) ad->argLoc = FALSE;\r
-       break;\r
-      default:\r
-       ExitArgError("Unrecognized boolean argument value", argValue);\r
-       break;\r
-      }\r
-      break;\r
-\r
-    case ArgColor:\r
-      *(COLORREF *)ad->argLoc = ParseColorName(argValue);\r
-      break;\r
-\r
-    case ArgAttribs: {\r
-      ColorClass cc = (ColorClass)ad->argLoc;\r
-      ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);\r
-      }\r
-      break;\r
-      \r
-    case ArgBoardSize:\r
-      *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);\r
-      break;\r
-\r
-    case ArgFont:\r
-      ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);\r
-      break;\r
-\r
-    case ArgCommSettings:\r
-      ParseCommSettings(argValue, &dcb);\r
-      break;\r
-\r
-    case ArgNone:\r
-      ExitArgError("Unrecognized argument", argValue);\r
-      break;\r
-    }\r
-  }\r
-}\r
-\r
-VOID\r
-LFfromMFP(LOGFONT* lf, MyFontParams *mfp)\r
-{\r
-  HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);\r
-  lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);\r
-  DeleteDC(hdc);\r
-  lf->lfWidth = 0;\r
-  lf->lfEscapement = 0;\r
-  lf->lfOrientation = 0;\r
-  lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;\r
-  lf->lfItalic = mfp->italic;\r
-  lf->lfUnderline = mfp->underline;\r
-  lf->lfStrikeOut = mfp->strikeout;\r
-  lf->lfCharSet = DEFAULT_CHARSET;\r
-  lf->lfOutPrecision = OUT_DEFAULT_PRECIS;\r
-  lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;\r
-  lf->lfQuality = DEFAULT_QUALITY;\r
-  lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;\r
-  strcpy(lf->lfFaceName, mfp->faceName);\r
-}\r
-\r
-VOID\r
-CreateFontInMF(MyFont *mf)\r
-{\r
-  LFfromMFP(&mf->lf, &mf->mfp);\r
-  if (mf->hf) DeleteObject(mf->hf);\r
-  mf->hf = CreateFontIndirect(&mf->lf);\r
-}\r
-\r
-VOID\r
-SetDefaultTextAttribs()\r
-{\r
-  ColorClass cc;\r
-  for (cc = (ColorClass)0; cc < NColorClasses; cc++) {\r
-    ParseAttribs(&textAttribs[cc].color, \r
-                &textAttribs[cc].effects, \r
-                defaultTextAttribs[cc]);\r
+    bs++;\r
   }\r
+  ExitArgError(_("Unrecognized board size value"), name, TRUE);\r
 }\r
 \r
-VOID\r
-SetDefaultSounds()\r
-{\r
+void\r
+LoadAllSounds()\r
+{ // [HGM] import name from appData first\r
   ColorClass cc;\r
   SoundClass sc;\r
-  for (cc = (ColorClass)0; cc < NColorClasses; cc++) {\r
+  for (cc = (ColorClass)0; cc < ColorNormal; cc++) {\r
+    textAttribs[cc].sound.name = strdup((&appData.soundShout)[cc]);\r
+    textAttribs[cc].sound.data = NULL;\r
+    MyLoadSound(&textAttribs[cc].sound);\r
+  }\r
+  for (cc = ColorNormal; cc < NColorClasses; cc++) {\r
     textAttribs[cc].sound.name = strdup("");\r
     textAttribs[cc].sound.data = NULL;\r
   }\r
   for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {\r
-    sounds[sc].name = strdup("");\r
+    sounds[sc].name = strdup((&appData.soundMove)[sc]);\r
     sounds[sc].data = NULL;\r
-  }\r
-  sounds[(int)SoundBell].name = strdup(SOUND_BELL);\r
-}\r
-\r
-VOID\r
-LoadAllSounds()\r
-{\r
-  ColorClass cc;\r
-  SoundClass sc;\r
-  for (cc = (ColorClass)0; cc < NColorClasses; cc++) {\r
-    MyLoadSound(&textAttribs[cc].sound);\r
-  }\r
-  for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {\r
     MyLoadSound(&sounds[sc]);\r
   }\r
 }\r
 \r
-VOID\r
-InitAppData(LPSTR lpCmdLine)\r
+void\r
+SetCommPortDefaults()\r
 {\r
-  int i, j;\r
-  char buf[ARG_MAX], currDir[MSG_SIZ];\r
-  char *dummy, *p;\r
-\r
-  programName = szAppName;\r
-\r
-  /* Initialize to defaults */\r
-  lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);\r
-  darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);\r
-  whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);\r
-  blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);\r
-  highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);\r
-  premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);\r
-  consoleBackgroundColor = ParseColorName(COLOR_BKGD);\r
-  SetDefaultTextAttribs();\r
-  SetDefaultSounds();\r
-  appData.movesPerSession = MOVES_PER_SESSION;\r
-  appData.initString = INIT_STRING;\r
-  appData.secondInitString = INIT_STRING;\r
-  appData.firstComputerString = COMPUTER_STRING;\r
-  appData.secondComputerString = COMPUTER_STRING;\r
-  appData.firstChessProgram = FIRST_CHESS_PROGRAM;\r
-  appData.secondChessProgram = SECOND_CHESS_PROGRAM;\r
-  appData.firstPlaysBlack = FALSE;\r
-  appData.noChessProgram = FALSE;\r
-  chessProgram = FALSE;\r
-  appData.firstHost = FIRST_HOST;\r
-  appData.secondHost = SECOND_HOST;\r
-  appData.firstDirectory = FIRST_DIRECTORY;\r
-  appData.secondDirectory = SECOND_DIRECTORY;\r
-  appData.bitmapDirectory = "";\r
-  appData.remoteShell = REMOTE_SHELL;\r
-  appData.remoteUser = "";\r
-  appData.timeDelay = TIME_DELAY;\r
-  appData.timeControl = TIME_CONTROL;\r
-  appData.timeIncrement = TIME_INCREMENT;\r
-  appData.icsActive = FALSE;\r
-  appData.icsHost = "";\r
-  appData.icsPort = ICS_PORT;\r
-  appData.icsCommPort = ICS_COMM_PORT;\r
-  appData.icsLogon = ICS_LOGON;\r
-  appData.icsHelper = "";\r
-  appData.useTelnet = FALSE;\r
-  appData.telnetProgram = TELNET_PROGRAM;\r
-  appData.gateway = "";\r
-  appData.loadGameFile = "";\r
-  appData.loadGameIndex = 0;\r
-  appData.saveGameFile = "";\r
-  appData.autoSaveGames = FALSE;\r
-  appData.loadPositionFile = "";\r
-  appData.loadPositionIndex = 1;\r
-  appData.savePositionFile = "";\r
-  appData.matchMode = FALSE;\r
-  appData.matchGames = 0;\r
-  appData.monoMode = FALSE;\r
-  appData.debugMode = FALSE;\r
-  appData.clockMode = TRUE;\r
-  boardSize = (BoardSize) -1; /* determine by screen size */\r
-  appData.Iconic = FALSE; /*unused*/\r
-  appData.searchTime = "";\r
-  appData.searchDepth = 0;\r
-  appData.showCoords = FALSE;\r
-  appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/\r
-  appData.autoCallFlag = FALSE;\r
-  appData.flipView = FALSE;\r
-  appData.autoFlipView = TRUE;\r
-  appData.cmailGameName = "";\r
-  appData.alwaysPromoteToQueen = FALSE;\r
-  appData.oldSaveStyle = FALSE;\r
-  appData.quietPlay = FALSE;\r
-  appData.showThinking = FALSE;\r
-  appData.ponderNextMove = TRUE;\r
-  appData.periodicUpdates = TRUE;\r
-  appData.popupExitMessage = TRUE;\r
-  appData.popupMoveErrors = FALSE;\r
-  appData.autoObserve = FALSE;\r
-  appData.autoComment = FALSE;\r
-  appData.animate = TRUE;\r
-  appData.animSpeed = 10;\r
-  appData.animateDragging = TRUE;\r
-  appData.highlightLastMove = TRUE;\r
-  appData.getMoveList = TRUE;\r
-  appData.testLegality = TRUE;\r
-  appData.premove = TRUE;\r
-  appData.premoveWhite = FALSE;\r
-  appData.premoveWhiteText = "";\r
-  appData.premoveBlack = FALSE;\r
-  appData.premoveBlackText = "";\r
-  appData.icsAlarm = TRUE;\r
-  appData.icsAlarmTime = 5000;\r
-  appData.autoRaiseBoard = TRUE;\r
-  appData.localLineEditing = TRUE;\r
-  appData.colorize = TRUE;\r
-  appData.reuseFirst = TRUE;\r
-  appData.reuseSecond = TRUE;\r
-  appData.blindfold = FALSE;\r
-  appData.icsEngineAnalyze = FALSE;\r
+   memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +\r
   dcb.DCBlength = sizeof(DCB);\r
   dcb.BaudRate = 9600;\r
   dcb.fBinary = TRUE;\r
@@ -1858,482 +1394,138 @@ InitAppData(LPSTR lpCmdLine)
   dcb.fNull = FALSE;\r
   dcb.fRtsControl = RTS_CONTROL_ENABLE;\r
   dcb.fAbortOnError = FALSE;\r
-  /* Microsoft SDK >= Feb. 2003 (MS VS >= 2002) */\r
-  #if (defined(_MSC_VER) && _MSC_VER <= 1200) \r
-       //dcb.wReserved = 0;\r
-  #else\r
-    dcb.wReserved = 0;\r
-  #endif\r
   dcb.ByteSize = 7;\r
   dcb.Parity = SPACEPARITY;\r
   dcb.StopBits = ONESTOPBIT;\r
-  settingsFileName = SETTINGS_FILE;\r
-  saveSettingsOnExit = TRUE;\r
-  boardX = CW_USEDEFAULT;\r
-  boardY = CW_USEDEFAULT;\r
-  consoleX = CW_USEDEFAULT; \r
-  consoleY = CW_USEDEFAULT; \r
-  consoleW = CW_USEDEFAULT;\r
-  consoleH = CW_USEDEFAULT;\r
-  analysisX = CW_USEDEFAULT; \r
-  analysisY = CW_USEDEFAULT; \r
-  analysisW = CW_USEDEFAULT;\r
-  analysisH = CW_USEDEFAULT;\r
-  commentX = CW_USEDEFAULT; \r
-  commentY = CW_USEDEFAULT; \r
-  commentW = CW_USEDEFAULT;\r
-  commentH = CW_USEDEFAULT;\r
-  editTagsX = CW_USEDEFAULT; \r
-  editTagsY = CW_USEDEFAULT; \r
-  editTagsW = CW_USEDEFAULT;\r
-  editTagsH = CW_USEDEFAULT;\r
-  gameListX = CW_USEDEFAULT; \r
-  gameListY = CW_USEDEFAULT; \r
-  gameListW = CW_USEDEFAULT;\r
-  gameListH = CW_USEDEFAULT;\r
-  icsTextMenuString = ICS_TEXT_MENU_DEFAULT;\r
-  icsNames = ICS_NAMES;\r
-  firstChessProgramNames = FCP_NAMES;\r
-  secondChessProgramNames = SCP_NAMES;\r
-  appData.initialMode = "";\r
-  appData.variant = "normal";\r
-  appData.firstProtocolVersion = PROTOVER;\r
-  appData.secondProtocolVersion = PROTOVER;\r
-  appData.showButtonBar = TRUE;\r
-\r
-   /* [AS] New properties (see comments in header file) */\r
-  appData.firstScoreIsAbsolute = FALSE;\r
-  appData.secondScoreIsAbsolute = FALSE;\r
-  appData.saveExtendedInfoInPGN = FALSE;\r
-  appData.hideThinkingFromHuman = FALSE;\r
-  appData.liteBackTextureFile = "";\r
-  appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;\r
-  appData.darkBackTextureFile = "";\r
-  appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;\r
-  appData.renderPiecesWithFont = "";\r
-  appData.fontToPieceTable = "";\r
-  appData.fontBackColorWhite = 0;\r
-  appData.fontForeColorWhite = 0;\r
-  appData.fontBackColorBlack = 0;\r
-  appData.fontForeColorBlack = 0;\r
-  appData.fontPieceSize = 80;\r
-  appData.overrideLineGap = 1;\r
-  appData.adjudicateLossThreshold = 0;\r
-  appData.delayBeforeQuit = 0;\r
-  appData.delayAfterQuit = 0;\r
-  appData.nameOfDebugFile = "winboard.debug";\r
-  appData.pgnEventHeader = "Computer Chess Game";\r
-  appData.defaultFrcPosition = -1;\r
-  appData.gameListTags = GLT_DEFAULT_TAGS;\r
-  appData.saveOutOfBookInfo = TRUE;\r
-  appData.showEvalInMoveHistory = TRUE;\r
-  appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );\r
-  appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );\r
-  appData.highlightMoveWithArrow = FALSE;\r
-  appData.highlightArrowColor = ParseColorName( "#FFFF80" );\r
-  appData.useStickyWindows = TRUE;\r
-  appData.adjudicateDrawMoves = 0;\r
-  appData.autoDisplayComment = TRUE;\r
-  appData.autoDisplayTags = TRUE;\r
-  appData.firstIsUCI = FALSE;\r
-  appData.secondIsUCI = FALSE;\r
-  appData.firstHasOwnBookUCI = TRUE;\r
-  appData.secondHasOwnBookUCI = TRUE;\r
-  appData.polyglotDir = "";\r
-  appData.usePolyglotBook = FALSE;\r
-  appData.polyglotBook = "";\r
-  appData.defaultHashSize = 64;\r
-  appData.defaultCacheSizeEGTB = 4;\r
-  appData.defaultPathEGTB = "c:\\egtb";\r
-  appData.firstOptions = "";\r
-  appData.secondOptions = "";\r
-\r
-  InitWindowPlacement( &wpMoveHistory );\r
-  InitWindowPlacement( &wpEvalGraph );\r
-  InitWindowPlacement( &wpEngineOutput );\r
-\r
-  /* [HGM] User-selectable board size, adjudication control, miscellaneous */\r
-  appData.NrFiles      = -1;\r
-  appData.NrRanks      = -1;\r
-  appData.holdingsSize = -1;\r
-  appData.testClaims   = FALSE;\r
-  appData.checkMates   = FALSE;\r
-  appData.materialDraws= FALSE;\r
-  appData.trivialDraws = FALSE;\r
-  appData.ruleMoves    = 51;\r
-  appData.drawRepeats  = 6;\r
-  appData.matchPause   = 10000;\r
-  appData.alphaRank    = FALSE;\r
-  appData.allWhite     = FALSE;\r
-  appData.upsideDown   = FALSE;\r
-  appData.serverPause  = 15;\r
-  appData.serverMovesName   = NULL;\r
-  appData.suppressLoadMoves = FALSE;\r
-  appData.firstTimeOdds  = 1;\r
-  appData.secondTimeOdds = 1;\r
-  appData.firstAccumulateTC  = 1; // combine previous and current sessions\r
-  appData.secondAccumulateTC = 1;\r
-  appData.firstNPS  = -1; // [HGM] nps: use wall-clock time\r
-  appData.secondNPS = -1;\r
-  appData.engineComments = 1;\r
-  appData.smpCores = 1; // [HGM] SMP: max nr of cores\r
-  appData.egtFormats = "";\r
-\r
-#ifdef ZIPPY\r
-  appData.zippyTalk = ZIPPY_TALK;\r
-  appData.zippyPlay = ZIPPY_PLAY;\r
-  appData.zippyLines = ZIPPY_LINES;\r
-  appData.zippyPinhead = ZIPPY_PINHEAD;\r
-  appData.zippyPassword = ZIPPY_PASSWORD;\r
-  appData.zippyPassword2 = ZIPPY_PASSWORD2;\r
-  appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;\r
-  appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;\r
-  appData.zippyUseI = ZIPPY_USE_I;\r
-  appData.zippyBughouse = ZIPPY_BUGHOUSE;\r
-  appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;\r
-  appData.zippyGameEnd = ZIPPY_GAME_END;\r
-  appData.zippyGameStart = ZIPPY_GAME_START;\r
-  appData.zippyAdjourn = ZIPPY_ADJOURN;\r
-  appData.zippyAbort = ZIPPY_ABORT;\r
-  appData.zippyVariants = ZIPPY_VARIANTS;\r
-  appData.zippyMaxGames = ZIPPY_MAX_GAMES;\r
-  appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;\r
-#endif\r
-\r
-  /* 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
 \r
-  /* Parse command line */\r
-  ParseArgs(StringGet, &lpCmdLine);\r
+// [HGM] args: these three cases taken out to stay in front-end\r
+void\r
+SaveFontArg(FILE *f, ArgDescriptor *ad)\r
+{      // in WinBoard every board size has its own font, and the "argLoc" identifies the table,\r
+       // while the curent board size determines the element. This system should be ported to XBoard.\r
+       // What the table contains pointers to, and how to print the font description, remains platform-dependent\r
+        int bs;\r
+       for (bs=0; bs<NUM_SIZES; bs++) {\r
+         MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;\r
+          fprintf(f, "/size=%s ", sizeInfo[bs].name);\r
+         fprintf(f, "/%s=\"%s:%g%s%s%s%s%sc%d\"\n",\r
+           ad->argName, mfp->faceName, mfp->pointSize,\r
+            mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",\r
+           mfp->bold ? "b" : "",\r
+           mfp->italic ? "i" : "",\r
+           mfp->underline ? "u" : "",\r
+           mfp->strikeout ? "s" : "",\r
+            (int)mfp->charset);\r
+       }\r
+      }\r
 \r
-  /* [HGM] make sure board size is acceptable */\r
-  if(appData.NrFiles > BOARD_SIZE ||\r
-     appData.NrRanks > BOARD_SIZE   )\r
-      DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);\r
+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
-  /* [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
+void\r
+SaveAttribsArg(FILE *f, ArgDescriptor *ad)\r
+{      // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though\r
+       MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];\r
+       fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,\r
+          (ta->effects & CFE_BOLD) ? "b" : "",\r
+          (ta->effects & CFE_ITALIC) ? "i" : "",\r
+          (ta->effects & CFE_UNDERLINE) ? "u" : "",\r
+          (ta->effects & CFE_STRIKEOUT) ? "s" : "",\r
+          (ta->effects) ? " " : "",\r
+         ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);\r
       }\r
-  }\r
 \r
+void\r
+SaveColor(FILE *f, ArgDescriptor *ad)\r
+{      // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?\r
+       COLORREF color = *(COLORREF *)colorVariable[(int)ad->argLoc];\r
+       fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName, \r
+         color&0xff, (color>>8)&0xff, (color>>16)&0xff);\r
+}\r
 \r
-  /* 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
+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
-  /* 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
+void\r
+ParseCommPortSettings(char *s)\r
+{ // wrapper to keep dcb from back-end\r
+  ParseCommSettings(s, &dcb);\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
+void\r
+GetWindowCoords()\r
+{ // wrapper to shield use of window handles from back-end (make addressible by number?)\r
+  GetActualPlacement(hwndMain, &wpMain);\r
+  GetActualPlacement(hwndConsole, &wpConsole);\r
+  GetActualPlacement(commentDialog, &wpComment);\r
+  GetActualPlacement(editTagsDialog, &wpTags);\r
+  GetActualPlacement(gameListDialog, &wpGameList);\r
+  GetActualPlacement(moveHistoryDialog, &wpMoveHistory);\r
+  GetActualPlacement(evalGraphDialog, &wpEvalGraph);\r
+  GetActualPlacement(engineOutputDialog, &wpEngineOutput);\r
+}\r
 \r
-  /* 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
+void\r
+PrintCommPortSettings(FILE *f, char *name)\r
+{ // wrapper to shield back-end from DCB\r
+      PrintCommSettings(f, name, &dcb);\r
+}\r
 \r
-  p = icsTextMenuString;\r
-  if (p[0] == '@') {\r
-    FILE* f = fopen(p + 1, "r");\r
-    if (f == NULL) {\r
-      DisplayFatalError(p + 1, errno, 2);\r
-      return;\r
+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
-    i = fread(buf, 1, sizeof(buf)-1, f);\r
-    fclose(f);\r
-    buf[i] = NULLCHAR;\r
-    p = buf;\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
-  ParseIcsTextMenu(strdup(p));\r
+  return (int) SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);\r
 }\r
 \r
-\r
-VOID\r
-InitMenuChecks()\r
+int\r
+MyGetFullPathName(char *name, char *fullname)\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
+  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
-SaveSettings(char* name)\r
+void\r
+PopUpStartupDialog()\r
 {\r
-  FILE *f;\r
-  ArgDescriptor *ad;\r
-  WINDOWPLACEMENT wp;\r
-  char dir[MSG_SIZ];\r
-\r
-  if (!hwndMain) 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 %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);\r
-  fprintf(f, ";\n");\r
-  fprintf(f, "; You can edit the values of options that are already set in this file,\n");\r
-  fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");\r
-  fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");\r
-  fprintf(f, ";\n");\r
-\r
-  wp.length = sizeof(WINDOWPLACEMENT);\r
-  GetWindowPlacement(hwndMain, &wp);\r
-  boardX = wp.rcNormalPosition.left;\r
-  boardY = wp.rcNormalPosition.top;\r
-\r
-  if (hwndConsole) {\r
-    GetWindowPlacement(hwndConsole, &wp);\r
-    consoleX = wp.rcNormalPosition.left;\r
-    consoleY = wp.rcNormalPosition.top;\r
-    consoleW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
-    consoleH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
-  }\r
-\r
-  if (analysisDialog) {\r
-    GetWindowPlacement(analysisDialog, &wp);\r
-    analysisX = wp.rcNormalPosition.left;\r
-    analysisY = wp.rcNormalPosition.top;\r
-    analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
-    analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
-  }\r
-\r
-  if (commentDialog) {\r
-    GetWindowPlacement(commentDialog, &wp);\r
-    commentX = wp.rcNormalPosition.left;\r
-    commentY = wp.rcNormalPosition.top;\r
-    commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
-    commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
-  }\r
-\r
-  if (editTagsDialog) {\r
-    GetWindowPlacement(editTagsDialog, &wp);\r
-    editTagsX = wp.rcNormalPosition.left;\r
-    editTagsY = wp.rcNormalPosition.top;\r
-    editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
-    editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
-  }\r
-\r
-  if (gameListDialog) {\r
-    GetWindowPlacement(gameListDialog, &wp);\r
-    gameListX = wp.rcNormalPosition.left;\r
-    gameListY = wp.rcNormalPosition.top;\r
-    gameListW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
-    gameListH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
-  }\r
-\r
-  /* [AS] Move history */\r
-  wpMoveHistory.visible = MoveHistoryIsUp();\r
-  \r
-  if( moveHistoryDialog ) {\r
-    GetWindowPlacement(moveHistoryDialog, &wp);\r
-    wpMoveHistory.x = wp.rcNormalPosition.left;\r
-    wpMoveHistory.y = wp.rcNormalPosition.top;\r
-    wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
-    wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
-  }\r
-\r
-  /* [AS] Eval graph */\r
-  wpEvalGraph.visible = EvalGraphIsUp();\r
-\r
-  if( evalGraphDialog ) {\r
-    GetWindowPlacement(evalGraphDialog, &wp);\r
-    wpEvalGraph.x = wp.rcNormalPosition.left;\r
-    wpEvalGraph.y = wp.rcNormalPosition.top;\r
-    wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
-    wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
-  }\r
-\r
-  /* [AS] Engine output */\r
-  wpEngineOutput.visible = EngineOutputIsUp();\r
-\r
-  if( engineOutputDialog ) {\r
-    GetWindowPlacement(engineOutputDialog, &wp);\r
-    wpEngineOutput.x = wp.rcNormalPosition.left;\r
-    wpEngineOutput.y = wp.rcNormalPosition.top;\r
-    wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
-    wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
-  }\r
-\r
-  for (ad = argDescriptors; ad->argName != NULL; ad++) {\r
-    if (!ad->save) continue;\r
-    switch (ad->argType) {\r
-    case ArgString:\r
-      {\r
-       char *p = *(char **)ad->argLoc;\r
-       if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {\r
-         /* Quote multiline values or \-containing values\r
-            with { } if possible */\r
-         fprintf(f, "/%s={%s}\n", ad->argName, p);\r
-       } else {\r
-         /* Else quote with " " */\r
-         fprintf(f, "/%s=\"", ad->argName);\r
-         while (*p) {\r
-           if (*p == '\n') fprintf(f, "\n");\r
-           else if (*p == '\r') fprintf(f, "\\r");\r
-           else if (*p == '\t') fprintf(f, "\\t");\r
-           else if (*p == '\b') fprintf(f, "\\b");\r
-           else if (*p == '\f') fprintf(f, "\\f");\r
-           else if (*p < ' ') fprintf(f, "\\%03o", *p);\r
-           else if (*p == '\"') fprintf(f, "\\\"");\r
-           else if (*p == '\\') fprintf(f, "\\\\");\r
-           else putc(*p, f);\r
-           p++;\r
-         }\r
-         fprintf(f, "\"\n");\r
-       }\r
-      }\r
-      break;\r
-    case ArgInt:\r
-      fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);\r
-      break;\r
-    case ArgFloat:\r
-      fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);\r
-      break;\r
-    case ArgBoolean:\r
-      fprintf(f, "/%s=%s\n", ad->argName, \r
-       (*(Boolean *)ad->argLoc) ? "true" : "false");\r
-      break;\r
-    case ArgTrue:\r
-      if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);\r
-      break;\r
-    case ArgFalse:\r
-      if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);\r
-      break;\r
-    case ArgColor:\r
-      {\r
-       COLORREF color = *(COLORREF *)ad->argLoc;\r
-       fprintf(f, "/%s=#%02x%02x%02x\n", ad->argName, \r
-         color&0xff, (color>>8)&0xff, (color>>16)&0xff);\r
-      }\r
-      break;\r
-    case ArgAttribs:\r
-      {\r
-       MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];\r
-       fprintf(f, "/%s=\"%s%s%s%s%s#%02x%02x%02x\"\n", ad->argName,\r
-          (ta->effects & CFE_BOLD) ? "b" : "",\r
-          (ta->effects & CFE_ITALIC) ? "i" : "",\r
-          (ta->effects & CFE_UNDERLINE) ? "u" : "",\r
-          (ta->effects & CFE_STRIKEOUT) ? "s" : "",\r
-          (ta->effects) ? " " : "",\r
-         ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);\r
-      }\r
-      break;\r
-    case ArgFilename:\r
-      if (strchr(*(char **)ad->argLoc, '\"')) {\r
-       fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);\r
-      } else {\r
-       fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);\r
-      }\r
-      break;\r
-    case ArgBoardSize:\r
-      fprintf(f, "/%s=%s\n", ad->argName,\r
-             sizeInfo[*(BoardSize *)ad->argLoc].name);\r
-      break;\r
-    case ArgFont:\r
-      {\r
-        int bs;\r
-       for (bs=0; bs<NUM_SIZES; bs++) {\r
-         MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;\r
-          fprintf(f, "/size=%s ", sizeInfo[bs].name);\r
-         fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",\r
-           ad->argName, mfp->faceName, mfp->pointSize,\r
-            mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",\r
-           mfp->bold ? "b" : "",\r
-           mfp->italic ? "i" : "",\r
-           mfp->underline ? "u" : "",\r
-           mfp->strikeout ? "s" : "");\r
-       }\r
-      }\r
-      break;\r
-    case ArgCommSettings:\r
-      PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);\r
-    }\r
-  }\r
-  fclose(f);\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
 /*---------------------------------------------------------------------------*\\r
  *\r
  * GDI board drawing routines\r
@@ -2847,7 +2039,7 @@ void CreatePiecesFromFont()
                 }\r
                 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {\r
                     /* Good Companion (Some characters get warped as literal :-( */\r
-                    char s[] = "1cmWG0ñueOS¯®oYI23wgQU";\r
+                    char s[] = "1cmWG0??S??oYI23wgQU";\r
                     s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;\r
                     SetCharTable(pieceToFontChar, s);\r
                 }\r
@@ -2859,57 +2051,10 @@ void CreatePiecesFromFont()
 \r
             /* Create bitmaps */\r
             hfont_old = SelectObject( hdc, hPieceFont );\r
-#if 0\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );\r
-\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WSG );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WV );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WAB );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WD );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WL );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WS );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BSG );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BV );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BAB );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BD );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BL );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BS );\r
-#else\r
            for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */\r
                if(PieceToChar((ChessSquare)i) != '.')     /* skip unused pieces         */\r
                    CreatePieceMaskFromFont( hdc_window, hdc, i );\r
-#endif\r
+\r
             SelectObject( hdc, hfont_old );\r
 \r
             fontBitmapSquareSize = squareSize;\r
@@ -2930,11 +2075,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
@@ -2951,7 +2096,7 @@ InsertInPalette(COLORREF color)
   LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);\r
 \r
   if (pLogPal->palNumEntries++ >= PALETTESIZE) {\r
-    DisplayFatalError("Too many colors", 0, 1);\r
+    DisplayFatalError(_("Too many colors"), 0, 1);\r
     pLogPal->palNumEntries--;\r
     return;\r
   }\r
@@ -2997,7 +2142,8 @@ InitDrawingColors()
   whitePieceBrush = CreateSolidBrush(whitePieceColor);\r
   blackPieceBrush = CreateSolidBrush(blackPieceColor);\r
   iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));\r
-\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
@@ -3039,6 +2185,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
@@ -3052,7 +2199,7 @@ InitDrawingSizes(BoardSize boardSize, int flags)
   char buf[MSG_SIZ];\r
   char *str;\r
   HMENU hmenu = GetMenu(hwndMain);\r
-  RECT crect, wrect;\r
+  RECT crect, wrect, oldRect;\r
   int offby;\r
   LOGBRUSH logbrush;\r
 \r
@@ -3062,6 +2209,11 @@ InitDrawingSizes(BoardSize boardSize, int flags)
   /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */\r
   if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;\r
 \r
+  oldRect.left = wpMain.x; //[HGM] placement: remember previous window params\r
+  oldRect.top = wpMain.y;\r
+  oldRect.right = wpMain.x + wpMain.width;\r
+  oldRect.bottom = wpMain.y + wpMain.height;\r
+\r
   tinyLayout = sizeInfo[boardSize].tinyLayout;\r
   smallLayout = sizeInfo[boardSize].smallLayout;\r
   squareSize = sizeInfo[boardSize].squareSize;\r
@@ -3073,7 +2225,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
@@ -3082,11 +2234,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
@@ -3097,20 +2249,20 @@ 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
 \r
   /* Compute where everything goes */\r
-  if(first.programLogo || second.programLogo) {\r
+  if((first.programLogo || second.programLogo) && !tinyLayout) {\r
         /* [HGM] logo: if either logo is on, reserve space for it */\r
        logoHeight =  2*clockSize.cy;\r
        leftLogoRect.left   = OUTER_MARGIN;\r
@@ -3124,25 +2276,27 @@ InitDrawingSizes(BoardSize boardSize, int flags)
        rightLogoRect.bottom = OUTER_MARGIN + logoHeight;\r
 \r
 \r
-    blackRect.left = leftLogoRect.right;\r
-    blackRect.right = rightLogoRect.left;\r
-    blackRect.top = OUTER_MARGIN;\r
-    blackRect.bottom = blackRect.top + clockSize.cy;\r
+    whiteRect.left = leftLogoRect.right;\r
+    whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;\r
+    whiteRect.top = OUTER_MARGIN;\r
+    whiteRect.bottom = whiteRect.top + logoHeight;\r
 \r
-    whiteRect.left = blackRect.left ;\r
-    whiteRect.right = blackRect.right;\r
-    whiteRect.top = blackRect.bottom;\r
-    whiteRect.bottom = leftLogoRect.bottom;\r
+    blackRect.right = rightLogoRect.left;\r
+    blackRect.left = whiteRect.right + INNER_MARGIN;\r
+    blackRect.top = whiteRect.top;\r
+    blackRect.bottom = whiteRect.bottom;\r
   } else {\r
     whiteRect.left = OUTER_MARGIN;\r
     whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;\r
-    whiteRect.top = OUTER_MARGIN + logoHeight;\r
+    whiteRect.top = OUTER_MARGIN;\r
     whiteRect.bottom = whiteRect.top + clockSize.cy;\r
 \r
     blackRect.left = whiteRect.right + INNER_MARGIN;\r
     blackRect.right = blackRect.left + boardWidth/2 - 1;\r
     blackRect.top = whiteRect.top;\r
     blackRect.bottom = whiteRect.bottom;\r
+\r
+    logoHeight = 0; // [HGM] logo: suppress logo after change to tiny layout!\r
   }\r
 \r
   messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;\r
@@ -3162,43 +2316,56 @@ InitDrawingSizes(BoardSize boardSize, int flags)
 \r
   sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;\r
   sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;\r
-  if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only\r
-  winWidth = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;\r
-  winHeight = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +\r
+  oldBoardSize = boardSize;\r
+  oldTinyLayout = tinyLayout;\r
+  winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;\r
+  winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +\r
     GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;\r
+  winW *= 1 + twoBoards;\r
+  if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only\r
+  wpMain.width = winW;  // [HGM] placement: set through temporary which can used by initial sizing choice\r
+  wpMain.height = winH; //       without disturbing window attachments\r
   GetWindowRect(hwndMain, &wrect);\r
-  SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,\r
+  SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,\r
               SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);\r
+\r
+  // [HGM] placement: let attached windows follow size change.\r
+  ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, moveHistoryDialog, &wpMoveHistory );\r
+  ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, evalGraphDialog, &wpEvalGraph );\r
+  ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, engineOutputDialog, &wpEngineOutput );\r
+  ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, gameListDialog, &wpGameList );\r
+  ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, hwndConsole, &wpConsole );\r
+\r
   /* compensate if menu bar wrapped */\r
   GetClientRect(hwndMain, &crect);\r
   offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;\r
-  winHeight += offby;\r
+  wpMain.height += offby;\r
   switch (flags) {\r
   case WMSZ_TOPLEFT:\r
     SetWindowPos(hwndMain, NULL, \r
-                 wrect.right - winWidth, wrect.bottom - winHeight, \r
-                 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);\r
+                 wrect.right - wpMain.width, wrect.bottom - wpMain.height, \r
+                 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);\r
     break;\r
 \r
   case WMSZ_TOPRIGHT:\r
   case WMSZ_TOP:\r
     SetWindowPos(hwndMain, NULL, \r
-                 wrect.left, wrect.bottom - winHeight, \r
-                 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);\r
+                 wrect.left, wrect.bottom - wpMain.height, \r
+                 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);\r
     break;\r
 \r
   case WMSZ_BOTTOMLEFT:\r
   case WMSZ_LEFT:\r
     SetWindowPos(hwndMain, NULL, \r
-                 wrect.right - winWidth, wrect.top, \r
-                 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);\r
+                 wrect.right - wpMain.width, wrect.top, \r
+                 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);\r
     break;\r
 \r
   case WMSZ_BOTTOMRIGHT:\r
   case WMSZ_BOTTOM:\r
   case WMSZ_RIGHT:\r
   default:\r
-    SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,\r
+    SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,\r
                SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);\r
     break;\r
   }\r
@@ -3216,7 +2383,7 @@ InitDrawingSizes(BoardSize boardSize, int flags)
                     boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),\r
                     messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,\r
                     (HMENU) buttonDesc[i].id,\r
-                    (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);\r
+                    (HINSTANCE) GetWindowLongPtr(hwndMain, GWLP_HINSTANCE), NULL);\r
       if (tinyLayout) {\r
        SendMessage(buttonDesc[i].hwnd, WM_SETFONT, \r
                    (WPARAM)font[boardSize][MESSAGE_FONT]->hf,\r
@@ -3225,7 +2392,7 @@ InitDrawingSizes(BoardSize boardSize, int flags)
       if (buttonDesc[i].id == IDM_Pause)\r
        hwndPause = buttonDesc[i].hwnd;\r
       buttonDesc[i].wndproc = (WNDPROC)\r
-       SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);\r
+       SetWindowLongPtr(buttonDesc[i].hwnd, GWLP_WNDPROC, (LONG_PTR) ButtonProc);\r
     }\r
   }\r
   if (gridPen != NULL) DeleteObject(gridPen);\r
@@ -3254,7 +2421,6 @@ InitDrawingSizes(BoardSize boardSize, int flags)
        boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));\r
       gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +\r
         BOARD_WIDTH * (squareSize + lineGap);\r
-       lineGap / 2 + (i * (squareSize + lineGap));\r
       gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;\r
     }\r
     for (i = 0; i < BOARD_WIDTH + 1; i++) {\r
@@ -3279,8 +2445,6 @@ InitDrawingSizes(BoardSize boardSize, int flags)
 \r
 \r
 /*  if (boardSize == oldBoardSize) return; [HGM] variant might have changed */\r
-  oldBoardSize = boardSize;\r
-  oldTinyLayout = tinyLayout;\r
 \r
   /* Load piece bitmaps for this board size */\r
   for (i=0; i<=2; i++) {\r
@@ -3309,7 +2473,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
@@ -3336,14 +2500,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
@@ -3519,8 +2693,8 @@ SquareToPos(int row, int column, int * x, int * y)
 VOID\r
 DrawCoordsOnDC(HDC hdc)\r
 {\r
-  static char files[24] = {'0', '1','2','3','4','5','6','7','8','9','0','1','1','0','9','8','7','6','5','4','3','2','1','0'};\r
-  static char ranks[24] = {'l', 'k','j','i','h','g','f','e','d','c','b','a','a','b','c','d','e','f','g','h','i','j','k','l'};\r
+  static char files[] = "0123456789012345678901221098765432109876543210";\r
+  static char ranks[] = "wvutsrqponmlkjihgfedcbaabcdefghijklmnopqrstuvw";\r
   char str[2] = { NULLCHAR, NULLCHAR };\r
   int oldMode, oldAlign, x, y, start, i;\r
   HFONT oldFont;\r
@@ -3529,7 +2703,7 @@ DrawCoordsOnDC(HDC hdc)
   if (!appData.showCoords)\r
     return;\r
 \r
-  start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;\r
+  start = flipView ? 1-(ONE!='1') : 45+(ONE!='1')-BOARD_HEIGHT;\r
 \r
   oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));\r
   oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));\r
@@ -3546,7 +2720,7 @@ DrawCoordsOnDC(HDC hdc)
     y += squareSize + lineGap;\r
   }\r
 \r
-  start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;\r
+  start = flipView ? 23-(BOARD_RGHT-BOARD_LEFT) : 23;\r
 \r
   SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);\r
   for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {\r
@@ -3604,23 +2778,14 @@ DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
 }\r
 \r
 VOID\r
-DrawHighlightsOnDC(HDC hdc)\r
+DrawHighlightsOnDC(HDC hdc, HighlightInfo *h, int pen)\r
 {\r
   int i;\r
   for (i=0; i<2; i++) {\r
-    if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) \r
+    if (h->sq[i].x >= 0 && h->sq[i].y >= 0) \r
       DrawHighlightOnDC(hdc, TRUE,\r
-                       highlightInfo.sq[i].x, highlightInfo.sq[i].y,\r
-                       HIGHLIGHT_PEN);\r
-  }\r
-  for (i=0; i<2; i++) {\r
-    if (premoveHighlightInfo.sq[i].x >= 0 && \r
-       premoveHighlightInfo.sq[i].y >= 0) {\r
-       DrawHighlightOnDC(hdc, TRUE,\r
-                         premoveHighlightInfo.sq[i].x, \r
-                         premoveHighlightInfo.sq[i].y,\r
-                         PREMOVE_PEN);\r
-    }\r
+                       h->sq[i].x, h->sq[i].y,\r
+                       pen);\r
   }\r
 }\r
 \r
@@ -3637,7 +2802,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
@@ -3646,6 +2811,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
@@ -3655,6 +2823,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
@@ -3674,8 +2845,8 @@ DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y,
   } else {\r
     tmpSize = squareSize;\r
     if(minorSize &&\r
-        (piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper ||\r
-         piece >= (int)BlackNightrider && piece <= BlackGrasshopper)  ) {\r
+        ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||\r
+         (piece >= (int)BlackNightrider && piece <= BlackGrasshopper))  ) {\r
       /* [HGM] no bitmap available for promoted pieces in Crazyhouse        */\r
       /* Bitmaps of smaller size are substituted, but we have to align them */\r
       x += (squareSize - minorSize)>>1;\r
@@ -3691,35 +2862,13 @@ DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y,
         StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);\r
       else\r
         BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);\r
-#if 0\r
-      /* Use black piece color for outline of white pieces */\r
-      /* Not sure this looks really good (though xboard does it).\r
-        Maybe better to have another selectable color, default black */\r
-      SelectObject(hdc, blackPieceBrush); /* could have own brush */\r
-      SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));\r
-      BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);\r
-#else\r
       /* Use black for outline of white pieces */\r
       SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));\r
       if(appData.upsideDown && color==flipView)\r
         StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);\r
       else\r
         BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);\r
-#endif\r
     } else {\r
-#if 0\r
-      /* Use white piece color for details of black pieces */\r
-      /* Requires filled-in solid bitmaps (BLACK_PIECE class); the\r
-        WHITE_PIECE ones aren't always the right shape. */\r
-      /* Not sure this looks really good (though xboard does it).\r
-        Maybe better to have another selectable color, default medium gray? */\r
-      oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));\r
-      oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */\r
-      BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);\r
-      SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));\r
-      SelectObject(hdc, blackPieceBrush);\r
-      BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);\r
-#else\r
       /* Use square color for details of black pieces */\r
       oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));\r
       oldBrush = SelectObject(hdc, blackPieceBrush);\r
@@ -3727,7 +2876,6 @@ DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y,
         StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);\r
       else\r
         BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);\r
-#endif\r
     }\r
     SelectObject(hdc, oldBrush);\r
     SelectObject(tmphdc, oldBitmap);\r
@@ -3787,7 +2935,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
@@ -3795,7 +2949,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
@@ -3806,7 +2966,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
@@ -3830,50 +2990,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
@@ -3890,8 +3050,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
@@ -3902,20 +3062,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
@@ -3940,20 +3102,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
@@ -3963,7 +3125,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
@@ -4085,7 +3247,7 @@ BOOL DrawPositionNeedsFullRepaint()
         but animation is fast enough that it's difficult to notice.\r
     */\r
     if( animInfo.piece == EmptySquare ) {\r
-        if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {\r
+        if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() /*&& HasHighlightInfo()*/ ) {\r
             result = TRUE;\r
         }\r
     }\r
@@ -4105,8 +3267,8 @@ DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
   if( liteBackTexture != NULL || darkBackTexture != NULL ) {\r
       static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */\r
       if( backTextureSquareSize != squareSize \r
-       || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {\r
-         backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;\r
+       || backTextureBoardSize != BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT) {\r
+         backTextureBoardSize = BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT;\r
           backTextureSquareSize = squareSize;\r
           RebuildTextureSquareInfo();\r
       }\r
@@ -4209,22 +3371,25 @@ void fputDW(FILE *f, int x)
 #define MAX_CLIPS 200   /* more than enough */\r
 \r
 VOID\r
-DrawLogoOnDC(HDC hdc, RECT logoRect, ChessProgramState *cps)\r
+DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)\r
 {\r
-  HBITMAP bufferBitmap;\r
+//  HBITMAP bufferBitmap;\r
   BITMAP bi;\r
-  RECT Rect;\r
+//  RECT Rect;\r
   HDC tmphdc;\r
   HBITMAP hbm;\r
   int w = 100, h = 50;\r
 \r
-  if(cps->programLogo == NULL) return;\r
+  if(logo == NULL) {\r
+    if(!logoHeight) return;\r
+    FillRect( hdc, &logoRect, whitePieceBrush );\r
+  }\r
 //  GetClientRect(hwndMain, &Rect);\r
 //  bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,\r
 //                                     Rect.bottom-Rect.top+1);\r
   tmphdc = CreateCompatibleDC(hdc);\r
-  hbm = SelectObject(tmphdc, (HBITMAP) cps->programLogo);\r
-  if( GetObject( cps->programLogo, sizeof(bi), &bi ) > 0 ) {\r
+  hbm = SelectObject(tmphdc, logo);\r
+  if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {\r
             w = bi.bmWidth;\r
             h = bi.bmHeight;\r
   }\r
@@ -4235,12 +3400,119 @@ DrawLogoOnDC(HDC hdc, RECT logoRect, ChessProgramState *cps)
 }\r
 \r
 VOID\r
+DisplayLogos()\r
+{\r
+  if(logoHeight) {\r
+       HDC hdc = GetDC(hwndMain);\r
+       HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;\r
+       if(appData.autoLogo) {\r
+         \r
+         switch(gameMode) { // pick logos based on game mode\r
+           case IcsObserving:\r
+               whiteLogo = second.programLogo; // ICS logo\r
+               blackLogo = second.programLogo;\r
+           default:\r
+               break;\r
+           case IcsPlayingWhite:\r
+               if(!appData.zippyPlay) whiteLogo = userLogo;\r
+               blackLogo = second.programLogo; // ICS logo\r
+               break;\r
+           case IcsPlayingBlack:\r
+               whiteLogo = second.programLogo; // ICS logo\r
+               blackLogo = appData.zippyPlay ? first.programLogo : userLogo;\r
+               break;\r
+           case TwoMachinesPlay:\r
+               if(first.twoMachinesColor[0] == 'b') {\r
+                   whiteLogo = second.programLogo;\r
+                   blackLogo = first.programLogo;\r
+               }\r
+               break;\r
+           case MachinePlaysWhite:\r
+               blackLogo = userLogo;\r
+               break;\r
+           case MachinePlaysBlack:\r
+               whiteLogo = userLogo;\r
+               blackLogo = first.programLogo;\r
+         }\r
+       }\r
+       DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);\r
+       DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);\r
+       ReleaseDC(hwndMain, hdc);\r
+  }\r
+}\r
+\r
+void\r
+UpdateLogos(int display)\r
+{ // called after loading new engine(s), in tourney or from menu\r
+  LoadLogo(&first, 0, FALSE);\r
+  LoadLogo(&second, 1, appData.icsActive);\r
+  InitDrawingSizes(-2, 0); // adapt layout of board window to presence/absence of logos\r
+  if(display) DisplayLogos();\r
+}\r
+\r
+static HDC hdcSeek;\r
+\r
+// [HGM] seekgraph\r
+void DrawSeekAxis( int x, int y, int xTo, int yTo )\r
+{\r
+    POINT stPt;\r
+    HPEN hp = SelectObject( hdcSeek, gridPen );\r
+    MoveToEx( hdcSeek, boardRect.left+x, boardRect.top+y, &stPt );\r
+    LineTo( hdcSeek, boardRect.left+xTo, boardRect.top+yTo );\r
+    SelectObject( hdcSeek, hp );\r
+}\r
+\r
+// front-end wrapper for drawing functions to do rectangles\r
+void DrawSeekBackground( int left, int top, int right, int bottom )\r
+{\r
+    HPEN hp;\r
+    RECT rc;\r
+\r
+    if (hdcSeek == NULL) {\r
+    hdcSeek = GetDC(hwndMain);\r
+      if (!appData.monoMode) {\r
+        SelectPalette(hdcSeek, hPal, FALSE);\r
+        RealizePalette(hdcSeek);\r
+      }\r
+    }\r
+    hp = SelectObject( hdcSeek, gridPen );\r
+    rc.top = boardRect.top+top; rc.left = boardRect.left+left; \r
+    rc.bottom = boardRect.top+bottom; rc.right = boardRect.left+right;\r
+    FillRect( hdcSeek, &rc, lightSquareBrush );\r
+    SelectObject( hdcSeek, hp );\r
+}\r
+\r
+// front-end wrapper for putting text in graph\r
+void DrawSeekText(char *buf, int x, int y)\r
+{\r
+        SIZE stSize;\r
+       SetBkMode( hdcSeek, TRANSPARENT );\r
+        GetTextExtentPoint32( hdcSeek, buf, strlen(buf), &stSize );\r
+        TextOut( hdcSeek, boardRect.left+x-3, boardRect.top+y-stSize.cy/2, buf, strlen(buf) );\r
+}\r
+\r
+void DrawSeekDot(int x, int y, int color)\r
+{\r
+       int square = color & 0x80;\r
+       HBRUSH oldBrush = SelectObject(hdcSeek, \r
+                       color == 0 ? markerBrush : color == 1 ? darkSquareBrush : explodeBrush);\r
+       color &= 0x7F;\r
+       if(square)\r
+           Rectangle(hdcSeek, boardRect.left+x - squareSize/9, boardRect.top+y - squareSize/9,\r
+                              boardRect.left+x + squareSize/9, boardRect.top+y + squareSize/9);\r
+       else\r
+           Ellipse(hdcSeek, boardRect.left+x - squareSize/8, boardRect.top+y - squareSize/8,\r
+                            boardRect.left+x + squareSize/8, boardRect.top+y + squareSize/8);\r
+           SelectObject(hdcSeek, oldBrush);\r
+}\r
+\r
+VOID\r
 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)\r
 {\r
-  static Board lastReq, lastDrawn;\r
+  static Board lastReq[2], lastDrawn[2];\r
   static HighlightInfo lastDrawnHighlight, lastDrawnPremove;\r
   static int lastDrawnFlipView = 0;\r
-  static int lastReqValid = 0, lastDrawnValid = 0;\r
+  static int lastReqValid[2] = {0, 0}, lastDrawnValid[2] = {0, 0};\r
   int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;\r
   HDC tmphdc;\r
   HDC hdcmem;\r
@@ -4249,6 +3521,7 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
   RECT Rect;\r
   HRGN clips[MAX_CLIPS];\r
   ChessSquare dragged_piece = EmptySquare;\r
+  int nr = twoBoards*partnerUp;\r
 \r
   /* I'm undecided on this - this function figures out whether a full\r
    * repaint is necessary on its own, so there's no real reason to have the\r
@@ -4260,29 +3533,20 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
    */\r
   Boolean fullrepaint = repaint;\r
 \r
+  if(DrawSeekGraph()) return; // [HG} seekgraph: suppress printing board if seek graph up\r
+\r
   if( DrawPositionNeedsFullRepaint() ) {\r
       fullrepaint = TRUE;\r
   }\r
 \r
-#if 0\r
-  if( fullrepaint ) {\r
-      static int repaint_count = 0;\r
-      char buf[128];\r
-\r
-      repaint_count++;\r
-      sprintf( buf, "FULL repaint: %d\n", repaint_count );\r
-      OutputDebugString( buf );\r
-  }\r
-#endif\r
-\r
   if (board == NULL) {\r
-    if (!lastReqValid) {\r
+    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
@@ -4304,35 +3568,6 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
     releaseDC = FALSE;\r
   }\r
 \r
-#if 0\r
-  fprintf(debugFP, "*******************************\n"\r
-                   "repaint = %s\n"\r
-                   "dragInfo.from (%d,%d)\n"\r
-                   "dragInfo.start (%d,%d)\n"\r
-                   "dragInfo.pos (%d,%d)\n"\r
-                   "dragInfo.lastpos (%d,%d)\n", \r
-                    repaint ? "TRUE" : "FALSE",\r
-                    dragInfo.from.x, dragInfo.from.y, \r
-                    dragInfo.start.x, dragInfo.start.y,\r
-                    dragInfo.pos.x, dragInfo.pos.y,\r
-                    dragInfo.lastpos.x, dragInfo.lastpos.y);\r
-  fprintf(debugFP, "prev:  ");\r
-  for (row = 0; row < BOARD_HEIGHT; row++) {\r
-    for (column = 0; column < BOARD_WIDTH; column++) {\r
-      fprintf(debugFP, "%d ", lastDrawn[row][column]);\r
-    }\r
-  }\r
-  fprintf(debugFP, "\n");\r
-  fprintf(debugFP, "board: ");\r
-  for (row = 0; row < BOARD_HEIGHT; row++) {\r
-    for (column = 0; column < BOARD_WIDTH; column++) {\r
-      fprintf(debugFP, "%d ", board[row][column]);\r
-    }\r
-  }\r
-  fprintf(debugFP, "\n");\r
-  fflush(debugFP);\r
-#endif\r
-\r
   /* Create some work-DCs */\r
   hdcmem = CreateCompatibleDC(hdc);\r
   tmphdc = CreateCompatibleDC(hdc);\r
@@ -4350,23 +3585,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
@@ -4407,6 +3643,30 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
        }\r
       }\r
     }\r
+   } else { // nr == 1\r
+       partnerHighlightInfo.sq[0].y = board[EP_STATUS-4];\r
+       partnerHighlightInfo.sq[0].x = board[EP_STATUS-3];\r
+       partnerHighlightInfo.sq[1].y = board[EP_STATUS-2];\r
+       partnerHighlightInfo.sq[1].x = board[EP_STATUS-1];\r
+      for (i=0; i<2; i++) {\r
+       if (partnerHighlightInfo.sq[i].x >= 0 &&\r
+           partnerHighlightInfo.sq[i].y >= 0) {\r
+         SquareToPos(partnerHighlightInfo.sq[i].y,\r
+                     partnerHighlightInfo.sq[i].x, &x, &y);\r
+         clips[num_clips++] =\r
+           CreateRectRgn(x - lineGap, y - lineGap, \r
+                         x + squareSize + lineGap, y + squareSize + lineGap);\r
+       }\r
+       if (oldPartnerHighlight.sq[i].x >= 0 && \r
+           oldPartnerHighlight.sq[i].y >= 0) {\r
+         SquareToPos(oldPartnerHighlight.sq[i].y, \r
+                     oldPartnerHighlight.sq[i].x, &x, &y);\r
+         clips[num_clips++] =\r
+           CreateRectRgn(x - lineGap, y - lineGap, \r
+                         x + squareSize + lineGap, y + squareSize + lineGap);\r
+       }\r
+      }\r
+   }\r
   } else {\r
     fullrepaint = TRUE;\r
   }\r
@@ -4465,8 +3725,8 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
         atomic, where the piece moves to an empty square and then\r
         explodes.  The old and new positions both had an empty square\r
         at the destination, but animation has drawn a piece there and\r
-        we have to remember to erase it. */\r
-      lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;\r
+        we have to remember to erase it. [HGM] moved until after setting lastDrawn */\r
+      lastDrawn[0][animInfo.to.y][animInfo.to.x] = animInfo.piece;\r
     }\r
   }\r
 \r
@@ -4484,13 +3744,49 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
   }\r
 \r
   /* Do all the drawing to the memory DC */\r
-  DrawGridOnDC(hdcmem);\r
-  DrawHighlightsOnDC(hdcmem);\r
-  DrawBoardOnDC(hdcmem, board, tmphdc);\r
-\r
-  if(logoHeight) {\r
-       DrawLogoOnDC(hdc, leftLogoRect, flipClock ? &second : &first);\r
-       DrawLogoOnDC(hdc, rightLogoRect, flipClock ? &first : &second);\r
+  if(explodeInfo.radius) { // [HGM] atomic\r
+       HBRUSH oldBrush;\r
+       int x, y, r=(explodeInfo.radius * squareSize)/100;\r
+        ChessSquare piece = board[explodeInfo.fromY][explodeInfo.fromX];\r
+        board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer\r
+       SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);\r
+       x += squareSize/2;\r
+       y += squareSize/2;\r
+        if(!fullrepaint) {\r
+         clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);\r
+         ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);\r
+       }\r
+       DrawGridOnDC(hdcmem);\r
+       DrawHighlightsOnDC(hdcmem, &highlightInfo, HIGHLIGHT_PEN);\r
+       DrawHighlightsOnDC(hdcmem, &premoveHighlightInfo, PREMOVE_PEN);\r
+       DrawBoardOnDC(hdcmem, board, tmphdc);\r
+        board[explodeInfo.fromY][explodeInfo.fromX] = piece;\r
+       oldBrush = SelectObject(hdcmem, explodeBrush);\r
+       Ellipse(hdcmem, x-r, y-r, x+r, y+r);\r
+       SelectObject(hdcmem, oldBrush);\r
+  } else {\r
+    DrawGridOnDC(hdcmem);\r
+    if(nr == 0) { // [HGM] dual: decide which highlights to draw\r
+       DrawHighlightsOnDC(hdcmem, &highlightInfo, HIGHLIGHT_PEN);\r
+       DrawHighlightsOnDC(hdcmem, &premoveHighlightInfo, PREMOVE_PEN);\r
+    } else {\r
+       DrawHighlightsOnDC(hdcmem, &partnerHighlightInfo, HIGHLIGHT_PEN);\r
+       oldPartnerHighlight = partnerHighlightInfo;\r
+    }\r
+    DrawBoardOnDC(hdcmem, board, tmphdc);\r
+  }\r
+  if(nr == 0) // [HGM] dual: markers only on left board\r
+  for (row = 0; row < BOARD_HEIGHT; row++) {\r
+    for (column = 0; column < BOARD_WIDTH; column++) {\r
+       if (marker[row][column]) { // marker changes only occur with full repaint!\r
+           HBRUSH oldBrush = SelectObject(hdcmem, \r
+                       marker[row][column] == 2 ? markerBrush : explodeBrush);\r
+           SquareToPos(row, column, &x, &y);\r
+           Ellipse(hdcmem, x + squareSize/4, y + squareSize/4,\r
+                         x + 3*squareSize/4, y + 3*squareSize/4);\r
+           SelectObject(hdcmem, oldBrush);\r
+       }\r
+    }\r
   }\r
 \r
   if( appData.highlightMoveWithArrow ) {\r
@@ -4499,7 +3795,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
@@ -4513,8 +3809,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
@@ -4536,6 +3832,13 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
 \r
   /* Set clipping on the target DC */\r
   if (!fullrepaint) {\r
+    if(nr == 1) for (x = 0; x < num_clips; x++) { // [HGM] dual: translate clips\r
+       RECT rect;\r
+       GetRgnBox(clips[x], &rect);\r
+       DeleteObject(clips[x]);\r
+       clips[x] = CreateRectRgn(rect.left + wpMain.width/2, rect.top, \r
+                         rect.right + wpMain.width/2, rect.bottom);\r
+    }\r
     SelectClipRgn(hdc, clips[0]);\r
     for (x = 1; x < num_clips; x++) {\r
       if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)\r
@@ -4547,16 +3850,16 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
    * This way we avoid any flickering\r
    */\r
   oldBitmap = SelectObject(tmphdc, bufferBitmap);\r
-  BitBlt(hdc, boardRect.left, boardRect.top,\r
+  BitBlt(hdc, boardRect.left + twoBoards*partnerUp*wpMain.width/2, boardRect.top, // [HGM] dual\r
         boardRect.right - boardRect.left,\r
         boardRect.bottom - boardRect.top,\r
         tmphdc, boardRect.left, boardRect.top, SRCCOPY);\r
   if(saveDiagFlag) { \r
-    BITMAP b; int i, j, m, w, wb, fac=0; char pData[1000000]; \r
+    BITMAP b; int i, j=0, m, w, wb, fac=0; char *pData; \r
     BITMAPINFOHEADER bih; int color[16], nrColors=0;\r
 \r
     GetObject(bufferBitmap, sizeof(b), &b);\r
-    if(b.bmWidthBytes*b.bmHeight <= 990000) {\r
+    if(pData = malloc(b.bmWidthBytes*b.bmHeight + 10000)) {\r
        bih.biSize = sizeof(BITMAPINFOHEADER);\r
        bih.biWidth = b.bmWidth;\r
        bih.biHeight = b.bmHeight;\r
@@ -4573,7 +3876,6 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
        GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);\r
 //     fprintf(diagFile, "%8x\n", (int) pData);\r
 \r
-#if 1\r
        wb = b.bmWidthBytes;\r
        // count colors\r
        for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {\r
@@ -4596,7 +3898,7 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
                    while(p&3) pData[p++] = 0;\r
                }\r
                fac = 3;\r
-               wb = (wb+31>>5)<<2;\r
+               wb = ((wb+31)>>5)<<2;\r
        }\r
        // write BITMAPFILEHEADER\r
        fprintf(diagFile, "BM");\r
@@ -4621,7 +3923,7 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
        // write bitmap data\r
        for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++) \r
                fputc(pData[i], diagFile);\r
-#endif\r
+       free(pData);\r
      }\r
   }\r
 \r
@@ -4637,7 +3939,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
@@ -4648,7 +3950,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
@@ -4656,16 +3958,10 @@ int
 SaveDiagram(f)\r
      FILE *f;\r
 {\r
-    time_t tm;\r
-    char *fen;\r
-\r
     saveDiagFlag = 1; diagFile = f;\r
     HDCDrawPosition(NULL, TRUE, NULL);\r
-\r
     saveDiagFlag = 0;\r
 \r
-//    if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");\r
-    \r
     fclose(f);\r
     return TRUE;\r
 }\r
@@ -4683,7 +3979,7 @@ PaintProc(HWND hwnd)
   PAINTSTRUCT ps;\r
   HFONT       oldFont;\r
 \r
-  if(hdc = BeginPaint(hwnd, &ps)) {\r
+  if((hdc = BeginPaint(hwnd, &ps))) {\r
     if (IsIconic(hwnd)) {\r
       DrawIcon(hdc, 2, 2, iconCurrent);\r
     } else {\r
@@ -4692,6 +3988,11 @@ PaintProc(HWND hwnd)
        RealizePalette(hdc);\r
       }\r
       HDCDrawPosition(hdc, 1, NULL);\r
+      if(twoBoards) { // [HGM] dual: also redraw other board in other orientation\r
+       flipView = !flipView; partnerUp = !partnerUp;\r
+       HDCDrawPosition(hdc, 1, NULL);\r
+       flipView = !flipView; partnerUp = !partnerUp;\r
+      }\r
       oldFont =\r
        SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);\r
       ExtTextOut(hdc, messageRect.left, messageRect.top,\r
@@ -4699,6 +4000,7 @@ PaintProc(HWND hwnd)
                 &messageRect, messageText, strlen(messageText), NULL);\r
       SelectObject(hdc, oldFont);\r
       DisplayBothClocks();\r
+      DisplayLogos();\r
     }\r
     EndPaint(hwnd,&ps);\r
   }\r
@@ -4713,8 +4015,8 @@ PaintProc(HWND hwnd)
  * The offset boardRect.left or boardRect.top must already have been\r
  *   subtracted from x.\r
  */\r
-int\r
-EventToSquare(int x)\r
+int EventToSquare(x, limit)\r
+     int x, limit;\r
 {\r
   if (x <= 0)\r
     return -2;\r
@@ -4724,7 +4026,7 @@ EventToSquare(int x)
   if ((x % (squareSize + lineGap)) >= squareSize)\r
     return -1;\r
   x /= (squareSize + lineGap);\r
-  if (x >= BOARD_SIZE)\r
+    if (x >= limit)\r
     return -2;\r
   return x;\r
 }\r
@@ -4736,11 +4038,11 @@ typedef struct {
 } DropEnable;\r
 \r
 DropEnable dropEnables[] = {\r
-  { 'P', DP_Pawn, "Pawn" },\r
-  { 'N', DP_Knight, "Knight" },\r
-  { 'B', DP_Bishop, "Bishop" },\r
-  { 'R', DP_Rook, "Rook" },\r
-  { 'Q', DP_Queen, "Queen" },\r
+  { 'P', DP_Pawn, N_("Pawn") },\r
+  { 'N', DP_Knight, N_("Knight") },\r
+  { 'B', DP_Bishop, N_("Bishop") },\r
+  { 'R', DP_Rook, N_("Rook") },\r
+  { 'Q', DP_Queen, N_("Queen") },\r
 };\r
 \r
 VOID\r
@@ -4756,7 +4058,7 @@ SetupDropMenu(HMENU hmenu)
               dropEnables[i].piece);\r
     count = 0;\r
     while (p && *p++ == dropEnables[i].piece) count++;\r
-    sprintf(item, "%s  %d", dropEnables[i].name, count);\r
+      snprintf(item, MSG_SIZ, "%s  %d", T_(dropEnables[i].name), count);\r
     enable = count > 0 || !appData.testLegality\r
       /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse\r
                      && !appData.icsActive);\r
@@ -4766,21 +4068,40 @@ SetupDropMenu(HMENU hmenu)
   }\r
 }\r
 \r
-static int fromX = -1, fromY = -1, toX, toY;\r
+void DragPieceBegin(int x, int y, Boolean instantly)\r
+{\r
+      dragInfo.lastpos.x = boardRect.left + x;\r
+      dragInfo.lastpos.y = boardRect.top + y;\r
+      if(instantly) dragInfo.pos = dragInfo.lastpos;\r
+      dragInfo.from.x = fromX;\r
+      dragInfo.from.y = fromY;\r
+      dragInfo.piece = boards[currentMove][fromY][fromX];\r
+      dragInfo.start = dragInfo.from;\r
+      SetCapture(hwndMain);\r
+}\r
+\r
+void DragPieceEnd(int x, int y)\r
+{\r
+    ReleaseCapture();\r
+    dragInfo.start.x = dragInfo.start.y = -1;\r
+    dragInfo.from = dragInfo.start;\r
+    dragInfo.pos = dragInfo.lastpos = dragInfo.start;\r
+}\r
+\r
+void ChangeDragPiece(ChessSquare piece)\r
+{\r
+    dragInfo.piece = piece;\r
+}\r
 \r
 /* Event handler for mouse messages */\r
 VOID\r
 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)\r
 {\r
-  int x, y;\r
+  int x, y, menuNr;\r
   POINT pt;\r
   static int recursive = 0;\r
   HMENU hmenu;\r
-  BOOLEAN needsRedraw = FALSE;\r
-  BOOLEAN saveAnimate;\r
   BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */\r
-  static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;\r
-  ChessMove moveType;\r
 \r
   if (recursive) {\r
     if (message == WM_MBUTTONUP) {\r
@@ -4796,8 +4117,8 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
   \r
   pt.x = LOWORD(lParam);\r
   pt.y = HIWORD(lParam);\r
-  x = EventToSquare(pt.x - boardRect.left);\r
-  y = EventToSquare(pt.y - boardRect.top);\r
+  x = EventToSquare(pt.x - boardRect.left, BOARD_WIDTH);\r
+  y = EventToSquare(pt.y - boardRect.top, BOARD_HEIGHT);\r
   if (!flipView && y >= 0) {\r
     y = BOARD_HEIGHT - 1 - y;\r
   }\r
@@ -4805,241 +4126,41 @@ 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(promotionChoice) { // we are waiting for a click to indicate promotion piece\r
-       promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel\r
-       if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);\r
-       if(gameInfo.holdingsWidth && \r
-               (WhiteOnMove(currentMove) \r
-                       ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0\r
-                       : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {\r
-           // click in right holdings, for determining promotion piece\r
-           ChessSquare p = boards[currentMove][y][x];\r
-           if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);\r
-           if(p != EmptySquare) {\r
-               FinishMove(WhitePromotionQueen, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));\r
-               fromX = fromY = -1;\r
-               break;\r
-           }\r
-       }\r
-       DrawPosition(FALSE, boards[currentMove]);\r
-       break;\r
-    }\r
-    ErrorPopDown();\r
-    sameAgain = FALSE;\r
-    if (y == -2) {\r
-      /* Downclick vertically off board; check if on clock */\r
       if (PtInRect((LPRECT) &whiteRect, pt)) {\r
-        if (gameMode == EditPosition) {\r
-         SetWhiteToPlayEvent();\r
-       } else if (gameMode == IcsPlayingBlack ||\r
-                  gameMode == MachinePlaysWhite) {\r
-         CallFlagEvent();\r
-        } else if (gameMode == EditGame) {\r
-          AdjustClock((logoHeight > 0 ? flipView: 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(!(logoHeight > 0 ? flipView: flipClock), -1);\r
-       }\r
+       ClockClick(!flipClock);\r
       }\r
-      if (!appData.highlightLastMove) {\r
-        ClearHighlights();\r
-       DrawPosition(forceFullRepaint || FALSE, NULL);\r
-      }\r
-      fromX = fromY = -1;\r
       dragInfo.start.x = dragInfo.start.y = -1;\r
       dragInfo.from = dragInfo.start;\r
-      break;\r
-    } else if (x < 0 || y < 0\r
-      /* [HGM] block clicks between board and holdings */\r
-              || x == BOARD_LEFT-1 || x == BOARD_RGHT\r
-              || x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize\r
-              || x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize\r
-       /* EditPosition, empty square, or different color piece;\r
-          click-click move is possible */\r
-                               ) {\r
-      break;\r
-    } else if (fromX == x && fromY == y) {\r
-      /* Downclick on same square again */\r
-      ClearHighlights();\r
-      DrawPosition(forceFullRepaint || FALSE, NULL);\r
-      sameAgain = TRUE;  \r
-    } else if (fromX != -1 &&\r
-               x != BOARD_LEFT-2 && x != BOARD_RGHT+1 \r
-                                                                        ) {\r
-      /* Downclick on different square. */\r
-      /* [HGM] if on holdings file, should count as new first click ! */\r
-      { /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */\r
-       toX = x;\r
-       toY = y;\r
-        /* [HGM] <popupFix> UserMoveEvent requires two calls now,\r
-           to make sure move is legal before showing promotion popup */\r
-        moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);\r
-       if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */\r
+    if(fromX == -1 && frozen) { // not sure where this is for\r
                fromX = fromY = -1; \r
-               ClearHighlights();\r
-               DrawPosition(FALSE, boards[currentMove]);\r
-               break; \r
-       } else \r
-        if(moveType != ImpossibleMove) {\r
-          /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */\r
-          if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||\r
-             (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&\r
-              appData.alwaysPromoteToQueen) {\r
-                  FinishMove(moveType, fromX, fromY, toX, toY, 'q');\r
-                  if (!appData.highlightLastMove) {\r
-                      ClearHighlights();\r
-                      DrawPosition(forceFullRepaint || FALSE, NULL);\r
-                  }\r
-          } else\r
-          if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {\r
-                  SetHighlights(fromX, fromY, toX, toY);\r
-                  DrawPosition(forceFullRepaint || FALSE, NULL);\r
-                  /* [HGM] <popupFix> Popup calls FinishMove now.\r
-                     If promotion to Q is legal, all are legal! */\r
-                 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)\r
-                 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];\r
-                   // kludge to temporarily execute move on display, wthout promotng yet\r
-                   promotionChoice = TRUE;\r
-                   boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank\r
-                   boards[currentMove][toY][toX] = p;\r
-                   DrawPosition(FALSE, boards[currentMove]);\r
-                   boards[currentMove][fromY][fromX] = p; // take back, but display stays\r
-                   boards[currentMove][toY][toX] = q;\r
-                 } else\r
-                  PromotionPopup(hwnd);\r
-          } else {       /* not a promotion */\r
-             if (appData.animate || appData.highlightLastMove) {\r
-                 SetHighlights(fromX, fromY, toX, toY);\r
-             } else {\r
-                 ClearHighlights();\r
-             }\r
-             FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);\r
-            fromX = fromY = -1;\r
-             if (appData.animate && !appData.highlightLastMove) {\r
-                  ClearHighlights();\r
-                  DrawPosition(forceFullRepaint || FALSE, NULL);\r
-             }\r
-          }\r
-          break;\r
-        }\r
-        if (gotPremove) {\r
-            /* [HGM] it seemed that braces were missing here */\r
-            SetPremoveHighlights(fromX, fromY, toX, toY);\r
-            fromX = fromY = -1;\r
-            break;\r
-        }\r
-      }\r
-      ClearHighlights();\r
-      DrawPosition(forceFullRepaint || FALSE, NULL);\r
-    }\r
-    /* First downclick, or restart on a square with same color piece */\r
-    if (!frozen && OKToStartUserMove(x, y)) {\r
-      fromX = x;\r
-      fromY = y;\r
-      dragInfo.lastpos = pt;\r
-      dragInfo.from.x = fromX;\r
-      dragInfo.from.y = fromY;\r
-      dragInfo.start = dragInfo.from;\r
-      SetCapture(hwndMain);\r
-    } else {\r
-      fromX = fromY = -1;\r
-      dragInfo.start.x = dragInfo.start.y = -1;\r
-      dragInfo.from = dragInfo.start;\r
       DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */\r
+      break;\r
     }\r
+      LeftClick(Press, pt.x - boardRect.left, pt.y - boardRect.top);\r
+      DrawPosition(TRUE, NULL);\r
     break;\r
 \r
   case WM_LBUTTONUP:\r
-    ReleaseCapture();\r
-    if (fromX == -1) break;\r
-    if (x == fromX && y == fromY) {\r
-      dragInfo.from.x = dragInfo.from.y = -1;\r
-      /* Upclick on same square */\r
-      if (sameAgain) {\r
-       /* Clicked same square twice: abort click-click move */\r
-       fromX = fromY = -1;\r
-       gotPremove = 0;\r
-       ClearPremoveHighlights();\r
-      } else {\r
-       /* First square clicked: start click-click move */\r
-       SetHighlights(fromX, fromY, -1, -1);\r
-      }\r
-      DrawPosition(forceFullRepaint || FALSE, NULL);\r
-    } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {\r
-      /* Errant click; ignore */\r
-      break;\r
-    } else {\r
-      /* Finish drag move. */\r
-    if (appData.debugMode) {\r
-        fprintf(debugFP, "release\n");\r
-    }\r
-      dragInfo.from.x = dragInfo.from.y = -1;\r
-      toX = x;\r
-      toY = y;\r
-      saveAnimate = appData.animate; /* sorry, Hawk :) */\r
-      appData.animate = appData.animate && !appData.animateDragging;\r
-      moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);\r
-      if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */\r
-               fromX = fromY = -1; \r
-               ClearHighlights();\r
-               DrawPosition(FALSE, boards[currentMove]);\r
-               break; \r
-      } else \r
-      if(moveType != ImpossibleMove) {\r
-          /* [HGM] use move type to determine if move is promotion.\r
-             Knight is Shogi kludge for mandatory promotion, Queen means choice */\r
-          if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||\r
-             (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&\r
-              appData.alwaysPromoteToQueen) \r
-               FinishMove(moveType, fromX, fromY, toX, toY, 'q');\r
-          else \r
-          if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {\r
-               DrawPosition(forceFullRepaint || FALSE, NULL);\r
-                 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)\r
-                 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];\r
-                   // kludge to temporarily execute move on display, wthout promotng yet\r
-                   promotionChoice = TRUE;\r
-                   boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank\r
-                   boards[currentMove][toY][toX] = p;\r
-                   DrawPosition(FALSE, boards[currentMove]);\r
-                   boards[currentMove][fromY][fromX] = p; // take back, but display stays\r
-                   boards[currentMove][toY][toX] = q;\r
-                   break;\r
-                 } else\r
-               PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */\r
-        } else FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);\r
-      }\r
-      if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);\r
-      appData.animate = saveAnimate;\r
-      fromX = fromY = -1;\r
-      if (appData.highlightDragging && !appData.highlightLastMove) {\r
-       ClearHighlights();\r
-      }\r
-      if (appData.animate || appData.animateDragging ||\r
-         appData.highlightDragging || gotPremove) {\r
-       DrawPosition(forceFullRepaint || FALSE, NULL);\r
-      }\r
-    }\r
-    dragInfo.start.x = dragInfo.start.y = -1; \r
-    dragInfo.pos = dragInfo.lastpos = dragInfo.start;\r
+      LeftClick(Release, pt.x - boardRect.left, pt.y - boardRect.top);\r
+      DrawPosition(TRUE, NULL);\r
     break;\r
 \r
   case WM_MOUSEMOVE:\r
+    if(SeekGraphClick(Press, pt.x - boardRect.left, pt.y - boardRect.top, 1)) break;\r
+    if(PromoScroll(pt.x - boardRect.left, pt.y - boardRect.top)) break;\r
+    MovePV(pt.x - boardRect.left, pt.y - boardRect.top, boardRect.bottom - boardRect.top);\r
     if ((appData.animateDragging || appData.highlightDragging)\r
        && (wParam & MK_LBUTTON)\r
        && dragInfo.from.x >= 0) \r
     {\r
       BOOL full_repaint = FALSE;\r
 \r
-      sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */\r
       if (appData.animateDragging) {\r
        dragInfo.pos = pt;\r
       }\r
@@ -5061,16 +4182,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(lastDir == 1) ForwardEvent(); else lastDir = 1; // [HGM] suppress first event in each direction\r
+       if((short)HIWORD(wParam) < 0 && currentMove < forwardMostMove) \r
+               { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction\r
        /* Mouse Wheel is being rolled backward\r
         * Play moves backward\r
         */\r
-       if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove) \r
-               if(lastDir == -1) BackwardEvent(); else lastDir = -1;\r
+       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
@@ -5086,19 +4213,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((logoHeight > 0 ? flipView: 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(!(logoHeight > 0 ? flipView: 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
@@ -5106,16 +4231,6 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
        else\r
          MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);\r
       } else { /* message == WM_RBUTTONDOWN */\r
-#if 0\r
-       if (buttonCount == 3) {\r
-         if (wParam & MK_SHIFT) \r
-           MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);\r
-         else\r
-           MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);\r
-       } else {\r
-         MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);\r
-       }\r
-#else\r
        /* Just have one menu, on the right button.  Windows users don't\r
           think to try the middle one, and sometimes other software steals\r
           it, or it doesn't really exist. */\r
@@ -5123,24 +4238,15 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
             MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);\r
         else\r
             MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);\r
-#endif\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
@@ -5154,7 +4260,7 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 LRESULT CALLBACK\r
 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)\r
 {\r
-  int id = GetWindowLong(hwnd, GWL_ID);\r
+  int id = GetWindowLongPtr(hwnd, GWLP_ID);\r
   int i, dir;\r
 \r
   for (i=0; i<N_BUTTONS; i++) {\r
@@ -5176,31 +4282,16 @@ ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     case '\r':\r
       SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);\r
       return TRUE;\r
-    case '\t':\r
-      if (appData.icsActive) {\r
-       if (GetKeyState(VK_SHIFT) < 0) {\r
-         /* shifted */\r
-         HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);\r
-         if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);\r
-         SetFocus(h);\r
-       } else {\r
-         /* unshifted */\r
-         HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);\r
-         if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);\r
-         SetFocus(h);\r
-       }\r
-       return TRUE;\r
-      }\r
-      break;\r
     default:\r
-      if (appData.icsActive) {\r
+      if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {\r
+       // [HGM] movenum: only letters or leading zero should go to ICS input\r
         HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);\r
        if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);\r
        SetFocus(h);\r
        SendMessage(h, WM_CHAR, wParam, lParam);\r
        return TRUE;\r
       } else if (isalpha((char)wParam) || isdigit((char)wParam)){\r
-       PopUpMoveDialog((char)wParam);\r
+       TypeInEvent((char)wParam);\r
       }\r
       break;\r
     }\r
@@ -5219,22 +4310,24 @@ 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) != '~' ||\r
-        PieceToChar(BlackAngel) >= 'A' &&\r
-        PieceToChar(BlackAngel) != '~'   ) ?\r
+       ((PieceToChar(WhiteAngel) >= 'A' && WhiteOnMove(currentMove) &&\r
+         PieceToChar(WhiteAngel) != '~') ||\r
+        (PieceToChar(BlackAngel) >= 'A' && !WhiteOnMove(currentMove) &&\r
+         PieceToChar(BlackAngel) != '~')   ) ?\r
               SW_SHOW : SW_HIDE);\r
     ShowWindow(GetDlgItem(hDlg, PB_Chancellor), \r
-       (PieceToChar(WhiteMarshall) >= 'A' &&\r
-        PieceToChar(WhiteMarshall) != '~' ||\r
-        PieceToChar(BlackMarshall) >= 'A' &&\r
-        PieceToChar(BlackMarshall) != '~'   ) ?\r
+       ((PieceToChar(WhiteMarshall) >= 'A' && WhiteOnMove(currentMove) &&\r
+         PieceToChar(WhiteMarshall) != '~') ||\r
+        (PieceToChar(BlackMarshall) >= 'A' && !WhiteOnMove(currentMove) &&\r
+         PieceToChar(BlackMarshall) != '~')   ) ?\r
               SW_SHOW : SW_HIDE);\r
     /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */\r
     ShowWindow(GetDlgItem(hDlg, PB_Rook),\r
@@ -5243,12 +4336,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
@@ -5265,32 +4357,32 @@ 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
-    FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);\r
+    UserMoveEvent(fromX, fromY, toX, toY, promoChar);\r
+    fromX = fromY = -1;\r
     if (!appData.highlightLastMove) {\r
       ClearHighlights();\r
       DrawPosition(FALSE, NULL);\r
@@ -5312,6 +4404,13 @@ PromotionPopup(HWND hwnd)
   FreeProcInstance(lpProc);\r
 }\r
 \r
+void\r
+PromotionPopUp()\r
+{\r
+  DrawPosition(TRUE, NULL);\r
+  PromotionPopup(hwndMain);\r
+}\r
+\r
 /* Toggle ShowThinking */\r
 VOID\r
 ToggleShowThinking()\r
@@ -5335,7 +4434,7 @@ LoadGameDialog(HWND hwnd, char* title)
     if (number == 0) {\r
       int error = GameListBuild(f);\r
       if (error) {\r
-        DisplayError("Cannot build game list", error);\r
+        DisplayError(_("Cannot build game list"), error);\r
       } else if (!ListEmpty(&gameList) &&\r
                  ((ListGame *) gameList.tailPred)->number > 1) {\r
        GameListPopUp(f, fileTitle);\r
@@ -5348,6 +4447,57 @@ LoadGameDialog(HWND hwnd, char* title)
   }\r
 }\r
 \r
+int get_term_width()\r
+{\r
+    HDC hdc;\r
+    TEXTMETRIC tm;\r
+    RECT rc;\r
+    HFONT hfont, hold_font;\r
+    LOGFONT lf;\r
+    HWND hText;\r
+\r
+    if (hwndConsole)\r
+        hText = GetDlgItem(hwndConsole, OPT_ConsoleText);\r
+    else\r
+        return 79;\r
+\r
+    // get the text metrics\r
+    hdc = GetDC(hText);\r
+    lf = font[boardSize][CONSOLE_FONT]->lf;\r
+    if (consoleCF.dwEffects & CFE_BOLD)\r
+        lf.lfWeight = FW_BOLD;\r
+    if (consoleCF.dwEffects & CFE_ITALIC)\r
+        lf.lfItalic = TRUE;\r
+    if (consoleCF.dwEffects & CFE_STRIKEOUT)\r
+        lf.lfStrikeOut = TRUE;\r
+    if (consoleCF.dwEffects & CFE_UNDERLINE)\r
+        lf.lfUnderline = TRUE;\r
+    hfont = CreateFontIndirect(&lf);\r
+    hold_font = SelectObject(hdc, hfont);\r
+    GetTextMetrics(hdc, &tm);\r
+    SelectObject(hdc, hold_font);\r
+    DeleteObject(hfont);\r
+    ReleaseDC(hText, hdc);\r
+\r
+    // get the rectangle\r
+    SendMessage(hText, EM_GETRECT, 0, (LPARAM)&rc);\r
+\r
+    return (rc.right-rc.left) / tm.tmAveCharWidth;\r
+}\r
+\r
+void UpdateICSWidth(HWND hText)\r
+{\r
+    LONG old_width, new_width;\r
+\r
+    new_width = get_term_width(hText, FALSE);\r
+    old_width = GetWindowLongPtr(hText, GWLP_USERDATA);\r
+    if (new_width != old_width)\r
+    {\r
+        ics_update_width(new_width);\r
+        SetWindowLongPtr(hText, GWLP_USERDATA, new_width);\r
+    }\r
+}\r
+\r
 VOID\r
 ChangedConsoleFont()\r
 {\r
@@ -5360,7 +4510,8 @@ ChangedConsoleFont()
 \r
   cfmt.cbSize = sizeof(CHARFORMAT);\r
   cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;\r
-  strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);\r
+    safeStrCpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName,\r
+              sizeof(cfmt.szFaceName)/sizeof(cfmt.szFaceName[0]) );\r
   /* yHeight is expressed in twips.  A twip is 1/20 of a font's point\r
    * size.  This was undocumented in the version of MSVC++ that I had\r
    * when I wrote the code, but is apparently documented now.\r
@@ -5387,6 +4538,7 @@ ChangedConsoleFont()
   paraf.dxOffset = WRAP_INDENT;\r
   SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) &paraf);\r
   SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);\r
+  UpdateICSWidth(hText);\r
 }\r
 \r
 /*---------------------------------------------------------------------------*\\r
@@ -5434,30 +4586,25 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     MouseEvent(hwnd, message, wParam, lParam);\r
     break;\r
 \r
+  JAWS_KB_NAVIGATION\r
+\r
   case WM_CHAR:\r
     \r
-    if (appData.icsActive) {\r
-      if (wParam == '\t') {\r
-       if (GetKeyState(VK_SHIFT) < 0) {\r
-         /* shifted */\r
-         HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);\r
-         if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);\r
-         SetFocus(h);\r
-       } else {\r
-         /* unshifted */\r
-         HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);\r
-         if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);\r
-         SetFocus(h);\r
-       }\r
-      } else {\r
+    JAWS_ALT_INTERCEPT\r
+\r
+    if (appData.icsActive && ((char)wParam == '\r' || (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9'))) { \r
+       // [HGM] movenum: for non-zero digits we always do type-in dialog\r
        HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);\r
        if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);\r
        SetFocus(h);\r
        SendMessage(h, message, wParam, lParam);\r
-      }\r
-    } else if (isalpha((char)wParam) || isdigit((char)wParam)) {\r
-      PopUpMoveDialog((char)wParam);\r
+    } else if(lParam != KF_REPEAT) {\r
+       if (isalpha((char)wParam) || isdigit((char)wParam)) {\r
+               TypeInEvent((char)wParam);\r
+       } else if((char)wParam == 003) CopyGameToClipboard();\r
+        else if((char)wParam == 026) PasteGameOrFENFromClipboard();\r
     }\r
+\r
     break;\r
 \r
   case WM_PALETTECHANGED:\r
@@ -5468,11 +4615,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       nnew = RealizePalette(hdc);\r
       if (nnew > 0) {\r
        paletteChanged = TRUE;\r
-#if 0\r
-        UpdateColors(hdc);\r
-#else\r
-        InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/\r
-#endif\r
+        InvalidateRect(hwnd, &boardRect, FALSE);\r
       }\r
       ReleaseDC(hwnd, hdc);\r
     }\r
@@ -5500,13 +4643,12 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     switch (wmId) {\r
     case IDM_NewGame:\r
       ResetGameEvent();\r
-      AnalysisPopDown();\r
+      SAY("new game enter a move to play against the computer with white");\r
       break;\r
 \r
     case IDM_NewGameFRC:\r
       if( NewGameFRC() == 0 ) {\r
         ResetGameEvent();\r
-        AnalysisPopDown();\r
       }\r
       break;\r
 \r
@@ -5515,7 +4657,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
@@ -5538,7 +4680,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
@@ -5561,7 +4703,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
@@ -5572,7 +4714,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
@@ -5583,7 +4725,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
@@ -5623,6 +4765,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
         }\r
         else {\r
             EvalGraphPopUp();\r
+           SetFocus(hwndMain);\r
         }\r
         break;\r
 \r
@@ -5654,6 +4797,10 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       GameListOptions();\r
       break;\r
 \r
+    case IDM_NewChat:\r
+      ChatPopUp(NULL);\r
+      break;\r
+\r
     case IDM_CopyPosition:\r
       CopyFENToClipboard();\r
       break;\r
@@ -5690,6 +4837,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
          TagsPopUp(tags, CmailMsg());\r
          free(tags);\r
       }\r
+      SAY("computer starts playing white");\r
       break;\r
 \r
     case IDM_MachineBlack:\r
@@ -5703,6 +4851,11 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
          TagsPopUp(tags, CmailMsg());\r
          free(tags);\r
       }\r
+      SAY("computer starts playing black");\r
+      break;\r
+\r
+    case IDM_Match: // [HGM] match: flows into next case, after setting Match Mode and nr of Games\r
+      MatchEvent(2); // distinguish from command-line-triggered case (matchMode=1)\r
       break;\r
 \r
     case IDM_TwoMachines:\r
@@ -5716,17 +4869,19 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
          TagsPopUp(tags, CmailMsg());\r
          free(tags);\r
       }\r
+      SAY("computer starts playing both sides");\r
       break;\r
 \r
     case IDM_AnalysisMode:\r
       if (!first.analysisSupport) {\r
-        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
@@ -5756,12 +4911,12 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     case IDM_AnalyzeFile:\r
       if (!first.analysisSupport) {\r
         char buf[MSG_SIZ];\r
-        sprintf(buf, "%s does not support analysis", first.tidy);\r
+         snprintf(buf, MSG_SIZ, _("%s does not support analysis"), first.tidy);\r
         DisplayError(buf, 0);\r
       } else {\r
        if (!appData.showThinking) ToggleShowThinking();\r
        AnalyzeFileEvent();\r
-       LoadGameDialog(hwnd, "Analyze Game from File");\r
+       LoadGameDialog(hwnd, _("Analyze Game from File"));\r
        AnalysisPeriodicEvent(1);\r
       }\r
       break;\r
@@ -5771,11 +4926,15 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       break;\r
 \r
     case IDM_EditGame:\r
+    case IDM_EditGame2:\r
       EditGameEvent();\r
+      SAY("edit game");\r
       break;\r
 \r
     case IDM_EditPosition:\r
+    case IDM_EditPosition2:\r
       EditPositionEvent();\r
+      SAY("enter a FEN string or setup a position on the board using the control R pop up menu");\r
       break;\r
 \r
     case IDM_Training:\r
@@ -5786,12 +4945,31 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       ShowGameListProc();\r
       break;\r
 \r
+    case IDM_EditProgs1:\r
+      EditTagsPopUp(firstChessProgramNames, &firstChessProgramNames);\r
+      break;\r
+\r
+    case IDM_EditProgs2:\r
+     LoadEnginePopUp(hwndMain);\r
+//      EditTagsPopUp(secondChessProgramNames, &secondChessProgramNames);\r
+      break;\r
+\r
+    case IDM_EditServers:\r
+      EditTagsPopUp(icsNames, &icsNames);\r
+      break;\r
+\r
     case IDM_EditTags:\r
+    case IDM_Tags:\r
       EditTagsProc();\r
       break;\r
 \r
+    case IDM_EditBook:\r
+      EditBookEvent();\r
+      break;\r
+\r
     case IDM_EditComment:\r
-      if (commentDialogUp && editComment) {\r
+    case IDM_Comment:\r
+      if (commentUp && editComment) {\r
        CommentPopDown();\r
       } else {\r
        EditCommentEvent();\r
@@ -5842,8 +5020,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
@@ -5855,6 +5037,8 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       SetFocus(hwndMain);\r
       break;\r
 \r
+    JAWS_MENU_ITEMS\r
+\r
     case IDM_Forward:\r
       ForwardEvent();\r
       SetFocus(hwndMain);\r
@@ -5871,7 +5055,11 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       break;\r
 \r
     case IDM_Revert:\r
-      RevertEvent();\r
+      RevertEvent(FALSE);\r
+      break;\r
+\r
+    case IDM_Annotate: // [HGM] vari: revert with annotation\r
+      RevertEvent(TRUE);\r
       break;\r
 \r
     case IDM_TruncateGame:\r
@@ -5894,6 +5082,13 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     case IDM_FlipClock:\r
       flipClock = !flipClock;\r
       DisplayBothClocks();\r
+      DisplayLogos();\r
+      break;\r
+\r
+    case IDM_MuteSounds:\r
+      mute = !mute; // [HGM] mute: keep track of global muting variable\r
+      CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds, \r
+                               MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));\r
       break;\r
 \r
     case IDM_GeneralOptions:\r
@@ -5909,10 +5104,24 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       EnginePlayOptionsPopup(hwnd);\r
       break;\r
 \r
+    case IDM_Engine1Options:\r
+      EngineOptionsPopup(hwnd, &first);\r
+      break;\r
+\r
+    case IDM_Engine2Options:\r
+      savedHwnd = hwnd;\r
+      if(WaitForEngine(&second, SettingsMenuIfReady)) break;\r
+      EngineOptionsPopup(hwnd, &second);\r
+      break;\r
+\r
     case IDM_OptionsUCI:\r
       UciOptionsPopup(hwnd);\r
       break;\r
 \r
+    case IDM_Tourney:\r
+      TourneyPopup(hwnd);\r
+      break;\r
+\r
     case IDM_IcsOptions:\r
       IcsOptionsPopup(hwnd);\r
       break;\r
@@ -5980,17 +5189,19 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       break;\r
 \r
     case IDM_HELPCONTENTS:\r
-      if (!WinHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {\r
-       MessageBox (GetFocus(),\r
-                   "Unable to activate help",\r
+      if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&\r
+         !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {\r
+         MessageBox (GetFocus(),\r
+                   _("Unable to activate help"),\r
                    szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);\r
       }\r
       break;\r
 \r
     case IDM_HELPSEARCH:\r
-      if (!WinHelp(hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) {\r
+        if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&\r
+           !HtmlHelp(hwnd, "winboard.chm", 0, 0)       ) {\r
        MessageBox (GetFocus(),\r
-                   "Unable to activate help",\r
+                   _("Unable to activate help"),\r
                    szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);\r
       }\r
       break;\r
@@ -5998,7 +5209,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     case IDM_HELPHELP:\r
       if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {\r
        MessageBox (GetFocus(),\r
-                   "Unable to activate help",\r
+                   _("Unable to activate help"),\r
                    szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);\r
       }\r
       break;\r
@@ -6012,12 +5223,12 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       break;\r
 \r
     case IDM_DirectCommand1:\r
-      AskQuestionEvent("Direct Command",\r
-                      "Send to chess program:", "", "1");\r
+      AskQuestionEvent(_("Direct Command"),\r
+                      _("Send to chess program:"), "", "1");\r
       break;\r
     case IDM_DirectCommand2:\r
-      AskQuestionEvent("Direct Command",\r
-                      "Send to second chess program:", "", "2");\r
+      AskQuestionEvent(_("Direct Command"),\r
+                      _("Send to second chess program:"), "", "2");\r
       break;\r
 \r
     case EP_WhitePawn:\r
@@ -6195,7 +5406,23 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       fromX = fromY = -1;\r
       break;\r
 \r
+    case IDM_English:\r
+      barbaric = 0; appData.language = "";\r
+      TranslateMenus(0);\r
+      CheckMenuItem(GetMenu(hwndMain), lastChecked, MF_BYCOMMAND|MF_UNCHECKED);\r
+      CheckMenuItem(GetMenu(hwndMain), IDM_English, MF_BYCOMMAND|MF_CHECKED);\r
+      lastChecked = wmId;\r
+      break;\r
+\r
     default:\r
+      if(wmId > IDM_English && wmId < IDM_English+20) {\r
+          LoadLanguageFile(languageFile[wmId - IDM_English - 1]);\r
+          TranslateMenus(0);\r
+          CheckMenuItem(GetMenu(hwndMain), lastChecked, MF_BYCOMMAND|MF_UNCHECKED);\r
+          CheckMenuItem(GetMenu(hwndMain), wmId, MF_BYCOMMAND|MF_CHECKED);\r
+          lastChecked = wmId;\r
+          break;\r
+      }\r
       return (DefWindowProc(hwnd, message, wParam, lParam));\r
     }\r
     break;\r
@@ -6235,6 +5462,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 \r
   /* [AS] Also move "attached" child windows */\r
   case WM_WINDOWPOSCHANGING:\r
+\r
     if( hwnd == hwndMain && appData.useStickyWindows ) {\r
         LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;\r
 \r
@@ -6242,11 +5470,19 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
             /* Window is moving */\r
             RECT rcMain;\r
 \r
-            GetWindowRect( hwnd, &rcMain );\r
+//            GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old\r
+           rcMain.left   = wpMain.x;           //              replace by these 4 lines to reconstruct old rect\r
+           rcMain.right  = wpMain.x + wpMain.width;\r
+           rcMain.top    = wpMain.y;\r
+           rcMain.bottom = wpMain.y + wpMain.height;\r
             \r
             ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );\r
             ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );\r
             ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );\r
+            ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );\r
+            ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );\r
+           wpMain.x = lpwp->x;\r
+            wpMain.y = lpwp->y;\r
         }\r
     }\r
     break;\r
@@ -6387,7 +5623,7 @@ MyLoadSound(MySound *ms)
   struct stat st;\r
   FILE *f;\r
 \r
-  if (ms->data) free(ms->data);\r
+  if (ms->data && ms->flag) free(ms->data);\r
   ms->data = NULL;\r
 \r
   switch (ms->name[0]) {\r
@@ -6408,6 +5644,7 @@ MyLoadSound(MySound *ms)
       HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");\r
       if (h == NULL) break;\r
       ms->data = (void *)LoadResource(hInst, h);\r
+      ms->flag = 0; // not maloced, so cannot be freed!\r
       if (h == NULL) break;\r
       ok = TRUE;\r
     }\r
@@ -6418,6 +5655,7 @@ MyLoadSound(MySound *ms)
     if (f == NULL) break;\r
     if (fstat(fileno(f), &st) < 0) break;\r
     ms->data = malloc(st.st_size);\r
+    ms->flag = 1;\r
     if (fread(ms->data, st.st_size, 1, f) < 1) break;\r
     fclose(f);\r
     ok = TRUE;\r
@@ -6425,7 +5663,7 @@ MyLoadSound(MySound *ms)
   }\r
   if (!ok) {\r
     char buf[MSG_SIZ];\r
-    sprintf(buf, "Error loading sound %s", ms->name);\r
+      snprintf(buf, MSG_SIZ, _("Error loading sound %s"), ms->name);\r
     DisplayError(buf, GetLastError());\r
   }\r
   return ok;\r
@@ -6435,8 +5673,11 @@ BOOLEAN
 MyPlaySound(MySound *ms)\r
 {\r
   BOOLEAN ok = FALSE;\r
+\r
+  if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted\r
   switch (ms->name[0]) {\r
   case NULLCHAR:\r
+       if(appData.debugMode) fprintf(debugFP, "silence\n");\r
     /* Silence */\r
     ok = TRUE;\r
     break;\r
@@ -6466,13 +5707,6 @@ MyPlaySound(MySound *ms)
   /* Don't print an error: this can happen innocently if the sound driver\r
      is busy; for instance, if another instance of WinBoard is playing\r
      a sound at about the same time. */\r
-#if 0\r
-  if (!ok) {\r
-    char buf[MSG_SIZ];\r
-    sprintf(buf, "Error playing sound %s", ms->name);\r
-    DisplayError(buf, GetLastError());\r
-  }\r
-#endif\r
   return ok;\r
 }\r
 \r
@@ -6495,6 +5729,7 @@ OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
       number = NULL;\r
     }\r
     CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));\r
+    Translate(hDlg, 1536);\r
     return FALSE;  /* Allow for further processing */\r
 \r
   case WM_COMMAND:\r
@@ -6514,6 +5749,7 @@ OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
   OFNOTIFY *ofnot;\r
   switch (uiMsg) {\r
   case WM_INITDIALOG:\r
+    Translate(hdlg, DLG_IndexNumber);\r
     ofname = (OPENFILENAME *)lParam;\r
     number = (UINT *)(ofname->lCustData);\r
     break;\r
@@ -6539,12 +5775,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
@@ -6577,13 +5813,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
@@ -6601,6 +5837,7 @@ MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
    * menu that TrackPopupMenu displays.\r
    */\r
   hmenuTrackPopup = GetSubMenu(hmenu, 0);\r
+  TranslateOneMenu(10, hmenuTrackPopup);\r
 \r
   SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);\r
 \r
@@ -6743,7 +5980,7 @@ InitComboStrings(HANDLE hwndCombo, char **cd)
   SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);\r
 \r
   while (*cd != NULL) {\r
-    SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);\r
+    SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) T_(*cd));\r
     cd++;\r
   }\r
 }\r
@@ -6751,7 +5988,7 @@ InitComboStrings(HANDLE hwndCombo, char **cd)
 void\r
 InitComboStringsFromOption(HANDLE hwndCombo, char *str)\r
 {\r
-  char buf1[ARG_MAX];\r
+  char buf1[MAX_ARG_LEN];\r
   int len;\r
 \r
   if (str[0] == '@') {\r
@@ -6784,7 +6021,7 @@ SetStartupDialogEnables(HWND hDlg)
 {\r
   EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),\r
     IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||\r
-    appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer));\r
+    (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));\r
   EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),\r
     IsDlgButtonChecked(hDlg, OPT_ChessEngine));\r
   EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),\r
@@ -6822,10 +6059,10 @@ InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir,
 \r
   InitComboStringsFromOption(hwndCombo, nthnames);\r
   q = QuoteForFilename(nthcp);\r
-  sprintf(buf, "%s%s%s", q, nthcp, q);\r
+    snprintf(buf, MSG_SIZ, "%s%s%s", q, nthcp, q);\r
   if (*nthdir != NULLCHAR) {\r
     q = QuoteForFilename(nthdir);\r
-    sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);\r
+      snprintf(buf + strlen(buf), MSG_SIZ, " /%s=%s%s%s", nthd, q, nthdir, q);\r
   }\r
   if (*nthcp == NULLCHAR) {\r
     SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);\r
@@ -6846,16 +6083,17 @@ StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
   case WM_INITDIALOG:\r
     /* Center the dialog */\r
     CenterWindow (hDlg, GetDesktopWindow());\r
+    Translate(hDlg, DLG_Startup);\r
     /* Initialize the dialog items */\r
     InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),\r
                  appData.firstChessProgram, "fd", appData.firstDirectory,\r
                  firstChessProgramNames);\r
     InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),\r
-                 appData.secondChessProgram, "sd", appData.secondDirectory,\r
-                 secondChessProgramNames);\r
+                 appData.secondChessProgram, singleList ? "fd" : "sd", appData.secondDirectory,\r
+                 singleList ? firstChessProgramNames : secondChessProgramNames); //[HGM] single: use first list in second combo\r
     hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);\r
     InitComboStringsFromOption(hwndCombo, icsNames);    \r
-    sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);\r
+      snprintf(buf, MSG_SIZ, "%s /icsport=%s", appData.icsHost, appData.icsPort);\r
     if (*appData.icsHelper != NULLCHAR) {\r
       char *q = QuoteForFilename(appData.icsHelper);\r
       sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);\r
@@ -6885,23 +6123,25 @@ StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
     switch (LOWORD(wParam)) {\r
     case IDOK:\r
       if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {\r
-        strcpy(buf, "/fcp=");\r
+        safeStrCpy(buf, "/fcp=", sizeof(buf)/sizeof(buf[0]) );\r
        GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));\r
         p = buf;\r
        ParseArgs(StringGet, &p);\r
-        strcpy(buf, "/scp=");\r
+       safeStrCpy(buf, singleList ? "/fcp=" : "/scp=", sizeof(buf)/sizeof(buf[0]) );\r
        GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));\r
-        p = buf;\r
+        p = buf;
+       SwapEngines(singleList); // temporarily swap first and second, to load a second 'first', ...\r
        ParseArgs(StringGet, &p);\r
+       SwapEngines(singleList); // ... and then make it 'second'\r
        appData.noChessProgram = FALSE;\r
        appData.icsActive = FALSE;\r
       } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {\r
-        strcpy(buf, "/ics /icshost=");\r
+        safeStrCpy(buf, "/ics /icshost=", sizeof(buf)/sizeof(buf[0]) );\r
        GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));\r
         p = buf;\r
        ParseArgs(StringGet, &p);\r
        if (appData.zippyPlay) {\r
-         strcpy(buf, "/fcp=");\r
+         safeStrCpy(buf, "/fcp=", sizeof(buf)/sizeof(buf[0]) );\r
          GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));\r
          p = buf;\r
          ParseArgs(StringGet, &p);\r
@@ -6910,8 +6150,8 @@ StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
        appData.noChessProgram = TRUE;\r
        appData.icsActive = FALSE;\r
       } else {\r
-       MessageBox(hDlg, "Choose an option, or cancel to exit",\r
-                  "Option Error", MB_OK|MB_ICONEXCLAMATION);\r
+       MessageBox(hDlg, _("Choose an option, or cancel to exit"),\r
+                  _("Option Error"), MB_OK|MB_ICONEXCLAMATION);\r
        return TRUE;\r
       }\r
       if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {\r
@@ -6929,7 +6169,7 @@ StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
     case IDM_HELPCONTENTS:\r
       if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {\r
        MessageBox (GetFocus(),\r
-                   "Unable to activate help",\r
+                   _("Unable to activate help"),\r
                    szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);\r
       }\r
       break;\r
@@ -6958,6 +6198,8 @@ About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
     /* Center the dialog over the application window */\r
     CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));\r
     SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);\r
+    Translate(hDlg, ABOUTBOX);\r
+    JAWS_COPYRIGHT\r
     return (TRUE);\r
 \r
   case WM_COMMAND: /* message: received a command */\r
@@ -6990,6 +6232,7 @@ CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
   switch (message) {\r
   case WM_INITDIALOG: /* message: initialize dialog box */\r
     /* Initialize the dialog items */\r
+    Translate(hDlg, DLG_EditComment);\r
     hwndText = GetDlgItem(hDlg, OPT_CommentText);\r
     SetDlgItemText(hDlg, OPT_CommentText, commentText);\r
     EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);\r
@@ -7012,18 +6255,18 @@ CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
       GetClientRect(hDlg, &rect);\r
       sizeX = rect.right;\r
       sizeY = rect.bottom;\r
-      if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&\r
-         commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {\r
+      if (wpComment.x != CW_USEDEFAULT && wpComment.y != CW_USEDEFAULT &&\r
+         wpComment.width != CW_USEDEFAULT && wpComment.height != CW_USEDEFAULT) {\r
        WINDOWPLACEMENT wp;\r
-       EnsureOnScreen(&commentX, &commentY);\r
+       EnsureOnScreen(&wpComment.x, &wpComment.y, 0, 0);\r
        wp.length = sizeof(WINDOWPLACEMENT);\r
        wp.flags = 0;\r
        wp.showCmd = SW_SHOW;\r
        wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;\r
-       wp.rcNormalPosition.left = commentX;\r
-       wp.rcNormalPosition.right = commentX + commentW;\r
-       wp.rcNormalPosition.top = commentY;\r
-       wp.rcNormalPosition.bottom = commentY + commentH;\r
+       wp.rcNormalPosition.left = wpComment.x;\r
+       wp.rcNormalPosition.right = wpComment.x + wpComment.width;\r
+       wp.rcNormalPosition.top = wpComment.y;\r
+       wp.rcNormalPosition.bottom = wpComment.y + wpComment.height;\r
        SetWindowPlacement(hDlg, &wp);\r
 \r
        GetClientRect(hDlg, &rect);\r
@@ -7035,6 +6278,7 @@ CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
        sizeY = newSizeY;\r
       }\r
     }\r
+    SendDlgItemMessage( hDlg, OPT_CommentText, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS | ENM_KEYEVENTS );\r
     return FALSE;\r
 \r
   case WM_COMMAND: /* message: received a command */\r
@@ -7079,6 +6323,42 @@ CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
     }\r
     break;\r
 \r
+  case WM_NOTIFY: // [HGM] vari: cloned from whistory.c\r
+        if( wParam == OPT_CommentText ) {\r
+            MSGFILTER * lpMF = (MSGFILTER *) lParam;\r
+\r
+            if( lpMF->msg == WM_RBUTTONDOWN && (lpMF->wParam & (MK_CONTROL | MK_SHIFT)) == 0 ||\r
+                lpMF->msg == WM_CHAR && lpMF->wParam == '\022' ) {\r
+                POINTL pt;\r
+                LRESULT index;\r
+\r
+                pt.x = LOWORD( lpMF->lParam );\r
+                pt.y = HIWORD( lpMF->lParam );\r
+\r
+                if(lpMF->msg == WM_CHAR) {\r
+                        CHARRANGE sel;\r
+                        SendDlgItemMessage( hDlg, OPT_CommentText, EM_EXGETSEL, 0, (LPARAM) &sel );\r
+                        index = sel.cpMin;\r
+                } else\r
+                index = SendDlgItemMessage( hDlg, OPT_CommentText, EM_CHARFROMPOS, 0, (LPARAM) &pt );\r
+\r
+               hwndText = GetDlgItem(hDlg, OPT_CommentText); // cloned from above\r
+               len = GetWindowTextLength(hwndText);\r
+               str = (char *) malloc(len + 1);\r
+               GetWindowText(hwndText, str, len + 1);\r
+               ReplaceComment(commentIndex, str);\r
+               if(commentIndex != currentMove) ToNrEvent(commentIndex);\r
+                LoadVariation( index, str ); // [HGM] also does the actual moving to it, now\r
+               free(str);\r
+\r
+                /* Zap the message for good: apparently, returning non-zero is not enough */\r
+                lpMF->msg = WM_USER;\r
+\r
+                return TRUE;\r
+            }\r
+        }\r
+        break;\r
+\r
   case WM_SIZE:\r
     newSizeX = LOWORD(lParam);\r
     newSizeY = HIWORD(lParam);\r
@@ -7103,7 +6383,7 @@ EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
   FARPROC lpProc;\r
   char *p, *q;\r
 \r
-  CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);\r
+  CheckMenuItem(GetMenu(hwndMain), IDM_Comment, edit ? MF_CHECKED : MF_UNCHECKED);\r
 \r
   if (str == NULL) str = "";\r
   p = (char *) malloc(2 * strlen(str) + 2);\r
@@ -7122,14 +6402,14 @@ EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
 \r
   if (commentDialog) {\r
     SendMessage(commentDialog, WM_INITDIALOG, 0, 0);\r
-    if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);\r
+    if (!commentUp) ShowWindow(commentDialog, SW_SHOW);\r
   } else {\r
     lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);\r
     CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),\r
                 hwndMain, (DLGPROC)lpProc);\r
     FreeProcInstance(lpProc);\r
   }\r
-  commentDialogUp = TRUE;\r
+  commentUp = TRUE;\r
 }\r
 \r
 \r
@@ -7144,15 +6424,13 @@ TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
 {\r
   char move[MSG_SIZ];\r
   HWND hInput;\r
-  ChessMove moveType;\r
-  int fromX, fromY, toX, toY;\r
-  char promoChar;\r
 \r
   switch (message) {\r
   case WM_INITDIALOG:\r
     move[0] = (char) lParam;\r
     move[1] = NULLCHAR;\r
     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
@@ -7161,21 +6439,11 @@ TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
 \r
   case WM_COMMAND:\r
     switch (LOWORD(wParam)) {\r
-    case IDOK:\r
-      if (gameMode != EditGame && currentMove != forwardMostMove && \r
-       gameMode != Training) {\r
-       DisplayMoveError("Displayed move is not current");\r
-      } else {\r
-       GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));\r
-       if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove, \r
-         &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {\r
-         if (gameMode != Training)\r
-             forwardMostMove = currentMove;\r
-         UserMoveEvent(fromX, fromY, toX, toY, promoChar);     \r
-       } else {\r
-         DisplayMoveError("Could not parse move");\r
-       }\r
-      }\r
+    case IDOK:
+\r
+      shiftKey = GetKeyState(VK_SHIFT) < 0; // [HGM] remember last shift status\r
+      GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
+      TypeInDoneEvent(move);\r
       EndDialog(hDlg, TRUE);\r
       return TRUE;\r
     case IDCANCEL:\r
@@ -7193,18 +6461,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
-       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
@@ -7224,6 +6485,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
@@ -7235,6 +6497,13 @@ TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
     case IDOK:\r
       GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));\r
       appData.userName = strdup(move);\r
+      SetUserLogo();\r
+      SetGameInfo();\r
+      if(gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack) {\r
+       snprintf(move, MSG_SIZ, "%s vs. %s", gameInfo.white, gameInfo.black);\r
+       DisplayTitle(move);\r
+      }\r
+\r
 \r
       EndDialog(hDlg, TRUE);\r
       return TRUE;\r
@@ -7313,6 +6582,7 @@ ErrorPopDown()
   if (errorDialog == NULL) return;\r
   DestroyWindow(errorDialog);\r
   errorDialog = NULL;\r
+  if(errorExitStatus) ExitEvent(errorExitStatus);\r
 }\r
 \r
 LRESULT CALLBACK\r
@@ -7338,6 +6608,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
@@ -7375,7 +6646,7 @@ GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
   case WM_INITDIALOG:\r
     GetWindowRect(hDlg, &rChild);\r
 \r
-    SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,\r
+    SetWindowPos(hDlg, NULL, wpMain.x, wpMain.y-height, wpMain.width, height,\r
                                                              SWP_NOZORDER);\r
 \r
     /* \r
@@ -7410,8 +6681,6 @@ VOID
 GothicPopUp(char *title, VariantClass variant)\r
 {\r
   FARPROC lpProc;\r
-  char *p, *q;\r
-  BOOLEAN modal = hwndMain == NULL;\r
   static char *lastTitle;\r
 \r
   strncpy(errorTitle, title, sizeof(errorTitle));\r
@@ -7477,76 +6746,7 @@ NextInHistory()
 {\r
   if (histP == histIn) return NULL;\r
   histP = (histP + 1) % HISTORY_SIZE;\r
-  return history[histP];\r
-}\r
-\r
-typedef struct {\r
-  char *item;\r
-  char *command;\r
-  BOOLEAN getname;\r
-  BOOLEAN immediate;\r
-} IcsTextMenuEntry;\r
-#define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)\r
-IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];\r
-\r
-void\r
-ParseIcsTextMenu(char *icsTextMenuString)\r
-{\r
-  int flags = 0;\r
-  IcsTextMenuEntry *e = icsTextMenuEntry;\r
-  char *p = icsTextMenuString;\r
-  while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {\r
-    free(e->item);\r
-    e->item = NULL;\r
-    if (e->command != NULL) {\r
-      free(e->command);\r
-      e->command = NULL;\r
-    }\r
-    e++;\r
-  }\r
-  e = icsTextMenuEntry;\r
-  while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {\r
-    if (*p == ';' || *p == '\n') {\r
-      e->item = strdup("-");\r
-      e->command = NULL;\r
-      p++;\r
-    } else if (*p == '-') {\r
-      e->item = strdup("-");\r
-      e->command = NULL;\r
-      p++;\r
-      if (*p) p++;\r
-    } else {\r
-      char *q, *r, *s, *t;\r
-      char c;\r
-      q = strchr(p, ',');\r
-      if (q == NULL) break;\r
-      *q = NULLCHAR;\r
-      r = strchr(q + 1, ',');\r
-      if (r == NULL) break;\r
-      *r = NULLCHAR;\r
-      s = strchr(r + 1, ',');\r
-      if (s == NULL) break;\r
-      *s = NULLCHAR;\r
-      c = ';';\r
-      t = strchr(s + 1, c);\r
-      if (t == NULL) {\r
-       c = '\n';\r
-       t = strchr(s + 1, c);\r
-      }\r
-      if (t != NULL) *t = NULLCHAR;\r
-      e->item = strdup(p);\r
-      e->command = strdup(q + 1);\r
-      e->getname = *(r + 1) != '0';\r
-      e->immediate = *(s + 1) != '0';\r
-      *q = ',';\r
-      *r = ',';\r
-      *s = ',';\r
-      if (t == NULL) break;\r
-      *t = c;\r
-      p = t + 1;\r
-    }\r
-    e++;\r
-  } \r
+  return history[histP];   \r
 }\r
 \r
 HMENU\r
@@ -7559,13 +6759,14 @@ LoadIcsTextMenu(IcsTextMenuEntry *e)
   while (e->item) {\r
     if (strcmp(e->item, "-") == 0) {\r
       AppendMenu(h, MF_SEPARATOR, 0, 0);\r
-    } else {\r
+    } else { // [HGM] re-written a bit to use only one AppendMenu call for both cases (| or no |)\r
+      int flags = MF_STRING, j = 0;\r
       if (e->item[0] == '|') {\r
-       AppendMenu(h, MF_STRING|MF_MENUBARBREAK,\r
-                  IDM_CommandX + i, &e->item[1]);\r
-      } else {\r
-       AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);\r
+       flags |= MF_MENUBARBREAK;\r
+        j++;\r
       }\r
+      if(!strcmp(e->command, "none")) flags |= MF_GRAYED; // [HGM] chatclick: provide inactive dummy\r
+      AppendMenu(h, flags, IDM_CommandX + i, e->item + j);\r
     }\r
     e++;\r
     i++;\r
@@ -7630,11 +6831,13 @@ CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
     SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);\r
   }\r
   if (immediate) {\r
-    sprintf(buf, "%s %s", command, name);\r
+    if(strstr(command, "%s")) snprintf(buf, MSG_SIZ, command, name); else\r
+    snprintf(buf, MSG_SIZ, "%s %s", command, name);\r
     SetWindowText(hInput, buf);\r
     SendMessage(hInput, WM_CHAR, '\r', 0);\r
   } else {\r
-    sprintf(buf, "%s %s ", command, name); /* trailing space */\r
+    if(!strcmp(command, "chat")) { ChatPopUp(name); return; }\r
+      snprintf(buf, MSG_SIZ, "%s %s ", command, name); /* trailing space */\r
     SetWindowText(hInput, buf);\r
     sel.cpMin = 999999;\r
     sel.cpMax = 999999;\r
@@ -7652,6 +6855,7 @@ ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
   switch (message) {\r
   case WM_KEYDOWN:\r
     if (!(GetKeyState(VK_CONTROL) & ~1)) break;\r
+    if(wParam=='R') return 0;\r
     switch (wParam) {\r
     case VK_PRIOR:\r
       SendMessage(hwnd, EM_LINESCROLL, 0, -999999);\r
@@ -7665,6 +6869,7 @@ ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     }\r
     break;\r
   case WM_CHAR:\r
+   if(wParam != '\022') {\r
     if (wParam == '\t') {\r
       if (GetKeyState(VK_SHIFT) < 0) {\r
        /* shifted */\r
@@ -7680,16 +6885,12 @@ ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       }\r
     } else {\r
       hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);\r
-      SetFocus(hInput);\r
+      JAWS_DELETE( SetFocus(hInput); )\r
       SendMessage(hInput, message, wParam, lParam);\r
     }\r
     return 0;\r
-  case WM_PASTE:\r
-    hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);\r
-    SetFocus(hInput);\r
-    return SendMessage(hInput, message, wParam, lParam);\r
-  case WM_MBUTTONDOWN:\r
-    return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);\r
+   } // [HGM] navigate: for Ctrl+R, flow into next case (moved up here) to summon up menu\r
+   lParam = -1;\r
   case WM_RBUTTONDOWN:\r
     if (!(GetKeyState(VK_SHIFT) & ~1)) {\r
       /* Move selection here if it was empty */\r
@@ -7698,18 +6899,12 @@ ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       pt.y = HIWORD(lParam);\r
       SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);\r
       if (sel.cpMin == sel.cpMax) {\r
-        sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/\r
+        if(lParam != -1) sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/\r
        sel.cpMax = sel.cpMin;\r
        SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);\r
       }\r
       SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);\r
-    }\r
-    return 0;\r
-  case WM_RBUTTONUP:\r
-    if (GetKeyState(VK_SHIFT) & ~1) {\r
-      SendDlgItemMessage(hwndConsole, OPT_ConsoleText, \r
-        WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);\r
-    } else {\r
+{ // [HGM] chatclick: code moved here from WM_RBUTTONUP case, to have menu appear on down-click\r
       POINT pt;\r
       HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);\r
       SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);\r
@@ -7720,11 +6915,25 @@ ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       if (!IsClipboardFormatAvailable(CF_TEXT)) {\r
         EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);\r
       }\r
-      pt.x = LOWORD(lParam);\r
-      pt.y = HIWORD(lParam);\r
+      pt.x = LOWORD(lParam)-30; // [HGM] chatclick: make menu pop up with pointer above upper-right item\r
+      pt.y = HIWORD(lParam)-10; //       make it appear as if mouse moved there, so it will be selected on up-click\r
+      PostMessage(hwnd, WM_MOUSEMOVE, wParam, lParam+5);\r
       MenuPopup(hwnd, pt, hmenu, -1);\r
+}\r
     }\r
     return 0;\r
+  case WM_RBUTTONUP:\r
+    if (GetKeyState(VK_SHIFT) & ~1) {\r
+      SendDlgItemMessage(hwndConsole, OPT_ConsoleText, \r
+        WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);\r
+    }\r
+    return 0;\r
+  case WM_PASTE:\r
+    hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);\r
+    SetFocus(hInput);\r
+    return SendMessage(hInput, message, wParam, lParam);\r
+  case WM_MBUTTONDOWN:\r
+    return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);\r
   case WM_COMMAND:\r
     switch (LOWORD(wParam)) {\r
     case IDM_QuickPaste:\r
@@ -7841,6 +7050,7 @@ ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     case '\021': /* Ctrl+Q */\r
       quoteNextChar = TRUE;\r
       return 0;\r
+    JAWS_REPLAY\r
     default:\r
       break;\r
     }\r
@@ -7935,24 +7145,41 @@ LRESULT CALLBACK
 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
 {\r
   static SnapData sd;\r
-  static HWND hText, hInput, hFocus;\r
-  InputSource *is = consoleInputSource;\r
+  HWND hText, hInput;\r
   RECT rect;\r
   static int sizeX, sizeY;\r
   int newSizeX, newSizeY;\r
   MINMAXINFO *mmi;\r
+  WORD wMask;\r
+\r
+  hText = GetDlgItem(hDlg, OPT_ConsoleText);\r
+  hInput = GetDlgItem(hDlg, OPT_ConsoleInput);\r
 \r
   switch (message) {\r
+  case WM_NOTIFY:\r
+    if (((NMHDR*)lParam)->code == EN_LINK)\r
+    {\r
+      ENLINK *pLink = (ENLINK*)lParam;\r
+      if (pLink->msg == WM_LBUTTONUP)\r
+      {\r
+        TEXTRANGE tr;\r
+\r
+        tr.chrg = pLink->chrg;\r
+        tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);\r
+        SendMessage(hText, EM_GETTEXTRANGE, 0, (LPARAM)&tr);\r
+        ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);\r
+        free(tr.lpstrText);\r
+      }\r
+    }\r
+    break;\r
   case WM_INITDIALOG: /* message: initialize dialog box */\r
     hwndConsole = hDlg;\r
-    hText = GetDlgItem(hDlg, OPT_ConsoleText);\r
-    hInput = GetDlgItem(hDlg, OPT_ConsoleInput);\r
     SetFocus(hInput);\r
     consoleTextWindowProc = (WNDPROC)\r
-      SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);\r
+      SetWindowLongPtr(hText, GWLP_WNDPROC, (LONG_PTR) ConsoleTextSubclass);\r
     SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);\r
     consoleInputWindowProc = (WNDPROC)\r
-      SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);\r
+      SetWindowLongPtr(hInput, GWLP_WNDPROC, (LONG_PTR) ConsoleInputSubclass);\r
     SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);\r
     Colorize(ColorNormal, TRUE);\r
     SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);\r
@@ -7960,40 +7187,46 @@ ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
     GetClientRect(hDlg, &rect);\r
     sizeX = rect.right;\r
     sizeY = rect.bottom;\r
-    if (consoleX != CW_USEDEFAULT && consoleY != CW_USEDEFAULT &&\r
-       consoleW != CW_USEDEFAULT && consoleH != CW_USEDEFAULT) {\r
+    if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&\r
+       wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {\r
       WINDOWPLACEMENT wp;\r
-      EnsureOnScreen(&consoleX, &consoleY);\r
+      EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);\r
       wp.length = sizeof(WINDOWPLACEMENT);\r
       wp.flags = 0;\r
       wp.showCmd = SW_SHOW;\r
       wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;\r
-      wp.rcNormalPosition.left = consoleX;\r
-      wp.rcNormalPosition.right = consoleX + consoleW;\r
-      wp.rcNormalPosition.top = consoleY;\r
-      wp.rcNormalPosition.bottom = consoleY + consoleH;\r
+      wp.rcNormalPosition.left = wpConsole.x;\r
+      wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;\r
+      wp.rcNormalPosition.top = wpConsole.y;\r
+      wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;\r
       SetWindowPlacement(hDlg, &wp);\r
     }\r
-#if 0 \r
+\r
    // [HGM] Chessknight's change 2004-07-13\r
    else { /* Determine Defaults */\r
        WINDOWPLACEMENT wp;\r
-       consoleX = winWidth + 1;\r
-       consoleY = boardY;\r
-       consoleW = screenWidth -  winWidth;\r
-       consoleH = winHeight;\r
-       EnsureOnScreen(&consoleX, &consoleY);\r
+       wpConsole.x = wpMain.width + 1;\r
+       wpConsole.y = wpMain.y;\r
+       wpConsole.width = screenWidth -  wpMain.width;\r
+       wpConsole.height = wpMain.height;\r
+       EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);\r
        wp.length = sizeof(WINDOWPLACEMENT);\r
        wp.flags = 0;\r
        wp.showCmd = SW_SHOW;\r
        wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;\r
-       wp.rcNormalPosition.left = consoleX;\r
-       wp.rcNormalPosition.right = consoleX + consoleW;\r
-       wp.rcNormalPosition.top = consoleY;\r
-       wp.rcNormalPosition.bottom = consoleY + consoleH;\r
+       wp.rcNormalPosition.left = wpConsole.x;\r
+       wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;\r
+       wp.rcNormalPosition.top = wpConsole.y;\r
+       wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;\r
        SetWindowPlacement(hDlg, &wp);\r
     }\r
-#endif\r
+\r
+   // Allow hText to highlight URLs and send notifications on them\r
+   wMask = (WORD) SendMessage(hText, EM_GETEVENTMASK, 0, 0L);\r
+   SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);\r
+   SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);\r
+   SetWindowLongPtr(hText, GWLP_USERDATA, 79); // initialize the text window's width\r
+\r
     return FALSE;\r
 \r
   case WM_SETFOCUS:\r
@@ -8053,6 +7286,7 @@ ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
     return OnMoving( &sd, hDlg, wParam, lParam );\r
 \r
   case WM_EXITSIZEMOVE:\r
+       UpdateICSWidth(hText);\r
     return OnExitSizeMove( &sd, hDlg, wParam, lParam );\r
   }\r
 \r
@@ -8171,7 +7405,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
@@ -8204,9 +7439,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: %s %s", color, 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
@@ -8221,10 +7456,22 @@ DisplayAClock(HDC hdc, int timeRemaining, int highlight,
   }\r
   oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);\r
 \r
+  JAWS_SILENCE\r
+\r
   ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,\r
             rect->top, ETO_CLIPPED|ETO_OPAQUE,\r
             rect, str, strlen(str), NULL);\r
-\r
+  if(logoHeight > 0 && appData.clockMode) {\r
+      RECT r;\r
+      str += strlen(color)+2;\r
+      r.top = rect->top + logoHeight/2;\r
+      r.left = rect->left;\r
+      r.right = rect->right;\r
+      r.bottom = rect->bottom;\r
+      ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,\r
+                r.top, ETO_CLIPPED|ETO_OPAQUE,\r
+                &r, str, strlen(str), NULL);\r
+  }\r
   (void) SetTextColor(hdc, oldFg);\r
   (void) SetBkColor(hdc, oldBg);\r
   (void) SelectObject(hdc, oldFont);\r
@@ -8301,7 +7548,7 @@ void CheckForInputBufferFull( InputSource * is )
 \r
         if( p >= is->next ) {\r
             if (appData.debugMode) {\r
-                fprintf( debugFP, "Input line exceeded buffer size (source id=%u)\n", is->id );\r
+                fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );\r
             }\r
 \r
             is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */\r
@@ -8350,7 +7597,7 @@ InputThread(LPVOID arg)
   CloseHandle(is->hFile);\r
 \r
   if (appData.debugMode) {\r
-    fprintf( debugFP, "Input thread terminated (id=%u, error=%d, count=%d)\n", is->id, is->error, is->count );\r
+    fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );\r
   }\r
 \r
   return 0;\r
@@ -8491,6 +7738,14 @@ typedef struct {
 } Enables;\r
 \r
 VOID\r
+GreyRevert(Boolean grey)\r
+{ // [HGM] vari: for retracting variations in local mode\r
+  HMENU hmenu = GetMenu(hwndMain);\r
+  EnableMenuItem(hmenu, IDM_Revert, MF_BYCOMMAND|(grey ? MF_GRAYED : MF_ENABLED));\r
+  EnableMenuItem(hmenu, IDM_Annotate, MF_BYCOMMAND|(grey ? MF_GRAYED : MF_ENABLED));\r
+}\r
+\r
+VOID\r
 SetMenuEnables(HMENU hmenu, Enables *enab)\r
 {\r
   while (enab->item > 0) {\r
@@ -8509,7 +7764,26 @@ Enables gnuEnables[] = {
   { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_Upload, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },\r
+\r
+  // Needed to switch from ncp to GNU mode on Engine Load\r
+  { ACTION_POS, MF_BYPOSITION|MF_ENABLED },\r
+  { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_Match, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_AnalyzeFile, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_Engine2Options, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_TimeControl, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_Book, MF_BYCOMMAND|MF_ENABLED },\r
   { -1, -1 }\r
 };\r
 \r
@@ -8519,21 +7793,29 @@ Enables icsEnables[] = {
   { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_Match, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },\r
   { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_Book, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_EditProgs2, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_Tourney, MF_BYCOMMAND|MF_GRAYED },\r
   { -1, -1 }\r
 };\r
 \r
-#ifdef ZIPPY\r
+#if ZIPPY\r
 Enables zippyEnables[] = {\r
   { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },\r
   { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },\r
   { IDM_Book, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },\r
   { -1, -1 }\r
 };\r
 #endif\r
@@ -8544,21 +7826,29 @@ Enables ncpEnables[] = {
   { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_Match, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },\r
   { ACTION_POS, MF_BYPOSITION|MF_GRAYED },\r
   { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_Book, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_Sounds, MF_BYCOMMAND|MF_GRAYED },\r
   { -1, -1 }\r
 };\r
 \r
 Enables trainingOnEnables[] = {\r
   { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_Comment, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },\r
@@ -8571,6 +7861,7 @@ Enables trainingOnEnables[] = {
 \r
 Enables trainingOffEnables[] = {\r
   { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_Comment, MF_BYCOMMAND|MF_ENABLED },\r
   { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },\r
   { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },\r
   { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },\r
@@ -8607,6 +7898,7 @@ Enables machineThinkingEnables[] = {
   { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },\r
+//  { IDM_Match, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },\r
   { -1, -1 }\r
@@ -8626,6 +7918,7 @@ Enables userThinkingEnables[] = {
   { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },\r
   { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },\r
   { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },\r
+//  { IDM_Match, MF_BYCOMMAND|MF_ENABLED },\r
   { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },\r
   { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },\r
   { -1, -1 }\r
@@ -8638,6 +7931,12 @@ Enables userThinkingEnables[] = {
  * \r
 \*---------------------------------------------------------------------------*/\r
 VOID\r
+CheckMark(UINT item, int state)\r
+{\r
+    if(item) CheckMenuItem(GetMenu(hwndMain), item, MF_BYCOMMAND|state);\r
+}\r
+\r
+VOID\r
 ModeHighlight()\r
 {\r
   static UINT prevChecked = 0;\r
@@ -8698,12 +7997,9 @@ ModeHighlight()
     nowChecked = 0;\r
     break;\r
   }\r
-  if (prevChecked != 0)\r
-    (void) CheckMenuItem(GetMenu(hwndMain),\r
-                        prevChecked, MF_BYCOMMAND|MF_UNCHECKED);\r
-  if (nowChecked != 0)\r
-    (void) CheckMenuItem(GetMenu(hwndMain),\r
-                        nowChecked, MF_BYCOMMAND|MF_CHECKED);\r
+  CheckMark(prevChecked, MF_UNCHECKED);\r
+  CheckMark(nowChecked, MF_CHECKED);\r
+  CheckMark(IDM_Match, matchMode && matchGame < appData.matchGames ? MF_CHECKED : MF_UNCHECKED);\r
 \r
   if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {\r
     (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training, \r
@@ -8718,13 +8014,12 @@ ModeHighlight()
   /* [DM] icsEngineAnalyze - Do a sceure check too */\r
   if (appData.icsActive) {\r
        if (appData.icsEngineAnalyze) {\r
-               (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,\r
-                       MF_BYCOMMAND|MF_CHECKED);\r
+               CheckMark(IDM_AnalysisMode, MF_CHECKED);\r
        } else {\r
-               (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,\r
-                       MF_BYCOMMAND|MF_UNCHECKED);\r
+               CheckMark(IDM_AnalysisMode, MF_UNCHECKED);\r
        }\r
   }\r
+  DisplayLogos(); // [HGM] logos: mode change could have altered logos\r
 }\r
 \r
 VOID\r
@@ -8732,9 +8027,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
@@ -8755,8 +8050,6 @@ SetNCPMode()
 {\r
   HMENU hmenu = GetMenu(hwndMain);\r
   SetMenuEnables(hmenu, ncpEnables);\r
-  EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,\r
-    MF_BYPOSITION|MF_GRAYED);\r
     DrawMenuBar(hwndMain);\r
 }\r
 \r
@@ -8808,7 +8101,7 @@ SetMachineThinkingEnables()
   } else if (gameMode == MachinePlaysWhite) {\r
     (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);\r
   } else if (gameMode == TwoMachinesPlay) {\r
-    (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);\r
+    (void)EnableMenuItem(hMenu, matchMode ? IDM_Match : IDM_TwoMachines, flags); // [HGM] match\r
   }\r
 }\r
 \r
@@ -8818,17 +8111,17 @@ DisplayTitle(char *str)
 {\r
   char title[MSG_SIZ], *host;\r
   if (str[0] != NULLCHAR) {\r
-    strcpy(title, str);\r
+    safeStrCpy(title, str, sizeof(title)/sizeof(title[0]) );\r
   } else if (appData.icsActive) {\r
     if (appData.icsCommPort[0] != NULLCHAR)\r
       host = "ICS";\r
     else \r
       host = appData.icsHost;\r
-    sprintf(title, "%s: %s", szTitle, host);\r
+      snprintf(title, MSG_SIZ, "%s: %s", szTitle, host);\r
   } else if (appData.noChessProgram) {\r
-    strcpy(title, szTitle);\r
+    safeStrCpy(title, szTitle, sizeof(title)/sizeof(title[0]) );\r
   } else {\r
-    strcpy(title, szTitle);\r
+    safeStrCpy(title, szTitle, sizeof(title)/sizeof(title[0]) );\r
     strcat(title, ": ");\r
     strcat(title, first.tidy);\r
   }\r
@@ -8862,9 +8155,13 @@ DisplayMessage(char *str1, char *str2)
     if (len > remain) len = remain;\r
     strncat(messageText, str2, len);\r
   }\r
-  messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;\r
+  messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
+  safeStrCpy(lastMsg, messageText, MSG_SIZ);
+\r
+  if (hwndMain == NULL || IsIconic(hwndMain)) return;\r
+\r
+  SAYMACHINEMOVE();\r
 \r
-  if (IsIconic(hwndMain)) return;\r
   hdc = GetDC(hwndMain);\r
   oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);\r
   ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,\r
@@ -8880,25 +8177,25 @@ DisplayError(char *str, int error)
   int len;\r
 \r
   if (error == 0) {\r
-    strcpy(buf, str);\r
+    safeStrCpy(buf, str, sizeof(buf)/sizeof(buf[0]) );\r
   } else {\r
     len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,\r
                        NULL, error, LANG_NEUTRAL,\r
                        (LPSTR) buf2, MSG_SIZ, NULL);\r
     if (len > 0) {\r
-      sprintf(buf, "%s:\n%s", str, buf2);\r
+      snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, buf2);\r
     } else {\r
       ErrorMap *em = errmap;\r
       while (em->err != 0 && em->err != error) em++;\r
       if (em->err != 0) {\r
-       sprintf(buf, "%s:\n%s", str, em->msg);\r
+       snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, em->msg);\r
       } else {\r
-       sprintf(buf, "%s:\nError code %d", str, error);\r
+       snprintf(buf, 2*MSG_SIZ, "%s:\nError code %d", str, error);\r
       }\r
     }\r
   }\r
   \r
-  ErrorPopUp("Error", buf);\r
+  ErrorPopUp(_("Error"), buf);\r
 }\r
 \r
 \r
@@ -8909,7 +8206,7 @@ DisplayMoveError(char *str)
   ClearHighlights();\r
   DrawPosition(FALSE, NULL);\r
   if (appData.popupMoveErrors) {\r
-    ErrorPopUp("Error", str);\r
+    ErrorPopUp(_("Error"), str);\r
   } else {\r
     DisplayMessage(str, "");\r
     moveErrorMessageUp = TRUE;\r
@@ -8921,21 +8218,21 @@ DisplayFatalError(char *str, int error, int exitStatus)
 {\r
   char buf[2*MSG_SIZ], buf2[MSG_SIZ];\r
   int len;\r
-  char *label = exitStatus ? "Fatal Error" : "Exiting";\r
+  char *label = exitStatus ? _("Fatal Error") : _("Exiting");\r
 \r
   if (error != 0) {\r
     len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,\r
                        NULL, error, LANG_NEUTRAL,\r
                        (LPSTR) buf2, MSG_SIZ, NULL);\r
     if (len > 0) {\r
-      sprintf(buf, "%s:\n%s", str, buf2);\r
+      snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, buf2);\r
     } else {\r
       ErrorMap *em = errmap;\r
       while (em->err != 0 && em->err != error) em++;\r
       if (em->err != 0) {\r
-       sprintf(buf, "%s:\n%s", str, em->msg);\r
+       snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, em->msg);\r
       } else {\r
-       sprintf(buf, "%s:\nError code %d", str, error);\r
+       snprintf(buf, 2*MSG_SIZ, "%s:\nError code %d", str, error);\r
       }\r
     }\r
     str = buf;\r
@@ -8954,14 +8251,14 @@ DisplayFatalError(char *str, int error, int exitStatus)
 VOID\r
 DisplayInformation(char *str)\r
 {\r
-  (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);\r
+  (void) MessageBox(hwndMain, str, _("Information"), MB_OK|MB_ICONINFORMATION);\r
 }\r
 \r
 \r
 VOID\r
 DisplayNote(char *str)\r
 {\r
-  ErrorPopUp("Note", str);\r
+  ErrorPopUp(_("Note"), str);\r
 }\r
 \r
 \r
@@ -8981,6 +8278,7 @@ QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
   case WM_INITDIALOG:\r
     qp = (QuestionParams *) lParam;\r
     CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));\r
+    Translate(hDlg, DLG_Question);\r
     SetWindowText(hDlg, qp->title);\r
     SetDlgItemText(hDlg, OPT_QuestionText, qp->question);\r
     SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));\r
@@ -8989,14 +8287,14 @@ QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
   case WM_COMMAND:\r
     switch (LOWORD(wParam)) {\r
     case IDOK:\r
-      strcpy(reply, qp->replyPrefix);\r
+      safeStrCpy(reply, qp->replyPrefix, sizeof(reply)/sizeof(reply[0]) );\r
       if (*reply) strcat(reply, " ");\r
       len = strlen(reply);\r
       GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);\r
       strcat(reply, "\n");\r
       OutputToProcess(qp->pr, reply, strlen(reply), &err);\r
       EndDialog(hDlg, TRUE);\r
-      if (err) DisplayFatalError("Error writing to chess program", err, 1);\r
+      if (err) DisplayFatalError(_("Error writing to chess program"), err, 1);\r
       return TRUE;\r
     case IDCANCEL:\r
       EndDialog(hDlg, FALSE);\r
@@ -9038,6 +8336,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
@@ -9064,7 +8363,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
@@ -9090,103 +8389,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
-    { 0, 0 }\r
-};\r
-\r
-const char * GLT_FindItem( char id )\r
-{\r
-    const char * result = 0;\r
-\r
-    GLT_Item * list = GLT_ItemInfo;\r
+/* [AS] Game list options. Refactored by HGM */\r
 \r
-    while( list->id != 0 ) {\r
-        if( list->id == id ) {\r
-            result = list->name;\r
-            break;\r
-        }\r
+HWND gameListOptionsDialog;\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
@@ -9207,20 +8445,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
@@ -9229,19 +8463,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
@@ -9249,13 +8471,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
@@ -9275,29 +8495,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
@@ -9307,6 +8525,11 @@ DrawPosition(int fullRedraw, Board board)
   HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board); \r
 }\r
 \r
+void NotifyFrontendLogin()\r
+{\r
+       if (hwndConsole)\r
+               UpdateICSWidth(GetDlgItem(hwndConsole, OPT_ConsoleText));\r
+}\r
 \r
 VOID\r
 ResetFrontEnd()\r
@@ -9321,6 +8544,7 @@ ResetFrontEnd()
     ReleaseCapture();\r
     DrawPosition(TRUE, NULL);\r
   }\r
+  TagsPopDown();\r
 }\r
 \r
 \r
@@ -9328,18 +8552,19 @@ VOID
 CommentPopUp(char *title, char *str)\r
 {\r
   HWND hwnd = GetActiveWindow();\r
-  EitherCommentPopUp(0, title, str, FALSE);\r
+  EitherCommentPopUp(currentMove, title, str, FALSE); // [HGM] vari: fake move index, rather than 0\r
+  SAY(str);\r
   SetActiveWindow(hwnd);\r
 }\r
 \r
 VOID\r
 CommentPopDown(void)\r
 {\r
-  CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);\r
+  CheckMenuItem(GetMenu(hwndMain), IDM_Comment, MF_UNCHECKED);\r
   if (commentDialog) {\r
     ShowWindow(commentDialog, SW_HIDE);\r
   }\r
-  commentDialogUp = FALSE;\r
+  commentUp = FALSE;\r
 }\r
 \r
 VOID\r
@@ -9381,6 +8606,12 @@ PlayAlarmSound()
   MyPlaySound(&sounds[(int)SoundAlarm]);\r
 }\r
 \r
+VOID\r
+PlayTellSound()\r
+{\r
+  MyPlaySound(&textAttribs[ColorTell].sound);\r
+}\r
+\r
 \r
 VOID\r
 EchoOn()\r
@@ -9429,7 +8660,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
@@ -9442,7 +8673,7 @@ HostName()
 \r
   if (!GetComputerName(buf, &bufsiz)) {\r
     /*DisplayError("Error getting host name", GetLastError());*/\r
-    strcpy(buf, "Unknown");\r
+    safeStrCpy(buf, _("Unknown"), sizeof(buf)/sizeof(buf[0]) );\r
   }\r
   return buf;\r
 }\r
@@ -9480,7 +8711,7 @@ DisplayWhiteClock(long timeRemaining, int highlight)
   hdc = GetDC(hwndMain);\r
   if (!IsIconic(hwndMain)) {\r
     DisplayAClock(hdc, timeRemaining, highlight, \r
-                       (logoHeight > 0 ? flipView: flipClock) ? &blackRect : &whiteRect, "White", flag);\r
+                       flipClock ? &blackRect : &whiteRect, _("White"), flag);\r
   }\r
   if (highlight && iconCurrent == iconBlack) {\r
     iconCurrent = iconWhite;\r
@@ -9504,7 +8735,7 @@ DisplayBlackClock(long timeRemaining, int highlight)
   hdc = GetDC(hwndMain);\r
   if (!IsIconic(hwndMain)) {\r
     DisplayAClock(hdc, timeRemaining, highlight, \r
-                       (logoHeight > 0 ? flipView: flipClock) ? &whiteRect : &blackRect, "Black", flag);\r
+                       flipClock ? &whiteRect : &blackRect, _("Black"), flag);\r
   }\r
   if (highlight && iconCurrent == iconWhite) {\r
     iconCurrent = iconBlack;\r
@@ -9552,7 +8783,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
@@ -9564,11 +8795,12 @@ void
 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)\r
 {\r
   if (delayedTimerEvent != 0) {\r
-    if (appData.debugMode) {\r
+    if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug\r
       fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");\r
     }\r
     KillTimer(hwndMain, delayedTimerEvent);\r
     delayedTimerEvent = 0;\r
+    if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it\r
     delayedTimerCallback();\r
   }\r
   delayedTimerCallback = cb;\r
@@ -9783,7 +9015,7 @@ DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
         result = TerminateProcess( cp->hProcess, 0 );\r
 \r
         if ( appData.debugMode) {\r
-            fprintf( debugFP, "Terminating process %u, result=%d\n", cp->pid, result );\r
+            fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );\r
         }\r
     }\r
     else if( signal == 10 ) {\r
@@ -9793,7 +9025,7 @@ DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
             result = TerminateProcess( cp->hProcess, 0 );\r
 \r
             if ( appData.debugMode) {\r
-                fprintf( debugFP, "Process %u still alive after timeout, killing... result=%d\n", cp->pid, result );\r
+                fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );\r
             }\r
 \r
         }\r
@@ -9855,9 +9087,9 @@ OpenTelnet(char *host, char *port, ProcRef *pr)
   char cmdLine[MSG_SIZ];\r
 \r
   if (port[0] == NULLCHAR) {\r
-    sprintf(cmdLine, "%s %s", appData.telnetProgram, host);\r
+    snprintf(cmdLine, MSG_SIZ, "%s %s", appData.telnetProgram, host);\r
   } else {\r
-    sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);\r
+    snprintf(cmdLine, MSG_SIZ, "%s %s %s", appData.telnetProgram, host, port);\r
   }\r
   return StartChildProcess(cmdLine, "", pr);\r
 }\r
@@ -9956,9 +9188,9 @@ OpenCommPort(char *name, ProcRef *pr)
   char fullname[MSG_SIZ];\r
 \r
   if (*name != '\\')\r
-    sprintf(fullname, "\\\\.\\%s", name);\r
+    snprintf(fullname, MSG_SIZ, "\\\\.\\%s", name);\r
   else\r
-    strcpy(fullname, name);\r
+    safeStrCpy(fullname, name, sizeof(fullname)/sizeof(fullname[0]) );\r
 \r
   h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,\r
                 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);\r
@@ -9990,7 +9222,7 @@ OpenCommPort(char *name, ProcRef *pr)
 int\r
 OpenLoopback(ProcRef *pr)\r
 {\r
-  DisplayFatalError("Not implemented", 0, 1);\r
+  DisplayFatalError(_("Not implemented"), 0, 1);\r
   return NO_ERROR;\r
 }\r
 \r
@@ -10128,7 +9360,7 @@ OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
     break;\r
   }\r
   prevStderrPort = fromPort; // remember port used\r
-  sprintf(stderrPortStr, "%d", fromPort);\r
+  snprintf(stderrPortStr, MSG_SIZ, "%d", fromPort);\r
 \r
   if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {\r
     err = WSAGetLastError();\r
@@ -10270,6 +9502,11 @@ RemoveInputSource(InputSourceRef isr)
   }\r
 }\r
 \r
+int no_wrap(char *message, int count)\r
+{\r
+    ConsoleOutput(message, count, FALSE);\r
+    return count;\r
+}\r
 \r
 int\r
 OutputToProcess(ProcRef pr, char *message, int count, int *outError)\r
@@ -10278,11 +9515,32 @@ OutputToProcess(ProcRef pr, char *message, int count, int *outError)
   int outCount = SOCKET_ERROR;\r
   ChildProc *cp = (ChildProc *) pr;\r
   static OVERLAPPED ovl;\r
+  static int line = 0;\r
 \r
-  if (pr == NoProc) {\r
-    ConsoleOutput(message, count, FALSE);\r
-    return count;\r
-  } \r
+  if (pr == NoProc)\r
+  {\r
+    if (appData.noJoin || !appData.useInternalWrap)\r
+      return no_wrap(message, count);\r
+    else\r
+    {\r
+      int width = get_term_width();\r
+      int len = wrap(NULL, message, count, width, &line);\r
+      char *msg = malloc(len);\r
+      int dbgchk;\r
+\r
+      if (!msg)\r
+        return no_wrap(message, count);\r
+      else\r
+      {\r
+        dbgchk = wrap(msg, message, count, width, &line);\r
+        if (dbgchk != len && appData.debugMode)\r
+            fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);\r
+        ConsoleOutput(msg, len, FALSE);\r
+        free(msg);\r
+        return len;\r
+      }\r
+    }\r
+  }\r
 \r
   if (ovl.hEvent == NULL) {\r
     ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);\r
@@ -10334,7 +9592,7 @@ void
 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,\r
                        char *buf, int count, int error)\r
 {\r
-  DisplayFatalError("Not implemented", 0, 1);\r
+  DisplayFatalError(_("Not implemented"), 0, 1);\r
 }\r
 \r
 /* see wgamelist.c for Game List functions */\r
@@ -10366,131 +9624,6 @@ StartAnalysisClock()
                                        (UINT) 2000, NULL);\r
 }\r
 \r
-LRESULT CALLBACK\r
-AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
-{\r
-  static HANDLE hwndText;\r
-  RECT rect;\r
-  static int sizeX, sizeY;\r
-  int newSizeX, newSizeY, flags;\r
-  MINMAXINFO *mmi;\r
-\r
-  switch (message) {\r
-  case WM_INITDIALOG: /* message: initialize dialog box */\r
-    /* Initialize the dialog items */\r
-    hwndText = GetDlgItem(hDlg, OPT_AnalysisText);\r
-    SetWindowText(hDlg, analysisTitle);\r
-    SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);\r
-    /* Size and position the dialog */\r
-    if (!analysisDialog) {\r
-      analysisDialog = hDlg;\r
-      flags = SWP_NOZORDER;\r
-      GetClientRect(hDlg, &rect);\r
-      sizeX = rect.right;\r
-      sizeY = rect.bottom;\r
-      if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&\r
-         analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {\r
-       WINDOWPLACEMENT wp;\r
-       EnsureOnScreen(&analysisX, &analysisY);\r
-       wp.length = sizeof(WINDOWPLACEMENT);\r
-       wp.flags = 0;\r
-       wp.showCmd = SW_SHOW;\r
-       wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;\r
-       wp.rcNormalPosition.left = analysisX;\r
-       wp.rcNormalPosition.right = analysisX + analysisW;\r
-       wp.rcNormalPosition.top = analysisY;\r
-       wp.rcNormalPosition.bottom = analysisY + analysisH;\r
-       SetWindowPlacement(hDlg, &wp);\r
-\r
-       GetClientRect(hDlg, &rect);\r
-       newSizeX = rect.right;\r
-       newSizeY = rect.bottom;\r
-        ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,\r
-                             newSizeX, newSizeY);\r
-       sizeX = newSizeX;\r
-       sizeY = newSizeY;\r
-      }\r
-    }\r
-    return FALSE;\r
-\r
-  case WM_COMMAND: /* message: received a command */\r
-    switch (LOWORD(wParam)) {\r
-    case IDCANCEL:\r
-      if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */\r
-          ExitAnalyzeMode();\r
-          ModeHighlight();\r
-          return TRUE;\r
-      }\r
-      EditGameEvent();\r
-      return TRUE;\r
-    default:\r
-      break;\r
-    }\r
-    break;\r
-\r
-  case WM_SIZE:\r
-    newSizeX = LOWORD(lParam);\r
-    newSizeY = HIWORD(lParam);\r
-    ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);\r
-    sizeX = newSizeX;\r
-    sizeY = newSizeY;\r
-    break;\r
-\r
-  case WM_GETMINMAXINFO:\r
-    /* Prevent resizing window too small */\r
-    mmi = (MINMAXINFO *) lParam;\r
-    mmi->ptMinTrackSize.x = 100;\r
-    mmi->ptMinTrackSize.y = 100;\r
-    break;\r
-  }\r
-  return FALSE;\r
-}\r
-\r
-VOID\r
-AnalysisPopUp(char* title, char* str)\r
-{\r
-  FARPROC lpProc;\r
-  char *p, *q;\r
-\r
-  /* [AS] */\r
-  EngineOutputPopUp();\r
-  return;\r
-\r
-  if (str == NULL) str = "";\r
-  p = (char *) malloc(2 * strlen(str) + 2);\r
-  q = p;\r
-  while (*str) {\r
-    if (*str == '\n') *q++ = '\r';\r
-    *q++ = *str++;\r
-  }\r
-  *q = NULLCHAR;\r
-  if (analysisText != NULL) free(analysisText);\r
-  analysisText = p;\r
-\r
-  if (analysisDialog) {\r
-    SetWindowText(analysisDialog, title);\r
-    SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);\r
-    ShowWindow(analysisDialog, SW_SHOW);\r
-  } else {\r
-    analysisTitle = title;\r
-    lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);\r
-    CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),\r
-                hwndMain, (DLGPROC)lpProc);\r
-    FreeProcInstance(lpProc);\r
-  }\r
-  analysisDialogUp = TRUE;  \r
-}\r
-\r
-VOID\r
-AnalysisPopDown()\r
-{\r
-  if (analysisDialog) {\r
-    ShowWindow(analysisDialog, SW_HIDE);\r
-  }\r
-  analysisDialogUp = FALSE;  \r
-}\r
-\r
-\r
 VOID\r
 SetHighlights(int fromX, int fromY, int toX, int toY)\r
 {\r
@@ -10550,6 +9683,24 @@ static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
 #define kFactor 4\r
 \r
 void\r
+AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)\r
+{      // [HGM] atomic: animate blast wave\r
+       int i;\r
+\r
+       explodeInfo.fromX = fromX;\r
+       explodeInfo.fromY = fromY;\r
+       explodeInfo.toX = toX;\r
+       explodeInfo.toY = toY;\r
+       for(i=1; i<4*kFactor; i++) {\r
+           explodeInfo.radius = (i*180)/(4*kFactor-1);\r
+           DrawPosition(FALSE, board);\r
+           Sleep(appData.animSpeed);\r
+       }\r
+       explodeInfo.radius = 0;\r
+       DrawPosition(TRUE, board);\r
+}\r
+\r
+void\r
 AnimateMove(board, fromX, fromY, toX, toY)\r
      Board board;\r
      int fromX;\r
@@ -10571,17 +9722,17 @@ AnimateMove(board, fromX, fromY, toX, toY)
   ScreenSquare(fromX, fromY, &start);\r
   ScreenSquare(toX, toY, &finish);\r
 \r
-  /* All pieces except knights move in straight line */\r
-  if (piece != WhiteKnight && piece != BlackKnight) {\r
+  /* All moves except knight jumps move in straight line */\r
+  if (!(abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1)) {\r
     mid.x = start.x + (finish.x - start.x) / 2;\r
     mid.y = start.y + (finish.y - start.y) / 2;\r
   } else {\r
-    /* Knight: make diagonal movement then straight */\r
+    /* Knight: make straight movement then diagonal */\r
     if (abs(toY - fromY) < abs(toX - fromX)) {\r
        mid.x = start.x + (finish.x - start.x) / 2;\r
-       mid.y = finish.y;\r
+       mid.y = start.y;\r
      } else {\r
-       mid.x = finish.x;\r
+       mid.x = start.x;\r
        mid.y = start.y + (finish.y - start.y) / 2;\r
      }\r
   }\r
@@ -10607,6 +9758,7 @@ AnimateMove(board, fromX, fromY, toX, toY)
   animInfo.pos = finish;\r
   DrawPosition(FALSE, NULL);\r
   animInfo.piece = EmptySquare;\r
+  Explode(board, fromX, fromY, toX, toY);\r
 }\r
 \r
 /*      Convert board position to corner of screen rect and color       */\r
@@ -10670,30 +9822,31 @@ Tween(start, mid, finish, factor, frames, nFrames)
 void\r
 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )\r
 {\r
-#if 0\r
-    char buf[256];\r
-\r
-    sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",\r
-        first, last, current, current >= 0 ? movelist[current] : "n/a" );\r
-\r
-    OutputDebugString( buf );\r
-#endif\r
-\r
     MoveHistorySet( movelist, first, last, current, pvInfoList );\r
 \r
     EvalGraphSet( first, last, current, pvInfoList );\r
-}\r
 \r
-void SetProgramStats( FrontEndProgramStats * stats )\r
-{\r
-#if 0\r
-    char buf[1024];\r
-\r
-    sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",\r
-        stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );\r
+    MakeEngineOutputTitle();\r
+}\r
 \r
-    OutputDebugString( buf );\r
-#endif\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
 \r
-    EngineOutputUpdate( stats );\r
+int flock(int fid, int code)\r
+{\r
+    HANDLE hFile = (HANDLE) _get_osfhandle(fid);\r
+    OVERLAPPED ov;\r
+    ov.hEvent = NULL;\r
+    ov.Offset = 0;\r
+    ov.OffsetHigh = 0;\r
+    switch(code) {\r
+      case 1: LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1024, 0, &ov); break;   // LOCK_SH\r
+      case 2: LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1024, 0, &ov); break;   // LOCK_EX\r
+      case 3: UnlockFileEx(hFile, 0, 1024, 0, &ov); break; // LOCK_UN\r
+      default: return -1;\r
+    }\r
+    return 0;\r
 }\r