Updated copyright notice to 2013
[xboard.git] / winboard / winboard.c
index 36f7ca6..5249c92 100644 (file)
@@ -5,7 +5,7 @@
  * Massachusetts. \r
  *\r
  * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,\r
- * 2007, 2008, 2009, 2010 Free Software Foundation, Inc.\r
+ * 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.\r
  *\r
  * Enhancements Copyright 2005 Alessandro Scotti\r
  *\r
@@ -73,6 +73,7 @@
 #include <richedit.h>\r
 #include <mmsystem.h>\r
 #include <ctype.h>\r
+#include <io.h>\r
 \r
 #if __GNUC__\r
 #include <errno.h>\r
 extern int whiteFlag, blackFlag;\r
 Boolean flipClock = FALSE;\r
 extern HANDLE chatHandle[];\r
-extern int ics_type;\r
+extern enum ICS_TYPE ics_type;\r
 \r
+int  MySearchPath P((char *installDir, char *name, char *fullname));\r
+int  MyGetFullPathName P((char *name, char *fullname));\r
 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);\r
 VOID NewVariantPopup(HWND hwnd);\r
 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,\r
@@ -123,9 +126,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
@@ -160,7 +164,7 @@ BoardSize boardSize;
 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
+int squareSize, lineGap, minorSize, border;\r
 static int winW, winH;\r
 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo\r
 static int logoHeight = 0;\r
@@ -247,11 +251,12 @@ Boolean barbaric; // flag indicating if translation is needed
 #define ABOUTBOX -1  /* not sure why these are needed */\r
 #define ABOUTBOX2 -1\r
 \r
-int dialogItems[][40] = {\r
-{ ABOUTBOX, IDOK, 400 }, \r
+int dialogItems[][42] = {\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_LoadOptions, OPT_Autostep, OPT_AStext1, OPT_Exact, OPT_Subset, OPT_Struct, OPT_Material, OPT_Range, OPT_Difference,\r
+  OPT_elo1t, OPT_elo2t, OPT_datet, OPT_Stretch, OPT_Stretcht, OPT_Reversed, OPT_SearchMode, OPT_Mirror, OPT_thresholds, 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
@@ -282,7 +287,7 @@ int dialogItems[][40] = {
   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 }, \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
@@ -291,7 +296,7 @@ int dialogItems[][40] = {
   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
+  GPB_General, GPB_Alarm, OPT_AutoCreate }, \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
@@ -299,7 +304,7 @@ int dialogItems[][40] = {
   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
+  IDC_Light, IDC_Dark, IDC_White, IDC_Black, IDC_High, IDC_PreHigh, GPB_Size, OPT_Bitmaps, OPT_PieceFont, OPT_Grid }, \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
@@ -311,7 +316,8 @@ int dialogItems[][40] = {
   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_ClockFont, OPT_MessageFont, OPT_CoordFont, OPT_EditTagsFont, OPT_ChoosePieceFont, OPT_MessageFont8,\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
@@ -330,7 +336,7 @@ int dialogItems[][40] = {
 { 0 }\r
 };\r
 \r
-static char languageBuf[50000], *foreign[1000], *english[1000], *languageFile[MSG_SIZ];\r
+static char languageBuf[70000], *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
@@ -345,6 +351,7 @@ LoadLanguageFile(char *name)
 \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
@@ -383,11 +390,16 @@ T_(char *s)
 {   // return the translation of the given string\r
     // efficiency can be improved a lot...\r
     int i=0;\r
+    static char buf[MSG_SIZ];\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
+       if(english[i][0] == '%' && strstr(s, english[i]+1) == s) { // allow translation of strings with variable ending\r
+           snprintf(buf, MSG_SIZ, "%s%s", foreign[i], s + strlen(english[i]+1)); // keep unmatched portion\r
+           return buf;\r
+       }\r
         i++;\r
     }\r
     return s;\r
@@ -398,13 +410,11 @@ Translate(HWND hDlg, int dialogID)
 {   // translate all text items in the given dialog\r
     int i=0, j, k;\r
     char buf[MSG_SIZ], *s;\r
-//if(appData.debugMode) fprintf(debugFP, "Translate(%d)\n", dialogID);\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(appData.debugMode) fprintf(debugFP, "WindowText '%s' -> '%s'\n", buf, s);\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
@@ -414,33 +424,45 @@ Translate(HWND hDlg, int dialogID)
     }\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) {\r
+                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, j;\r
+    int i;\r
     WIN32_FIND_DATA fileData;\r
     HANDLE hFind;\r
-#define IDM_English 1895\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
-          for(j=GetMenuItemCount(subMenu)-1; j>=0; j--){\r
-            char buf[MSG_SIZ];\r
-            UINT k = GetMenuItemID(subMenu, j);\r
-             if(menuText[i][j])
-               safeStrCpy(buf, menuText[i][j], sizeof(buf)/sizeof(buf[0]) ); else {\r
-                GetMenuString(subMenu, j, buf, MSG_SIZ, MF_BYPOSITION);\r
-                menuText[i][j] = strdup(buf); // remember original on first change\r
-            }\r
-            if(buf[0] == NULLCHAR) continue;\r
-//fprintf(debugFP, "menu(%d,%d) = %s (%08x, %08x) %d\n", i, j, buf, mainMenu, subMenu, k);\r
-            ModifyMenu(subMenu, j, MF_STRING|MF_BYPOSITION\r
-                                   |CheckMenuItem(subMenu, j, MF_BYPOSITION)\r
-                                   |EnableMenuItem(subMenu, j, MF_BYPOSITION), k, T_(buf));\r
-          }\r
+          TranslateOneMenu(i, subMenu);\r
         }\r
         DrawMenuBar(hwndMain);\r
     }\r
@@ -472,6 +494,30 @@ TranslateMenus(int addLanguage)
 \r
 #endif\r
 \r
+#define IDM_RecentEngines 3000\r
+\r
+void\r
+RecentEngineMenu (char *s)\r
+{\r
+    if(appData.icsActive) return;\r
+    if(appData.recentEngines > 0 && *s) { // feature is on, and list non-empty\r
+       HMENU mainMenu = GetMenu(hwndMain);\r
+       HMENU subMenu = GetSubMenu(mainMenu, 5); // Engine menu\r
+       int i=IDM_RecentEngines;\r
+       recentEngines = strdup(appData.recentEngineList); // remember them as they are in menu\r
+       AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);\r
+       while(*s) {\r
+         char *p = strchr(s, '\n');\r
+         if(p == NULL) return; // malformed!\r
+         *p = NULLCHAR;\r
+         AppendMenu(subMenu, MF_ENABLED|MF_STRING|MF_UNCHECKED, (UINT_PTR) i++, (LPCTSTR) s);\r
+         *p = '\n';\r
+         s = p+1;\r
+       }\r
+    }\r
+}\r
+\r
+\r
 typedef struct {\r
   char *name;\r
   int squareSize;\r
@@ -507,24 +553,24 @@ SizeInfo sizeInfo[] =
 #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
@@ -641,7 +687,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
@@ -718,7 +763,8 @@ void ThawUI()
 #define JAWS_INIT\r
 #define JAWS_ARGS\r
 #define JAWS_ALT_INTERCEPT\r
-#define JAWS_KB_NAVIGATION\r
+#define JAWS_KBUP_NAVIGATION\r
+#define JAWS_KBDOWN_NAVIGATION\r
 #define JAWS_MENU_ITEMS\r
 #define JAWS_SILENCE\r
 #define JAWS_REPLAY\r
@@ -756,6 +802,7 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
   }\r
 \r
   JAWS_INIT\r
+  TranslateMenus(1);\r
 \r
 //  InitCommonControlsEx(&ex);\r
   InitCommonControls();\r
@@ -876,14 +923,19 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
 void\r
 SetUserLogo()\r
 {   // update user logo if necessary\r
-    static char oldUserName[MSG_SIZ], *curName;\r
+    static char oldUserName[MSG_SIZ], dir[MSG_SIZ], *curName;\r
 \r
     if(appData.autoLogo) {\r
          curName = UserName();\r
          if(strcmp(curName, oldUserName)) {\r
-           snprintf(oldUserName, MSG_SIZ, "logos\\%s.bmp", curName);\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
@@ -940,6 +992,64 @@ EnsureOnScreen(int *x, int *y, int minX, int minY)
   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
+       char *opponent = "";\r
+       if(gameMode == IcsPlayingWhite) opponent = gameInfo.black;\r
+       if(gameMode == IcsPlayingBlack) opponent = gameInfo.white;\r
+       sprintf(buf, "logos\\%s\\%s.bmp", appData.icsHost, opponent);\r
+       if(!*opponent || !(cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ))) {\r
+           sprintf(buf, "logos\\%s.bmp", appData.icsHost);\r
+           cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );\r
+       }\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
+VOID\r
+InitTextures()\r
+{\r
+  ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );\r
+  backTextureSquareSize = 0; // kludge to force recalculation of texturemode\r
+  \r
+  if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {\r
+      if(liteBackTexture) DeleteObject(liteBackTexture);\r
+      liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );\r
+      liteBackTextureMode = appData.liteBackTextureMode;\r
+\r
+      if (liteBackTexture == NULL && appData.debugMode) {\r
+          fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );\r
+      }\r
+  }\r
+  \r
+  if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {\r
+      if(darkBackTexture) DeleteObject(darkBackTexture);\r
+      darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );\r
+      darkBackTextureMode = appData.darkBackTextureMode;\r
+\r
+      if (darkBackTexture == NULL && appData.debugMode) {\r
+          fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );\r
+      }\r
+  }\r
+}\r
+\r
 BOOL\r
 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)\r
 {\r
@@ -995,37 +1105,8 @@ 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
-\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
-         snprintf(buf, MSG_SIZ, "%s/logo.bmp", appData.firstDirectory);\r
-       first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );   \r
-      }\r
-  }\r
-\r
-  if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {\r
-      second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );\r
-\r
-      if (second.programLogo == NULL && appData.debugMode) {\r
-          fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );\r
-      }\r
-  } else if(appData.autoLogo) {\r
-      char buf[MSG_SIZ];\r
-      if(appData.icsActive) { // [HGM] logo: in ICS mode second can be used for ICS\r
-       snprintf(buf, MSG_SIZ, "logos\\%s.bmp", appData.icsHost);\r
-       second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );\r
-      } else\r
-      if(appData.secondDirectory && appData.secondDirectory[0]) {\r
-       snprintf(buf, MSG_SIZ, "%s\\logo.bmp", appData.secondDirectory);\r
-       second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );  \r
-      }\r
-  }\r
+  LoadLogo(&first, 0, FALSE);\r
+  LoadLogo(&second, 1, appData.icsActive);\r
 \r
   SetUserLogo();\r
 \r
@@ -1048,30 +1129,12 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
   }\r
 \r
   InitDrawingSizes(boardSize, 0);\r
-  TranslateMenus(1);\r
+  RecentEngineMenu(appData.recentEngineList);\r
   InitMenuChecks();\r
   buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);\r
 \r
   /* [AS] Load textures if specified */\r
-  ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );\r
-  \r
-  if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {\r
-      liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );\r
-      liteBackTextureMode = appData.liteBackTextureMode;\r
-\r
-      if (liteBackTexture == NULL && appData.debugMode) {\r
-          fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );\r
-      }\r
-  }\r
-  \r
-  if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {\r
-      darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );\r
-      darkBackTextureMode = appData.darkBackTextureMode;\r
-\r
-      if (darkBackTexture == NULL && appData.debugMode) {\r
-          fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );\r
-      }\r
-  }\r
+  InitTextures();\r
 \r
   mysrandom( (unsigned) time(NULL) );\r
 \r
@@ -1111,15 +1174,6 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
                  0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);\r
 #endif\r
     ShowWindow(hwndConsole, nCmdShow);\r
-    if(appData.chatBoxes) { // [HGM] chat: open chat boxes\r
-      char buf[MSG_SIZ], *p = buf, *q;\r
-       safeStrCpy(buf, appData.chatBoxes, sizeof(buf)/sizeof(buf[0]) );\r
-      do {\r
-       q = strchr(p, ';');\r
-       if(q) *q++ = 0;\r
-       if(*p) ChatPopUp(p);\r
-      } while(p=q);\r
-    }\r
     SetActiveWindow(hwndConsole);\r
   }\r
   if(!appData.noGUI)   UpdateWindow(hwnd);  else ShowWindow(hwnd, SW_MINIMIZE);\r
@@ -1150,6 +1204,7 @@ InitMenuChecks()
 \r
 #define OPTCHAR "/"\r
 #define SEPCHAR "="\r
+#define TOPLEVEL 0\r
 \r
 #include "args.h"\r
 \r
@@ -1218,21 +1273,22 @@ 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
   } else {\r
     q = mfp->faceName;\r
+\r
     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
@@ -1338,7 +1394,7 @@ ParseBoardSize(void *addr, char *name)
     }\r
     bs++;\r
   }\r
-  ExitArgError(_("Unrecognized board size value"), name);\r
+  ExitArgError(_("Unrecognized board size value"), name, TRUE);\r
 }\r
 \r
 void\r
@@ -1959,7 +2015,8 @@ void CreatePiecesFromFont()
         return;\r
     }\r
 \r
-    if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {\r
+    if( !appData.useFont || appData.renderPiecesWithFont == NULL ||\r
+            appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {\r
         fontBitmapSquareSize = -1;\r
         return;\r
     }\r
@@ -2059,9 +2116,15 @@ void CreatePiecesFromFont()
 HBITMAP\r
 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)\r
 {\r
-  char name[128];\r
+  char name[128], buf[MSG_SIZ];\r
 \r
     snprintf(name, sizeof(name)/sizeof(name[0]), "%s%d%s", piece, squareSize, suffix);\r
+  if(appData.pieceDirectory[0]) {\r
+    HBITMAP res;\r
+    snprintf(buf, MSG_SIZ, "%s\\%s.bmp", appData.pieceDirectory, name);\r
+    res = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );\r
+    if(res) return res;\r
+  }\r
   if (gameInfo.event &&\r
       strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&\r
       strcmp(name, "k80s") == 0) {\r
@@ -2188,12 +2251,28 @@ InitDrawingSizes(BoardSize boardSize, int flags)
   RECT crect, wrect, oldRect;\r
   int offby;\r
   LOGBRUSH logbrush;\r
+  VariantClass v = gameInfo.variant;\r
 \r
   int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only\r
   if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }\r
 \r
   /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */\r
   if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;\r
+  oldBoardSize = boardSize;\r
+\r
+  if(boardSize != SizeMiddling && boardSize != SizePetite && boardSize != SizeBulky && !appData.useFont)\r
+  { // correct board size to one where built-in pieces exist\r
+    if((v == VariantCapablanca || v == VariantGothic || v == VariantGrand || v == VariantCapaRandom || v == VariantJanus || v == VariantSuper)\r
+       && (boardSize < SizePetite || boardSize > SizeBulky) // Archbishop and Chancellor available in entire middle range\r
+      || (v == VariantShogi && boardSize != SizeModerate)   // Japanese-style Shogi\r
+      ||  v == VariantKnightmate || v == VariantSChess || v == VariantXiangqi || v == VariantSpartan\r
+      ||  v == VariantShatranj || v == VariantMakruk || v == VariantGreat || v == VariantFairy ) {\r
+      if(boardSize < SizeMediocre) boardSize = SizePetite; else\r
+      if(boardSize > SizeModerate) boardSize = SizeBulky;  else\r
+                                   boardSize = SizeMiddling;\r
+    }\r
+  }\r
+  if(!appData.useFont && boardSize == SizePetite && (v == VariantShogi || v == VariantKnightmate)) boardSize = SizeMiddling; // no Unicorn in Petite\r
 \r
   oldRect.left = wpMain.x; //[HGM] placement: remember previous window params\r
   oldRect.top = wpMain.y;\r
@@ -2205,13 +2284,14 @@ InitDrawingSizes(BoardSize boardSize, int flags)
   squareSize = sizeInfo[boardSize].squareSize;\r
   lineGap = sizeInfo[boardSize].lineGap;\r
   minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted  */\r
+  border = appData.useBorder && appData.border[0] ? squareSize/2 : 0;\r
 \r
   if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {\r
       lineGap = appData.overrideLineGap;\r
   }\r
 \r
   if (tinyLayout != oldTinyLayout) {\r
-    long style = GetWindowLong(hwndMain, GWL_STYLE);\r
+    long style = GetWindowLongPtr(hwndMain, GWL_STYLE);\r
     if (tinyLayout) {\r
       style &= ~WS_SYSMENU;\r
       InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,\r
@@ -2220,7 +2300,7 @@ 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
@@ -2229,8 +2309,8 @@ InitDrawingSizes(BoardSize boardSize, int flags)
     DrawMenuBar(hwndMain);\r
   }\r
 \r
-  boardWidth  = BoardWidth(boardSize, BOARD_WIDTH);\r
-  boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);\r
+  boardWidth  = BoardWidth(boardSize, BOARD_WIDTH) + 2*border;\r
+  boardHeight = BoardWidth(boardSize, BOARD_HEIGHT) + 2*border;\r
 \r
   /* Get text area sizes */\r
   hdc = GetDC(hwndMain);\r
@@ -2302,7 +2382,6 @@ InitDrawingSizes(BoardSize boardSize, int flags)
 \r
   sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;\r
   sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;\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
@@ -2369,7 +2448,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
@@ -2378,7 +2457,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
@@ -2402,20 +2481,20 @@ InitDrawingSizes(BoardSize boardSize, int flags)
 \r
     /* [HGM] Loop had to be split in part for vert. and hor. lines */\r
     for (i = 0; i < BOARD_HEIGHT + 1; i++) {\r
-      gridEndpoints[i*2].x = boardRect.left + lineGap / 2;\r
+      gridEndpoints[i*2].x = boardRect.left + lineGap / 2 + border;\r
       gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =\r
-       boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));\r
+       boardRect.top + lineGap / 2 + (i * (squareSize + lineGap)) + border;\r
       gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +\r
-        BOARD_WIDTH * (squareSize + lineGap);\r
+        BOARD_WIDTH * (squareSize + lineGap) + border;\r
       gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;\r
     }\r
     for (i = 0; i < BOARD_WIDTH + 1; i++) {\r
-      gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;\r
+      gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2 + border;\r
       gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =\r
         gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +\r
-       lineGap / 2 + (i * (squareSize + lineGap));\r
+       lineGap / 2 + (i * (squareSize + lineGap)) + border;\r
       gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =\r
-        boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);\r
+        boardRect.top + BOARD_HEIGHT * (squareSize + lineGap) + border;\r
       gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;\r
     }\r
   }\r
@@ -2668,19 +2747,19 @@ VOID
 SquareToPos(int row, int column, int * x, int * y)\r
 {\r
   if (flipView) {\r
-    *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);\r
-    *y = boardRect.top + lineGap + row * (squareSize + lineGap);\r
+    *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap) + border;\r
+    *y = boardRect.top + lineGap + row * (squareSize + lineGap) + border;\r
   } else {\r
-    *x = boardRect.left + lineGap + column * (squareSize + lineGap);\r
-    *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);\r
+    *x = boardRect.left + lineGap + column * (squareSize + lineGap) + border;\r
+    *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap) + border;\r
   }\r
 }\r
 \r
 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
@@ -2689,7 +2768,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
@@ -2699,15 +2778,23 @@ DrawCoordsOnDC(HDC hdc)
   y = boardRect.top + lineGap;\r
   x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);\r
 \r
+  if(border) {\r
+    SetTextAlign(hdc, TA_RIGHT|TA_TOP);\r
+    x += border - lineGap - 4; y += squareSize - 6;\r
+  } else\r
   SetTextAlign(hdc, TA_LEFT|TA_TOP);\r
   for (i = 0; i < BOARD_HEIGHT; i++) {\r
     str[0] = files[start + i];\r
-    ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);\r
+    ExtTextOut(hdc, x + 2 - (border ? gameInfo.holdingsWidth * (squareSize + lineGap) : 0), y + 1, 0, NULL, str, 1, NULL);\r
     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
+  if(border) {\r
+    SetTextAlign(hdc, TA_LEFT|TA_TOP);\r
+    x += -border + 4; y += border - squareSize + 6;\r
+  } else\r
   SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);\r
   for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {\r
     str[0] = ranks[start + i];\r
@@ -2744,14 +2831,14 @@ DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
   if (lineGap == 0) return;\r
   if (flipView) {\r
     x1 = boardRect.left +\r
-      lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);\r
+      lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap) + border;\r
     y1 = boardRect.top +\r
-      lineGap/2 + y * (squareSize + lineGap);\r
+      lineGap/2 + y * (squareSize + lineGap) + border;\r
   } else {\r
     x1 = boardRect.left +\r
-      lineGap/2 + x * (squareSize + lineGap);\r
+      lineGap/2 + x * (squareSize + lineGap) + border;\r
     y1 = boardRect.top +\r
-      lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);\r
+      lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap) + border;\r
   }\r
   hPen = pen ? premovePen : highlightPen;\r
   oldPen = SelectObject(hdc, on ? hPen : gridPen);\r
@@ -2829,7 +2916,9 @@ DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y,
     BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,\r
           sqcolor ? SRCCOPY : NOTSRCCOPY);\r
   } else {\r
+    HBRUSH xBrush = whitePieceBrush;\r
     tmpSize = squareSize;\r
+    if(appData.pieceDirectory[0]) xBrush = GetStockObject(WHITE_BRUSH);\r
     if(minorSize &&\r
         ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||\r
          (piece >= (int)BlackNightrider && piece <= BlackGrasshopper))  ) {\r
@@ -2842,7 +2931,7 @@ DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y,
     if (color || appData.allWhite ) {\r
       oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));\r
       if( color )\r
-              oldBrush = SelectObject(hdc, whitePieceBrush);\r
+              oldBrush = SelectObject(hdc, xBrush);\r
       else    oldBrush = SelectObject(hdc, blackPieceBrush);\r
       if(appData.upsideDown && color==flipView)\r
         StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);\r
@@ -2854,6 +2943,18 @@ 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, SRCAND);\r
       else\r
         BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);\r
+    } else if(appData.pieceDirectory[0]) {\r
+      oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));\r
+      oldBrush = SelectObject(hdc, xBrush);\r
+      if(appData.upsideDown && color==flipView)\r
+        StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);\r
+      else\r
+        BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);\r
+      SelectObject(tmphdc, PieceBitmap(piece, SOLID_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
     } else {\r
       /* Use square color for details of black pieces */\r
       oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));\r
@@ -2952,7 +3053,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
@@ -2976,50 +3077,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
@@ -3036,8 +3137,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
@@ -3048,20 +3149,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[3].x = Round(x + j*A_WIDTH_FACTOR);\r
-        arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);\r
+        arrow[2].x = Round(arrow[6].x + 2*j);\r
+        arrow[2].y = Round(arrow[6].y - 2*j*dx);\r
+\r
+        arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));\r
+        arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);\r
 \r
         arrow[4].x = d_x;\r
         arrow[4].y = d_y;\r
 \r
-        arrow[5].x = Round(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
@@ -3086,20 +3189,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
@@ -3109,7 +3212,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
@@ -3239,6 +3342,40 @@ BOOL DrawPositionNeedsFullRepaint()
     return result;\r
 }\r
 \r
+static HBITMAP borderBitmap;\r
+\r
+VOID\r
+DrawBackgroundOnDC(HDC hdc)\r
+{\r
+  \r
+  BITMAP bi;\r
+  HDC tmphdc;\r
+  HBITMAP hbm;\r
+  static char oldBorder[MSG_SIZ];\r
+  int w = 600, h = 600, mode;\r
+\r
+  if(strcmp(appData.border, oldBorder)) { // load new one when old one no longer valid\r
+    strncpy(oldBorder, appData.border, MSG_SIZ-1);\r
+    borderBitmap = LoadImage( 0, appData.border, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );        \r
+  }\r
+  if(borderBitmap == NULL) { // loading failed, use white\r
+    FillRect( hdc, &boardRect, whitePieceBrush );\r
+    return;\r
+  }\r
+  tmphdc = CreateCompatibleDC(hdc);\r
+  hbm = SelectObject(tmphdc, borderBitmap);\r
+  if( GetObject( borderBitmap, sizeof(bi), &bi ) > 0 ) {\r
+            w = bi.bmWidth;\r
+            h = bi.bmHeight;\r
+  }\r
+  mode = SetStretchBltMode(hdc, COLORONCOLOR);\r
+  StretchBlt(hdc, boardRect.left, boardRect.top, boardRect.right - boardRect.left, \r
+                  boardRect.bottom - boardRect.top, tmphdc, 0, 0, w, h, SRCCOPY);\r
+  SetStretchBltMode(hdc, mode);\r
+  SelectObject(tmphdc, hbm);\r
+  DeleteDC(tmphdc);\r
+}\r
+\r
 VOID\r
 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)\r
 {\r
@@ -3306,7 +3443,7 @@ DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
           DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);\r
         }\r
       } \r
-      else if( backTextureSquareInfo[row][column].mode > 0 ) {\r
+      else if( appData.useBitmaps && backTextureSquareInfo[row][column].mode > 0 ) {\r
           /* [AS] Draw the square using a texture bitmap */\r
           HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );\r
          int r = row, c = column; // [HGM] do not flip board in flipView\r
@@ -3364,7 +3501,10 @@ DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
   HBITMAP hbm;\r
   int w = 100, h = 50;\r
 \r
-  if(logo == 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
@@ -3380,6 +3520,57 @@ DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
   DeleteDC(tmphdc);\r
 }\r
 \r
+VOID\r
+DisplayLogos()\r
+{\r
+  if(logoHeight) {\r
+       HDC hdc = GetDC(hwndMain);\r
+       HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;\r
+       if(appData.autoLogo) {\r
+         \r
+         switch(gameMode) { // pick logos based on game mode\r
+           case IcsObserving:\r
+               whiteLogo = second.programLogo; // ICS logo\r
+               blackLogo = second.programLogo;\r
+           default:\r
+               break;\r
+           case IcsPlayingWhite:\r
+               if(!appData.zippyPlay) whiteLogo = userLogo;\r
+               blackLogo = second.programLogo; // ICS logo\r
+               break;\r
+           case IcsPlayingBlack:\r
+               whiteLogo = second.programLogo; // ICS logo\r
+               blackLogo = appData.zippyPlay ? first.programLogo : userLogo;\r
+               break;\r
+           case TwoMachinesPlay:\r
+               if(first.twoMachinesColor[0] == 'b') {\r
+                   whiteLogo = second.programLogo;\r
+                   blackLogo = first.programLogo;\r
+               }\r
+               break;\r
+           case MachinePlaysWhite:\r
+               blackLogo = userLogo;\r
+               break;\r
+           case MachinePlaysBlack:\r
+               whiteLogo = userLogo;\r
+               blackLogo = first.programLogo;\r
+         }\r
+       }\r
+       DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);\r
+       DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);\r
+       ReleaseDC(hwndMain, hdc);\r
+  }\r
+}\r
+\r
+void\r
+UpdateLogos(int display)\r
+{ // called after loading new engine(s), in tourney or from menu\r
+  LoadLogo(&first, 0, FALSE);\r
+  LoadLogo(&second, 1, appData.icsActive);\r
+  InitDrawingSizes(-2, 0); // adapt layout of board window to presence/absence of logos\r
+  if(display) DisplayLogos();\r
+}\r
+\r
 static HDC hdcSeek;\r
 \r
 // [HGM] seekgraph\r
@@ -3436,6 +3627,14 @@ void DrawSeekDot(int x, int y, int color)
            SelectObject(hdcSeek, oldBrush);\r
 }\r
 \r
+void DrawSeekOpen()\r
+{\r
+}\r
+\r
+void DrawSeekClose()\r
+{\r
+}\r
+\r
 VOID\r
 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)\r
 {\r
@@ -3695,6 +3894,7 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
        Ellipse(hdcmem, x-r, y-r, x+r, y+r);\r
        SelectObject(hdcmem, oldBrush);\r
   } else {\r
+    if(border) DrawBackgroundOnDC(hdcmem);\r
     DrawGridOnDC(hdcmem);\r
     if(nr == 0) { // [HGM] dual: decide which highlights to draw\r
        DrawHighlightsOnDC(hdcmem, &highlightInfo, HIGHLIGHT_PEN);\r
@@ -3718,41 +3918,6 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
        }\r
     }\r
   }\r
-  if(logoHeight) {\r
-       HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;\r
-       if(appData.autoLogo) {\r
-         \r
-         switch(gameMode) { // pick logos based on game mode\r
-           case IcsObserving:\r
-               whiteLogo = second.programLogo; // ICS logo\r
-               blackLogo = second.programLogo;\r
-           default:\r
-               break;\r
-           case IcsPlayingWhite:\r
-               if(!appData.zippyPlay) whiteLogo = userLogo;\r
-               blackLogo = second.programLogo; // ICS logo\r
-               break;\r
-           case IcsPlayingBlack:\r
-               whiteLogo = second.programLogo; // ICS logo\r
-               blackLogo = appData.zippyPlay ? first.programLogo : userLogo;\r
-               break;\r
-           case TwoMachinesPlay:\r
-               if(first.twoMachinesColor[0] == 'b') {\r
-                   whiteLogo = second.programLogo;\r
-                   blackLogo = first.programLogo;\r
-               }\r
-               break;\r
-           case MachinePlaysWhite:\r
-               blackLogo = userLogo;\r
-               break;\r
-           case MachinePlaysBlack:\r
-               whiteLogo = userLogo;\r
-               blackLogo = first.programLogo;\r
-         }\r
-       }\r
-       DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);\r
-       DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);\r
-  }\r
 \r
   if( appData.highlightMoveWithArrow ) {\r
     DrawArrowHighlight(hdcmem);\r
@@ -3774,8 +3939,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
@@ -3820,11 +3985,11 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
         boardRect.bottom - boardRect.top,\r
         tmphdc, boardRect.left, boardRect.top, SRCCOPY);\r
   if(saveDiagFlag) { \r
-    BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000]\r
+    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
@@ -3888,6 +4053,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
+       free(pData);\r
      }\r
   }\r
 \r
@@ -3924,11 +4090,8 @@ SaveDiagram(f)
 {\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
@@ -3967,6 +4130,7 @@ PaintProc(HWND hwnd)
                 &messageRect, messageText, strlen(messageText), NULL);\r
       SelectObject(hdc, oldFont);\r
       DisplayBothClocks();\r
+      DisplayLogos();\r
     }\r
     EndPaint(hwnd,&ps);\r
   }\r
@@ -3984,11 +4148,11 @@ PaintProc(HWND hwnd)
 int EventToSquare(x, limit)\r
      int x, limit;\r
 {\r
-  if (x <= 0)\r
+  if (x <= border)\r
     return -2;\r
-  if (x < lineGap)\r
+  if (x < lineGap + border)\r
     return -1;\r
-  x -= lineGap;\r
+  x -= lineGap + border;\r
   if ((x % (squareSize + lineGap)) >= squareSize)\r
     return -1;\r
   x /= (squareSize + lineGap);\r
@@ -4034,12 +4198,14 @@ SetupDropMenu(HMENU hmenu)
   }\r
 }\r
 \r
-void DragPieceBegin(int x, int y)\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
@@ -4052,6 +4218,11 @@ void DragPieceEnd(int x, int y)
     dragInfo.pos = dragInfo.lastpos = dragInfo.start;\r
 }\r
 \r
+void ChangeDragPiece(ChessSquare piece)\r
+{\r
+    dragInfo.piece = piece;\r
+}\r
+\r
 /* Event handler for mouse messages */\r
 VOID\r
 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)\r
@@ -4090,23 +4261,9 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
   switch (message) {\r
   case WM_LBUTTONDOWN:\r
       if (PtInRect((LPRECT) &whiteRect, pt)) {\r
-        if (gameMode == EditPosition) {\r
-         SetWhiteToPlayEvent();\r
-        } else if (gameMode == EditGame || GetKeyState(VK_SHIFT) < 0) {\r
-          AdjustClock(flipClock, -1);\r
-       } else if (gameMode == IcsPlayingBlack ||\r
-                  gameMode == MachinePlaysWhite) {\r
-         CallFlagEvent();\r
-        }\r
+        ClockClick(flipClock); break;\r
       } else if (PtInRect((LPRECT) &blackRect, pt)) {\r
-       if (gameMode == EditPosition) {\r
-         SetBlackToPlayEvent();\r
-        } else if (gameMode == EditGame || GetKeyState(VK_SHIFT) < 0) {\r
-          AdjustClock(!flipClock, -1);\r
-       } else if (gameMode == IcsPlayingWhite ||\r
-                  gameMode == MachinePlaysBlack) {\r
-         CallFlagEvent();\r
-       }\r
+       ClockClick(!flipClock); break;\r
       }\r
       dragInfo.start.x = dragInfo.start.y = -1;\r
       dragInfo.from = dragInfo.start;\r
@@ -4126,6 +4283,7 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 \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
@@ -4185,9 +4343,9 @@ 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 || GetKeyState(VK_SHIFT) < 0) AdjustClock(flipClock, 1);\r
+          if (GetKeyState(VK_SHIFT) < 0) AdjustClock(flipClock, 1);\r
       } else if (PtInRect((LPRECT) &blackRect, pt)) {\r
-          if (gameMode == EditGame || GetKeyState(VK_SHIFT) < 0) AdjustClock(!flipClock, 1);\r
+          if (GetKeyState(VK_SHIFT) < 0) AdjustClock(!flipClock, 1);\r
       }\r
       break;\r
     }\r
@@ -4213,7 +4371,7 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       }\r
       break;\r
     case 2:\r
-      SetCapture(hwndMain);
+      SetCapture(hwndMain);\r
       break;\r
     case 1:\r
       hmenu = LoadMenu(hInst, "DropPieceMenu");\r
@@ -4232,7 +4390,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
@@ -4263,7 +4421,7 @@ ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
        SendMessage(h, WM_CHAR, wParam, lParam);\r
        return TRUE;\r
       } else if (isalpha((char)wParam) || isdigit((char)wParam)){\r
-       PopUpMoveDialog((char)wParam);\r
+       TypeInEvent((char)wParam);\r
       }\r
       break;\r
     }\r
@@ -4285,19 +4443,20 @@ Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
     Translate(hDlg, DLG_PromotionKing);\r
     ShowWindow(GetDlgItem(hDlg, PB_King), \r
       (!appData.testLegality || gameInfo.variant == VariantSuicide ||\r
+       gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||\r
        gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?\r
               SW_SHOW : SW_HIDE);\r
     /* [HGM] Only allow C & A promotions if these pieces are defined */\r
     ShowWindow(GetDlgItem(hDlg, PB_Archbishop),\r
-       ((PieceToChar(WhiteAngel) >= 'A' &&\r
+       ((PieceToChar(WhiteAngel) >= 'A' && WhiteOnMove(currentMove) &&\r
          PieceToChar(WhiteAngel) != '~') ||\r
-        (PieceToChar(BlackAngel) >= 'A' &&\r
+        (PieceToChar(BlackAngel) >= 'A' && !WhiteOnMove(currentMove) &&\r
          PieceToChar(BlackAngel) != '~')   ) ?\r
               SW_SHOW : SW_HIDE);\r
     ShowWindow(GetDlgItem(hDlg, PB_Chancellor), \r
-       ((PieceToChar(WhiteMarshall) >= 'A' &&\r
+       ((PieceToChar(WhiteMarshall) >= 'A' && WhiteOnMove(currentMove) &&\r
          PieceToChar(WhiteMarshall) != '~') ||\r
-        (PieceToChar(BlackMarshall) >= 'A' &&\r
+        (PieceToChar(BlackMarshall) >= 'A' && !WhiteOnMove(currentMove) &&\r
          PieceToChar(BlackMarshall) != '~')   ) ?\r
               SW_SHOW : SW_HIDE);\r
     /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */\r
@@ -4307,12 +4466,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
@@ -4329,31 +4487,30 @@ Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
       promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);\r
       break;\r
     case PB_Queen:\r
-      promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);\r
+      promoChar = gameInfo.variant == VariantShogi ? '+' : ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteQueen : BlackQueen));\r
       break;\r
     case PB_Rook:\r
-      promoChar = PieceToChar(BlackRook);\r
+      promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteRook : BlackRook));\r
+      if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) promoChar = PieceToChar(BlackDragon);\r
       break;\r
     case PB_Bishop:\r
-      promoChar = PieceToChar(BlackBishop);\r
+      promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteBishop : BlackBishop));\r
+      if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) promoChar = PieceToChar(BlackAlfil);\r
       break;\r
     case PB_Chancellor:\r
-      promoChar = PieceToChar(BlackMarshall);\r
+      promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteMarshall : BlackMarshall));\r
       break;\r
     case PB_Archbishop:\r
-      promoChar = PieceToChar(BlackAngel);\r
+      promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteAngel : BlackAngel));\r
       break;\r
     case PB_Knight:\r
-      promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);\r
+      promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(WhiteOnMove(currentMove) ? WhiteKnight : BlackKnight);\r
       break;\r
     default:\r
       return FALSE;\r
     }\r
+    if(promoChar == '.') return FALSE; // invalid piece chosen \r
     EndDialog(hDlg, TRUE); /* Exit the dialog */\r
-    /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we\r
-       only show the popup when we are already sure the move is valid or\r
-       legal. We pass a faulty move type, but the kludge is that FinishMove\r
-       will figure out it is a promotion from the promoChar. */\r
     UserMoveEvent(fromX, fromY, toX, toY, promoChar);\r
     fromX = fromY = -1;\r
     if (!appData.highlightLastMove) {\r
@@ -4384,14 +4541,6 @@ PromotionPopUp()
   PromotionPopup(hwndMain);\r
 }\r
 \r
-/* Toggle ShowThinking */\r
-VOID\r
-ToggleShowThinking()\r
-{\r
-  appData.showThinking = !appData.showThinking;\r
-  ShowThinkingEvent();\r
-}\r
-\r
 VOID\r
 LoadGameDialog(HWND hwnd, char* title)\r
 {\r
@@ -4463,11 +4612,11 @@ void UpdateICSWidth(HWND hText)
     LONG old_width, new_width;\r
 \r
     new_width = get_term_width(hText, FALSE);\r
-    old_width = GetWindowLong(hText, GWL_USERDATA);\r
+    old_width = GetWindowLongPtr(hText, GWLP_USERDATA);\r
     if (new_width != old_width)\r
     {\r
         ics_update_width(new_width);\r
-        SetWindowLong(hText, GWL_USERDATA, new_width);\r
+        SetWindowLongPtr(hText, GWLP_USERDATA, new_width);\r
     }\r
 }\r
 \r
@@ -4532,6 +4681,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
   char fileTitle[MSG_SIZ];\r
   char buf[MSG_SIZ];\r
   static SnapData sd;\r
+  static int peek=0;\r
 \r
   switch (message) {\r
 \r
@@ -4559,7 +4709,23 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     MouseEvent(hwnd, message, wParam, lParam);\r
     break;\r
 \r
-  JAWS_KB_NAVIGATION\r
+  case WM_KEYUP:\r
+    if((char)wParam == '\b') {\r
+      ForwardEvent(); peek = 0;\r
+    }\r
+\r
+    JAWS_KBUP_NAVIGATION\r
+\r
+    break;\r
+\r
+  case WM_KEYDOWN:\r
+    if((char)wParam == '\b') {\r
+      if(!peek) BackwardEvent(), peek = 1;\r
+    }\r
+\r
+    JAWS_KBDOWN_NAVIGATION\r
+\r
+    break;\r
 \r
   case WM_CHAR:\r
     \r
@@ -4573,7 +4739,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
        SendMessage(h, message, wParam, lParam);\r
     } else if(lParam != KF_REPEAT) {\r
        if (isalpha((char)wParam) || isdigit((char)wParam)) {\r
-               PopUpMoveDialog((char)wParam);\r
+               TypeInEvent((char)wParam);\r
        } else if((char)wParam == 003) CopyGameToClipboard();\r
         else if((char)wParam == 026) PasteGameOrFENFromClipboard();\r
     }\r
@@ -4698,12 +4864,16 @@ 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
       break;\r
 \r
+    case IDM_CreateBook:\r
+      CreateBookEvent();\r
+      break;\r
+\r
     case IDM_CopyGame:\r
       CopyGameToClipboard();\r
       break;\r
@@ -4828,10 +4998,8 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       break;\r
 \r
     case IDM_Match: // [HGM] match: flows into next case, after setting Match Mode and nr of Games\r
-      if(gameMode != BeginningOfGame) break; // allow menu item to remain enabled for better mode highligting\r
-      matchMode = 2;// distinguish from command-line-triggered case (matchMode=1)\r
-      appData.matchGames = appData.defaultMatchGames;\r
-      matchGame = 1;\r
+      MatchEvent(2); // distinguish from command-line-triggered case (matchMode=1)\r
+      break;\r
 \r
     case IDM_TwoMachines:\r
       TwoMachinesEvent();\r
@@ -4848,52 +5016,13 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       break;\r
 \r
     case IDM_AnalysisMode:\r
-      if (!first.analysisSupport) {\r
-        snprintf(buf, MSG_SIZ, _("%s does not support analysis"), first.tidy);\r
-        DisplayError(buf, 0);\r
-      } else {\r
+      if(AnalyzeModeEvent()) {\r
        SAY("analyzing current position");\r
-        /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */\r
-        if (appData.icsActive) {\r
-               if (gameMode != IcsObserving) {\r
-                snprintf(buf, MSG_SIZ, "You are not observing a game");\r
-                       DisplayError(buf, 0);\r
-                       /* secure check */\r
-                       if (appData.icsEngineAnalyze) {\r
-                               if (appData.debugMode) \r
-                                       fprintf(debugFP, "Found unexpected active ICS engine analyze \n");\r
-                               ExitAnalyzeMode();\r
-                               ModeHighlight();\r
-                               break;\r
-                       }\r
-                       break;\r
-               } else {\r
-                       /* if enable, user want disable icsEngineAnalyze */\r
-                       if (appData.icsEngineAnalyze) {\r
-                               ExitAnalyzeMode();\r
-                               ModeHighlight();\r
-                               break;\r
-                       }\r
-                       appData.icsEngineAnalyze = TRUE;\r
-                       if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");\r
-               }\r
-        } \r
-       if (!appData.showThinking) ToggleShowThinking();\r
-       AnalyzeModeEvent();\r
       }\r
       break;\r
 \r
     case IDM_AnalyzeFile:\r
-      if (!first.analysisSupport) {\r
-        char buf[MSG_SIZ];\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
-       AnalysisPeriodicEvent(1);\r
-      }\r
+      AnalyzeFileEvent();\r
       break;\r
 \r
     case IDM_IcsClient:\r
@@ -4901,11 +5030,13 @@ 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
@@ -4918,11 +5049,33 @@ 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_LoadProg1:\r
+     LoadEnginePopUp(hwndMain, 0);\r
+      break;\r
+\r
+    case IDM_LoadProg2:\r
+     LoadEnginePopUp(hwndMain, 1);\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
+    case IDM_Comment:\r
       if (commentUp && editComment) {\r
        CommentPopDown();\r
       } else {\r
@@ -4979,7 +5132,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       break;\r
 \r
     case IDM_TypeInMove:\r
-      PopUpMoveDialog('\000');\r
+      TypeInEvent('\000');\r
       break;\r
 \r
     case IDM_TypeInName:\r
@@ -5008,6 +5161,11 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       SetFocus(hwndMain);\r
       break;\r
 \r
+    case OPT_GameListNext: // [HGM] forward these two accelerators to Game List\r
+    case OPT_GameListPrev:\r
+      if(gameListDialog) SendMessage(gameListDialog, WM_COMMAND, wmId, 0);\r
+      break;\r
+\r
     case IDM_Revert:\r
       RevertEvent(FALSE);\r
       break;\r
@@ -5036,7 +5194,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     case IDM_FlipClock:\r
       flipClock = !flipClock;\r
       DisplayBothClocks();\r
-      DrawPosition(FALSE, NULL);\r
+      DisplayLogos();\r
       break;\r
 \r
     case IDM_MuteSounds:\r
@@ -5054,6 +5212,10 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       BoardOptionsPopup(hwnd);\r
       break;\r
 \r
+    case IDM_ThemeOptions:\r
+      ThemeOptionsPopup(hwnd);\r
+      break;\r
+\r
     case IDM_EnginePlayOptions:\r
       EnginePlayOptionsPopup(hwnd);\r
       break;\r
@@ -5064,7 +5226,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 \r
     case IDM_Engine2Options:\r
       savedHwnd = hwnd;\r
-      if(WaitForSecond(SettingsMenuIfReady)) break;\r
+      if(WaitForEngine(&second, SettingsMenuIfReady)) break;\r
       EngineOptionsPopup(hwnd, &second);\r
       break;\r
 \r
@@ -5072,6 +5234,10 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       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
@@ -5357,7 +5523,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       break;\r
 \r
     case IDM_English:\r
-      barbaric = 0;\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
@@ -5365,7 +5531,10 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       break;\r
 \r
     default:\r
-      if(wmId > IDM_English && wmId < IDM_English+5) {\r
+      if(wmId >= IDM_RecentEngines && wmId < IDM_RecentEngines + appData.recentEngines)\r
+          RecentEngineEvent(wmId - IDM_RecentEngines);\r
+      else\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
@@ -5573,7 +5742,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
@@ -5594,6 +5763,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
@@ -5604,6 +5774,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
@@ -5785,6 +5956,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
@@ -6036,8 +6208,8 @@ StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
                  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
       snprintf(buf, MSG_SIZ, "%s /icsport=%s", appData.icsHost, appData.icsPort);\r
@@ -6073,11 +6245,14 @@ StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
         safeStrCpy(buf, "/fcp=", sizeof(buf)/sizeof(buf[0]) );\r
        GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));\r
         p = buf;\r
+       comboLine = strdup(p+5); // [HGM] recent: remember complete line of first combobox\r
        ParseArgs(StringGet, &p);\r
-       safeStrCpy(buf, "/scp=", sizeof(buf)/sizeof(buf[0]) );\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
+       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
@@ -6223,7 +6398,7 @@ CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
        sizeY = newSizeY;\r
       }\r
     }\r
-    SendDlgItemMessage( hDlg, OPT_CommentText, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS );\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
@@ -6272,13 +6447,19 @@ CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
         if( wParam == OPT_CommentText ) {\r
             MSGFILTER * lpMF = (MSGFILTER *) lParam;\r
 \r
-            if( lpMF->msg == WM_RBUTTONDOWN && (lpMF->wParam & (MK_CONTROL | MK_SHIFT)) == 0 ) {\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
@@ -6322,7 +6503,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
@@ -6363,9 +6544,6 @@ 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
@@ -6381,40 +6559,11 @@ TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
 \r
   case WM_COMMAND:\r
     switch (LOWORD(wParam)) {\r
-    case IDOK:
+    case IDOK:\r
+\r
       shiftKey = GetKeyState(VK_SHIFT) < 0; // [HGM] remember last shift status\r
       GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));\r
-      { int n; Board board;\r
-       // [HGM] FENedit\r
-       if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {\r
-               EditPositionPasteFEN(move);\r
-               EndDialog(hDlg, TRUE);\r
-               return TRUE;\r
-       }\r
-       // [HGM] movenum: allow move number to be typed in any mode\r
-       if(sscanf(move, "%d", &n) == 1 && n != 0 ) {\r
-         ToNrEvent(2*n-1);\r
-         EndDialog(hDlg, TRUE);\r
-         return TRUE;\r
-       }\r
-      }\r
-      if (gameMode != EditGame && currentMove != forwardMostMove && \r
-       gameMode != Training) {\r
-       DisplayMoveError(_("Displayed move is not current"));\r
-      } else {\r
-//     GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream\r
-       int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove, \r
-         &moveType, &fromX, &fromY, &toX, &toY, &promoChar);\r
-       if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized\r
-       if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove, \r
-         &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {\r
-         if (gameMode != Training)\r
-             forwardMostMove = currentMove;\r
-         UserMoveEvent(fromX, fromY, toX, toY, promoChar);     \r
-       } else {\r
-         DisplayMoveError(_("Could not parse move"));\r
-       }\r
-      }\r
+      TypeInDoneEvent(move);\r
       EndDialog(hDlg, TRUE);\r
       return TRUE;\r
     case IDCANCEL:\r
@@ -6432,21 +6581,11 @@ VOID
 PopUpMoveDialog(char firstchar)\r
 {\r
     FARPROC lpProc;\r
-    \r
-    if ((gameMode == BeginningOfGame && !appData.icsActive) || \r
-        gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||\r
-       gameMode == AnalyzeMode || gameMode == EditGame || \r
-       gameMode == EditPosition || gameMode == IcsExamining ||\r
-       gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||\r
-       isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes\r
-               ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||\r
-                 gameMode == IcsObserving || gameMode == TwoMachinesPlay    ) ||\r
-       gameMode == Training) {\r
+\r
       lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);\r
       DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),\r
        hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);\r
       FreeProcInstance(lpProc);\r
-    }\r
 }\r
 \r
 /*---------------------------------------------------------------------------*\\r
@@ -6836,6 +6975,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
@@ -6869,7 +7009,8 @@ ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       SendMessage(hInput, message, wParam, lParam);\r
     }\r
     return 0;\r
-   } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu\r
+   } // [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
@@ -6878,7 +7019,7 @@ 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
@@ -7155,10 +7296,10 @@ ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
     hwndConsole = hDlg;\r
     SetFocus(hInput);\r
     consoleTextWindowProc = (WNDPROC)\r
-      SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);\r
+      SetWindowLongPtr(hText, GWLP_WNDPROC, (LONG_PTR) ConsoleTextSubclass);\r
     SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);\r
     consoleInputWindowProc = (WNDPROC)\r
-      SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);\r
+      SetWindowLongPtr(hInput, GWLP_WNDPROC, (LONG_PTR) ConsoleInputSubclass);\r
     SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);\r
     Colorize(ColorNormal, TRUE);\r
     SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);\r
@@ -7204,7 +7345,7 @@ ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
    wMask = (WORD) SendMessage(hText, EM_GETEVENTMASK, 0, 0L);\r
    SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);\r
    SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);\r
-   SetWindowLong(hText, GWL_USERDATA, 79); // initialize the text window's width\r
+   SetWindowLongPtr(hText, GWLP_USERDATA, 79); // initialize the text window's width\r
 \r
     return FALSE;\r
 \r
@@ -7384,7 +7525,7 @@ DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
   HFONT oldFont;\r
   RECT rect;\r
 \r
-  if(copyNumber > 1)
+  if(copyNumber > 1)\r
     snprintf(buf, sizeof(buf)/sizeof(buf[0]),"%d", copyNumber); else buf[0] = 0;\r
 \r
   oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */\r
@@ -7416,6 +7557,7 @@ DisplayAClock(HDC hdc, int timeRemaining, int highlight,
   COLORREF oldFg, oldBg;\r
   HFONT oldFont;\r
 \r
+  if (twoBoards && partnerUp) return;\r
   if (appData.clockMode) {\r
     if (tinyLayout)\r
       snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%c %s %s", color[0], TimeString(timeRemaining), flagFell);\r
@@ -7442,7 +7584,7 @@ DisplayAClock(HDC hdc, int timeRemaining, int highlight,
             rect, str, strlen(str), NULL);\r
   if(logoHeight > 0 && appData.clockMode) {\r
       RECT r;\r
-      snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s %s", buf+7, flagFell);\r
+      str += strlen(color)+2;\r
       r.top = rect->top + logoHeight/2;\r
       r.left = rect->left;\r
       r.right = rect->right;\r
@@ -7747,6 +7889,22 @@ Enables gnuEnables[] = {
   { 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
@@ -7764,10 +7922,13 @@ Enables icsEnables[] = {
   { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_Book, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_LoadProg1, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_LoadProg2, 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
@@ -7803,11 +7964,13 @@ Enables ncpEnables[] = {
   { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_Sounds, MF_BYCOMMAND|MF_GRAYED },\r
   { -1, -1 }\r
 };\r
 \r
 Enables trainingOnEnables[] = {\r
   { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_Comment, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },\r
@@ -7820,6 +7983,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
@@ -7856,7 +8020,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_Match, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },\r
   { -1, -1 }\r
@@ -7876,7 +8040,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_Match, MF_BYCOMMAND|MF_ENABLED },\r
   { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },\r
   { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },\r
   { -1, -1 }\r
@@ -7888,6 +8052,12 @@ Enables userThinkingEnables[] = {
  *  Functions appear in same order as prototypes in frontend.h.\r
  * \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
@@ -7918,7 +8088,7 @@ ModeHighlight()
     nowChecked = IDM_MachineWhite;\r
     break;\r
   case TwoMachinesPlay:\r
-    nowChecked = matchMode ? IDM_Match : IDM_TwoMachines; // [HGM] match\r
+    nowChecked = IDM_TwoMachines;\r
     break;\r
   case AnalyzeMode:\r
     nowChecked = IDM_AnalysisMode;\r
@@ -7949,12 +8119,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
@@ -7969,13 +8136,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
@@ -7983,8 +8149,8 @@ SetICSMode()
 {\r
   HMENU hmenu = GetMenu(hwndMain);\r
   SetMenuEnables(hmenu, icsEnables);\r
-  EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,\r
-    MF_BYPOSITION|MF_ENABLED);\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
@@ -8006,8 +8172,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
@@ -8114,6 +8278,7 @@ DisplayMessage(char *str1, char *str2)
     strncat(messageText, str2, len);\r
   }\r
   messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;\r
+  safeStrCpy(lastMsg, messageText, MSG_SIZ);\r
 \r
   if (hwndMain == NULL || IsIconic(hwndMain)) return;\r
 \r
@@ -8473,7 +8638,19 @@ DisplayIcsInteractionTitle(char *str)
   char consoleTitle[MSG_SIZ];\r
 \r
     snprintf(consoleTitle, MSG_SIZ, "%s: %s", szConsoleTitle, str);\r
-  SetWindowText(hwndConsole, consoleTitle);\r
+    SetWindowText(hwndConsole, consoleTitle);\r
+\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
+\r
+    SetActiveWindow(hwndMain);\r
 }\r
 \r
 void\r
@@ -8517,7 +8694,7 @@ CommentPopUp(char *title, char *str)
 VOID\r
 CommentPopDown(void)\r
 {\r
-  CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);\r
+  CheckMenuItem(GetMenu(hwndMain), IDM_Comment, MF_UNCHECKED);\r
   if (commentDialog) {\r
     ShowWindow(commentDialog, SW_HIDE);\r
   }\r
@@ -8563,6 +8740,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
@@ -8795,6 +8978,37 @@ IDLE_PRIORITY_CLASS         0x00000040
         return 0x00000040;\r
 }\r
 \r
+void RunCommand(char *cmdLine)\r
+{\r
+  /* Now create the child process. */\r
+  STARTUPINFO siStartInfo;\r
+  PROCESS_INFORMATION piProcInfo;\r
+\r
+  siStartInfo.cb = sizeof(STARTUPINFO);\r
+  siStartInfo.lpReserved = NULL;\r
+  siStartInfo.lpDesktop = NULL;\r
+  siStartInfo.lpTitle = NULL;\r
+  siStartInfo.dwFlags = STARTF_USESTDHANDLES;\r
+  siStartInfo.cbReserved2 = 0;\r
+  siStartInfo.lpReserved2 = NULL;\r
+  siStartInfo.hStdInput = NULL;\r
+  siStartInfo.hStdOutput = NULL;\r
+  siStartInfo.hStdError = NULL;\r
+\r
+  CreateProcess(NULL,\r
+               cmdLine,           /* command line */\r
+               NULL,      /* process security attributes */\r
+               NULL,      /* primary thread security attrs */\r
+               TRUE,      /* handles are inherited */\r
+               DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,\r
+               NULL,      /* use parent's environment */\r
+               NULL,\r
+               &siStartInfo, /* STARTUPINFO pointer */\r
+               &piProcInfo); /* receives PROCESS_INFORMATION */\r
+\r
+  CloseHandle(piProcInfo.hThread);\r
+}\r
+\r
 /* Start a child process running the given program.\r
    The process's standard output can be read from "from", and its\r
    standard input can be written to "to".\r
@@ -9054,6 +9268,7 @@ OpenTCP(char *host, char *port, ProcRef *pr)
   ChildProc *cp;\r
   int err;\r
   SOCKET s;\r
+\r
   struct sockaddr_in sa, mysa;\r
   struct hostent FAR *hp;\r
   unsigned short uport;\r
@@ -9530,6 +9745,12 @@ OutputToProcess(ProcRef pr, char *message, int count, int *outError)
   return outCount;\r
 }\r
 \r
+void\r
+DoSleep(int n)\r
+{\r
+    if(n != 0) Sleep(n);\r
+}\r
+\r
 int\r
 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,\r
                       long msdelay)\r
@@ -9550,7 +9771,7 @@ CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
 /* see wedittags.c for Edit Tags functions */\r
 \r
 \r
-VOID\r
+int\r
 ICSInitScript()\r
 {\r
   FILE *f;\r
@@ -9562,8 +9783,10 @@ ICSInitScript()
     if (f != NULL) {\r
       ProcessICSInitScript(f);\r
       fclose(f);\r
+      return TRUE;\r
     }\r
   }\r
+  return FALSE;\r
 }\r
 \r
 \r
@@ -9719,11 +9942,11 @@ ScreenSquare(column, row, pt)
      int column; int row; POINT * pt;\r
 {\r
   if (flipView) {\r
-    pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);\r
-    pt->y = lineGap + row * (squareSize + lineGap);\r
+    pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap) + border;\r
+    pt->y = lineGap + row * (squareSize + lineGap) + border;\r
   } else {\r
-    pt->x = lineGap + column * (squareSize + lineGap);\r
-    pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);\r
+    pt->x = lineGap + column * (squareSize + lineGap) + border;\r
+    pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap) + border;\r
   }\r
 }\r
 \r
@@ -9771,15 +9994,44 @@ Tween(start, mid, finish, factor, frames, nFrames)
 }\r
 \r
 void\r
-HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )\r
+SettingsPopUp(ChessProgramState *cps)\r
+{     // [HGM] wrapper needed because handles must not be passed through back-end\r
+      EngineOptionsPopup(savedHwnd, cps);\r
+}\r
+\r
+int flock(int fid, int code)\r
 {\r
-    MoveHistorySet( movelist, first, last, current, pvInfoList );\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
 \r
-    EvalGraphSet( first, last, current, pvInfoList );\r
+char *\r
+Col2Text (int n)\r
+{\r
+    static int i=0;\r
+    static char col[8][20];\r
+    COLORREF color = *(COLORREF *) colorVariable[n];\r
+    i = i+1 & 7;\r
+    snprintf(col[i], 20, "#%02lx%02lx%02lx", color&0xff, (color>>8)&0xff, (color>>16)&0xff);\r
+    return col[i];\r
 }\r
 \r
 void\r
-SettingsPopUp(ChessProgramState *cps)\r
-{     // [HGM] wrapper needed because handles must not be passed through back-end\r
-      EngineOptionsPopup(savedHwnd, cps);\r
+ActivateTheme (int new)\r
+{   // Redo initialization of features depending on options that can occur in themes\r
+   InitTextures();\r
+   if(new) InitDrawingColors();\r
+   fontBitmapSquareSize = 0; // request creation of new font pieces\r
+   InitDrawingSizes(-2, 0);\r
+   InvalidateRect(hwndMain, NULL, TRUE);\r
 }\r