Fix multi-leg promotions
[xboard.git] / winboard / winboard.c
index 1655d40..e4b8692 100644 (file)
@@ -2,10 +2,11 @@
  * WinBoard.c -- Windows NT front end to XBoard\r
  *\r
  * Copyright 1991 by Digital Equipment Corporation, Maynard,\r
- * Massachusetts. \r
+ * Massachusetts.\r
  *\r
  * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,\r
- * 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.\r
+ * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Free\r
+ * Software Foundation, Inc.\r
  *\r
  * Enhancements Copyright 2005 Alessandro Scotti\r
  *\r
@@ -92,6 +93,9 @@
 #include "help.h"\r
 #include "wsnap.h"\r
 \r
+#define SLASH '/'\r
+#define DATADIR "~~"\r
+\r
 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );\r
 \r
   int myrandom(void);\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
                   /*char*/int promoChar));\r
 void DisplayMove P((int moveNumber));\r
-Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen));\r
 void ChatPopUp P((char *s));\r
 typedef struct {\r
   ChessSquare piece;  \r
@@ -185,6 +190,7 @@ Boolean alwaysOnTop = FALSE;
 RECT boardRect;\r
 COLORREF lightSquareColor, darkSquareColor, whitePieceColor, \r
   blackPieceColor, highlightSquareColor, premoveHighlightColor;\r
+COLORREF markerColor[8] = { 0x00FFFF, 0x0000FF, 0x00FF00, 0xFF0000, 0xFFFF00, 0xFF00FF, 0xFFFFFF, 0x000000 };\r
 HPALETTE hPal;\r
 ColorClass currentColorClass;\r
 \r
@@ -195,7 +201,7 @@ static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred
 static HBRUSH lightSquareBrush, darkSquareBrush,\r
   blackSquareBrush, /* [HGM] for band between board and holdings */\r
   explodeBrush,     /* [HGM] atomic */\r
-  markerBrush,      /* [HGM] markers */\r
+  markerBrush[8],   /* [HGM] markers */\r
   whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;\r
 static POINT gridEndpoints[(BOARD_RANKS + BOARD_FILES + 2) * 2];\r
 static DWORD gridVertexCounts[BOARD_RANKS + BOARD_FILES + 2];\r
@@ -220,6 +226,7 @@ static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_RANKS][BOA
 #if __GNUC__ && !defined(_winmajor)\r
 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */\r
 #else\r
+\r
 #if defined(_winmajor)\r
 #define oldDialog (_winmajor < 4)\r
 #else\r
@@ -249,11 +256,13 @@ 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
+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,\r
+  OPT_Ranget, 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
@@ -293,7 +302,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
@@ -301,7 +310,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
@@ -313,7 +322,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
@@ -332,7 +342,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
@@ -386,11 +396,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
@@ -428,7 +443,7 @@ TranslateOneMenu(int i, HMENU subMenu)
             info.dwTypeData = buf;\r
             info.cch = sizeof(buf);\r
             GetMenuItemInfo(subMenu, j, TRUE, &info);\r
-            if(i < 10) {
+            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
@@ -485,6 +500,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
@@ -496,12 +535,12 @@ typedef struct {
 \r
 SizeInfo sizeInfo[] = \r
 {\r
-  { "tiny",     21, 0, 1, 1, 0, 0 },\r
-  { "teeny",    25, 1, 1, 1, 0, 0 },\r
-  { "dinky",    29, 1, 1, 1, 0, 0 },\r
-  { "petite",   33, 1, 1, 1, 0, 0 },\r
-  { "slim",     37, 2, 1, 0, 0, 0 },\r
-  { "small",    40, 2, 1, 0, 0, 0 },\r
+  { "tiny",     21, 0, 1, 2, 0, 0 },\r
+  { "teeny",    25, 1, 1, 2, 0, 0 },\r
+  { "dinky",    29, 1, 1, 2, 0, 0 },\r
+  { "petite",   33, 1, 1, 2, 0, 0 },\r
+  { "slim",     37, 2, 1, 1, 0, 0 },\r
+  { "small",    40, 2, 1, 1, 0, 0 },\r
   { "mediocre", 45, 2, 1, 0, 0, 0 },\r
   { "middling", 49, 2, 0, 0, 0, 0 },\r
   { "average",  54, 2, 0, 0, 0, 0 },\r
@@ -520,24 +559,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
@@ -549,7 +588,7 @@ typedef struct {
   WNDPROC wndproc;\r
 } MyButtonDesc;\r
 \r
-#define BUTTON_WIDTH (tinyLayout ? 16 : 32)\r
+#define BUTTON_WIDTH (tinyLayout == 2 ? 16 : 32)\r
 #define N_BUTTONS 5\r
 \r
 MyButtonDesc buttonDesc[N_BUTTONS] =\r
@@ -563,8 +602,9 @@ MyButtonDesc buttonDesc[N_BUTTONS] =
 \r
 int tinyLayout = 0, smallLayout = 0;\r
 #define MENU_BAR_ITEMS 9\r
-char *menuBarText[2][MENU_BAR_ITEMS+1] = {\r
+char *menuBarText[3][MENU_BAR_ITEMS+1] = {\r
   { N_("&File"), N_("&Edit"), N_("&View"), N_("&Mode"), N_("&Action"), N_("E&ngine"), N_("&Options"), N_("&Help"), NULL },\r
+  { N_("&Fil"), N_("&Ed"), N_("&Vw"), N_("&Mod"), N_("&Act"), N_("E&ng"), N_("&Opt"), N_("&Hlp"), NULL },\r
   { N_("&F"), N_("&E"), N_("&V"), N_("&M"), N_("&A"), N_("&N"), N_("&O"), N_("&H"), NULL },\r
 };\r
 \r
@@ -730,7 +770,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
@@ -747,12 +788,14 @@ void ThawUI()
  *\r
 \*---------------------------------------------------------------------------*/\r
 \r
+static void HandleMessage P((MSG *message));\r
+static HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;\r
+\r
 int APIENTRY\r
 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,\r
        LPSTR lpCmdLine, int nCmdShow)\r
 {\r
   MSG msg;\r
-  HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;\r
 //  INITCOMMONCONTROLSEX ex;\r
 \r
   debugFP = stderr;\r
@@ -784,6 +827,17 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    0,    /* lowest message to examine */\r
                    0))   /* highest message to examine */\r
     {\r
+       HandleMessage(&msg);\r
+    }\r
+\r
+\r
+  return (msg.wParam); /* Returns the value from PostQuitMessage */\r
+}\r
+\r
+static void\r
+HandleMessage (MSG *message)\r
+{\r
+    MSG msg = *message;\r
 \r
       if(msg.message == WM_CHAR && msg.wParam == '\t') {\r
        // [HGM] navigate: switch between all windows with tab\r
@@ -851,7 +905,7 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
          if(currentElement < 5 && IsIconic(hwndMain))    ShowWindow(hwndMain, SW_RESTORE); // all open together\r
          SetFocus(h);\r
 \r
-         continue; // this message now has been processed\r
+         return; // this message now has been processed\r
        }\r
       }\r
 \r
@@ -870,14 +924,24 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
            if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {\r
                done = 1; break;\r
        }\r
-       if(done) continue; // [HGM] chat: end patch\r
+       if(done) return; // [HGM] chat: end patch\r
        TranslateMessage(&msg); /* Translates virtual key codes */\r
        DispatchMessage(&msg);  /* Dispatches message to window */\r
       }\r
-    }\r
-\r
+}\r
 \r
-  return (msg.wParam); /* Returns the value from PostQuitMessage */\r
+void\r
+DoEvents ()\r
+{ /* Dispatch pending messages */\r
+  MSG msg;\r
+  while (PeekMessage(&msg, /* message structure */\r
+                    NULL, /* handle of window receiving the message */\r
+                    0,    /* lowest message to examine */\r
+                    0,    /* highest message to examine */\r
+                    PM_REMOVE))\r
+    {\r
+       HandleMessage(&msg);\r
+    }\r
 }\r
 \r
 /*---------------------------------------------------------------------------*\\r
@@ -889,16 +953,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
@@ -943,21 +1010,25 @@ InitApplication(HINSTANCE hInstance)
 \r
 /* Set by InitInstance, used by EnsureOnScreen */\r
 int screenHeight, screenWidth;\r
+RECT screenGeometry;\r
 \r
 void\r
 EnsureOnScreen(int *x, int *y, int minX, int minY)\r
 {\r
 //  int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);\r
   /* Be sure window at (x,y) is not off screen (or even mostly off screen) */\r
-  if (*x > screenWidth - 32) *x = 0;\r
-  if (*y > screenHeight - 32) *y = 0;\r
-  if (*x < minX) *x = minX;\r
-  if (*y < minY) *y = minY;\r
+  if (*x > screenGeometry.right - 32) *x = screenGeometry.left;\r
+  if (*y > screenGeometry.bottom - 32) *y = screenGeometry.top;\r
+  if (*x < screenGeometry.left + minX) *x = screenGeometry.left + minX;\r
+  if (*y < screenGeometry.top + minY) *y = screenGeometry.top + minY;\r
 }\r
 \r
 VOID\r
-LoadLogo(ChessProgramState *cps, int n)\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
@@ -965,14 +1036,79 @@ LoadLogo(ChessProgramState *cps, int n)
           fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.logo[n] );\r
       }\r
   } else if(appData.autoLogo) {\r
-      if(appData.firstDirectory && appData.directory[n][0]) {\r
-       char buf[MSG_SIZ];\r
-         snprintf(buf, MSG_SIZ, "%s/logo.bmp", appData.directory[n]);\r
-       cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );    \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
+#ifndef SM_CXVIRTUALSCREEN\r
+#define SM_CXVIRTUALSCREEN 78\r
+#endif\r
+#ifndef SM_CYVIRTUALSCREEN\r
+#define SM_CYVIRTUALSCREEN 79\r
+#endif\r
+#ifndef SM_XVIRTUALSCREEN \r
+#define SM_XVIRTUALSCREEN 76\r
+#endif\r
+#ifndef SM_YVIRTUALSCREEN \r
+#define SM_YVIRTUALSCREEN 77\r
+#endif\r
+\r
+VOID\r
+InitGeometry()\r
+{\r
+  screenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);\r
+  if( !screenHeight ) screenHeight = GetSystemMetrics(SM_CYSCREEN);\r
+  screenWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);\r
+  if( !screenWidth ) screenWidth = GetSystemMetrics(SM_CXSCREEN);\r
+  screenGeometry.left = GetSystemMetrics(SM_XVIRTUALSCREEN);\r
+  screenGeometry.top = GetSystemMetrics(SM_YVIRTUALSCREEN);\r
+  screenGeometry.right = screenGeometry.left + screenWidth;\r
+  screenGeometry.bottom = screenGeometry.top + screenHeight;\r
+}\r
+\r
+ChessProgramState broadcast;\r
+\r
 BOOL\r
 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)\r
 {\r
@@ -986,11 +1122,12 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
 \r
   if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {\r
     *filepart = NULLCHAR;\r
+    SetCurrentDirectory(installDir);\r
   } else {\r
     GetCurrentDirectory(MSG_SIZ, installDir);\r
   }\r
   gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise\r
-  screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData\r
+  InitGeometry();\r
   InitAppData(lpCmdLine);      /* Get run-time parameters */\r
   /* xboard, and older WinBoards, controlled the move sound with the\r
      appData.ringBellAfterMoves option.  In the current WinBoard, we\r
@@ -1004,7 +1141,18 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
     appData.ringBellAfterMoves = TRUE;\r
   }\r
   if (appData.debugMode) {\r
-    debugFP = fopen(appData.nameOfDebugFile, "w");\r
+    char *c = appData.nameOfDebugFile;\r
+    if(strstr(c, "///") == c) {\r
+      broadcast.which = "broadcaster";\r
+      broadcast.pr   = NoProc;\r
+      broadcast.isr  = NULL;\r
+      broadcast.program = c + 3;\r
+      broadcast.dir  = ".";\r
+      broadcast.host = "localhost";\r
+      StartChessProgram(&broadcast);\r
+      debugFP = (FILE*) _fdopen(_open_osfhandle((long)(((ChildProc*)(broadcast.pr))->hTo), _O_WRONLY), "w");\r
+    } else\r
+    debugFP = fopen(c, "w");\r
     setbuf(debugFP, NULL);\r
   }\r
 \r
@@ -1028,25 +1176,8 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
   }\r
 \r
   /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */\r
-  LoadLogo(&first, 0);\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
@@ -1054,8 +1185,8 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
   iconBlack = LoadIcon(hInstance, "icon_black");\r
   iconCurrent = iconWhite;\r
   InitDrawingColors();\r
-  screenHeight = GetSystemMetrics(SM_CYSCREEN);\r
-  screenWidth = GetSystemMetrics(SM_CXSCREEN);\r
+\r
+  InitPosition(0); // to set nr of ranks and files, which might be non-default through command-line args\r
   for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {\r
     /* Compute window size for each board size, and use the largest\r
        size that fits on this screen as the default. */\r
@@ -1069,29 +1200,12 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
   }\r
 \r
   InitDrawingSizes(boardSize, 0);\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
@@ -1131,15 +1245,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
@@ -1161,6 +1266,7 @@ InitMenuChecks()
   (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,\r
                       MF_BYCOMMAND|(saveSettingsOnExit ?\r
                                     MF_CHECKED : MF_UNCHECKED));\r
+  EnableMenuItem(hmenu, IDM_SaveSelected, MF_GRAYED);\r
 }\r
 \r
 //---------------------------------------------------------------------------------------------------------\r
@@ -1170,6 +1276,7 @@ InitMenuChecks()
 \r
 #define OPTCHAR "/"\r
 #define SEPCHAR "="\r
+#define TOPLEVEL 0\r
 \r
 #include "args.h"\r
 \r
@@ -1190,6 +1297,9 @@ LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
   lf->lfStrikeOut = mfp->strikeout;\r
   lf->lfCharSet = mfp->charset;\r
   lf->lfOutPrecision = OUT_DEFAULT_PRECIS;\r
+\r
+\r
+\r
   lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;\r
   lf->lfQuality = DEFAULT_QUALITY;\r
   lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;\r
@@ -1238,21 +1348,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
@@ -1358,7 +1469,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
@@ -1742,6 +1853,8 @@ static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
     COLORREF chroma = RGB(0xFF,0x00,0xFF);\r
     RECT rc;\r
     SIZE sz;\r
+\r
+\r
     POINT pt;\r
     int backColor = whitePieceColor; \r
     int foreColor = blackPieceColor;\r
@@ -1979,7 +2092,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
@@ -2079,9 +2193,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
@@ -2118,6 +2238,7 @@ InsertInPalette(COLORREF color)
 VOID\r
 InitDrawingColors()\r
 {\r
+  int i;\r
   if (pLogPal == NULL) {\r
     /* Allocate enough memory for a logical palette with\r
      * PALETTESIZE entries and set the size and version fields\r
@@ -2149,8 +2270,9 @@ InitDrawingColors()
   blackPieceBrush = CreateSolidBrush(blackPieceColor);\r
   iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));\r
   explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic\r
-  markerBrush = CreateSolidBrush(premoveHighlightColor); // [HGM] markers\r
-  /* [AS] Force rendering of the font-based pieces */\r
+    for(i=0; i<8;i++) markerBrush[i] = CreateSolidBrush(markerColor[i]); // [HGM] markers\r
+\r
+   /* [AS] Force rendering of the font-based pieces */\r
   if( fontBitmapSquareSize > 0 ) {\r
     fontBitmapSquareSize = 0;\r
   }\r
@@ -2208,12 +2330,30 @@ 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
+  if(boardSize == -1) return;     // no size defined yet; abort (to allow early call of InitPosition)\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
+\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 || v == VariantLion ) {\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 == 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
@@ -2225,6 +2365,11 @@ 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
+  // [HGM] decide on tininess based on total board width rather than square size\r
+  tinyLayout = squareSize * (BOARD_WIDTH);\r
+  tinyLayout = tinyLayout < 35*8 ? 2 : tinyLayout < 43*8 ? 1 : 0;\r
 \r
   if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {\r
       lineGap = appData.overrideLineGap;\r
@@ -2232,7 +2377,7 @@ InitDrawingSizes(BoardSize boardSize, int flags)
 \r
   if (tinyLayout != oldTinyLayout) {\r
     long style = GetWindowLongPtr(hwndMain, GWL_STYLE);\r
-    if (tinyLayout) {\r
+    if (tinyLayout == 2) {\r
       style &= ~WS_SYSMENU;\r
       InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,\r
                 "&Minimize\tCtrl+F4");\r
@@ -2249,8 +2394,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
@@ -2268,7 +2413,7 @@ InitDrawingSizes(BoardSize boardSize, int flags)
   ReleaseDC(hwndMain, hdc);\r
 \r
   /* Compute where everything goes */\r
-  if((first.programLogo || second.programLogo) && !tinyLayout) {\r
+  if((first.programLogo || second.programLogo) && tinyLayout != 2) {\r
         /* [HGM] logo: if either logo is on, reserve space for it */\r
        logoHeight =  2*clockSize.cy;\r
        leftLogoRect.left   = OUTER_MARGIN;\r
@@ -2322,7 +2467,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
@@ -2390,7 +2534,7 @@ InitDrawingSizes(BoardSize boardSize, int flags)
                     messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,\r
                     (HMENU) buttonDesc[i].id,\r
                     (HINSTANCE) GetWindowLongPtr(hwndMain, GWLP_HINSTANCE), NULL);\r
-      if (tinyLayout) {\r
+      if (tinyLayout == 2) {\r
        SendMessage(buttonDesc[i].hwnd, WM_SETFONT, \r
                    (WPARAM)font[boardSize][MESSAGE_FONT]->hf,\r
                    MAKELPARAM(FALSE, 0));\r
@@ -2422,20 +2566,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
@@ -2459,10 +2603,12 @@ InitDrawingSizes(BoardSize boardSize, int flags)
         piece = (ChessSquare) ((int) piece + 1)) {\r
       if (pieceBitmap[i][piece] != NULL)\r
        DeleteObject(pieceBitmap[i][piece]);\r
+      pieceBitmap[i][piece] = NULL;\r
     }\r
   }\r
 \r
   fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */\r
+\r
   // Orthodox Chess pieces\r
   pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");\r
   pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");\r
@@ -2560,11 +2706,29 @@ InitDrawingSizes(BoardSize boardSize, int flags)
     pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");\r
     pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");\r
     pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");\r
+    pieceBitmap[0][WhiteAmazon] = DoLoadBitmap(hInst, "l", squareSize, "s");\r
+    pieceBitmap[1][WhiteAmazon] = DoLoadBitmap(hInst, "l", squareSize, "o");\r
+    pieceBitmap[2][WhiteAmazon] = DoLoadBitmap(hInst, "l", squareSize, "w");\r
     pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");\r
     pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");\r
     pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");\r
-\r
-    if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */\r
+    pieceBitmap[0][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "s");\r
+    pieceBitmap[1][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "o");\r
+    pieceBitmap[2][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "w");\r
+    pieceBitmap[0][WhiteCub] = DoLoadBitmap(hInst, "ln", squareSize, "s");\r
+    pieceBitmap[1][WhiteCub] = DoLoadBitmap(hInst, "ln", squareSize, "o");\r
+    pieceBitmap[2][WhiteCub] = DoLoadBitmap(hInst, "ln", squareSize, "w");\r
+    pieceBitmap[0][WhiteWolf] = DoLoadBitmap(hInst, "wolf", squareSize, "s");\r
+    pieceBitmap[1][WhiteWolf] = DoLoadBitmap(hInst, "wolf", squareSize, "o");\r
+    pieceBitmap[2][WhiteWolf] = DoLoadBitmap(hInst, "wolf", squareSize, "w");\r
+    pieceBitmap[0][WhiteCamel] = DoLoadBitmap(hInst, "camel", squareSize, "s");\r
+    pieceBitmap[1][WhiteCamel] = DoLoadBitmap(hInst, "camel", squareSize, "o");\r
+    pieceBitmap[2][WhiteCamel] = DoLoadBitmap(hInst, "camel", squareSize, "w");\r
+    pieceBitmap[0][WhiteZebra] = DoLoadBitmap(hInst, "zebra", squareSize, "s");\r
+    pieceBitmap[1][WhiteZebra] = DoLoadBitmap(hInst, "zebra", squareSize, "o");\r
+    pieceBitmap[2][WhiteZebra] = DoLoadBitmap(hInst, "n", squareSize, "w");\r
+\r
+    if(gameInfo.variant == VariantShogi && BOARD_HEIGHT != 7) { /* promoted Gold representations (but not in Tori!)*/\r
       pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");\r
       pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");\r
       pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");\r
@@ -2664,6 +2828,15 @@ InitDrawingSizes(BoardSize boardSize, int flags)
   pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");\r
   minorSize = 0;\r
   }\r
+\r
+  if(appData.pieceDirectory[0]) for(i=WhitePawn; i<BlackPawn; i++) { // try for all missing pieces with new naming convention\r
+    char buf[MSG_SIZ];\r
+    if(pieceBitmap[0][i]) continue;\r
+    snprintf(buf, MSG_SIZ, "piece%d_", i);\r
+    pieceBitmap[0][i] = DoLoadBitmap(hInst, buf, squareSize, "s");\r
+    pieceBitmap[1][i] = DoLoadBitmap(hInst, buf, squareSize, "o");\r
+    pieceBitmap[2][i] = DoLoadBitmap(hInst, buf, squareSize, "w");\r
+  }\r
 }\r
 \r
 HBITMAP\r
@@ -2688,19 +2861,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
@@ -2709,7 +2882,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
@@ -2719,15 +2892,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
@@ -2764,14 +2945,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
@@ -2849,7 +3030,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
@@ -2862,7 +3045,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
@@ -2874,6 +3057,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
@@ -3162,6 +3357,9 @@ BOOL HasHighlightInfo()
     }\r
 \r
     return result;\r
+\r
+\r
+\r
 }\r
 \r
 BOOL IsDrawArrowEnabled()\r
@@ -3261,6 +3459,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
@@ -3319,6 +3551,7 @@ DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
             DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);\r
       else if( column == BOARD_RGHT) /* right align */\r
             DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);\r
+      else if( piece == DarkSquare) DisplayHoldingsCount(hdc, x, y, 0, 0);\r
       else\r
       if (appData.monoMode) {\r
         if (piece == EmptySquare) {\r
@@ -3328,7 +3561,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
@@ -3386,7 +3619,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
@@ -3444,6 +3680,15 @@ DisplayLogos()
   }\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
@@ -3489,7 +3734,7 @@ void DrawSeekDot(int x, int y, int color)
 {\r
        int square = color & 0x80;\r
        HBRUSH oldBrush = SelectObject(hdcSeek, \r
-                       color == 0 ? markerBrush : color == 1 ? darkSquareBrush : explodeBrush);\r
+                       color == 0 ? markerBrush[1] : color == 1 ? darkSquareBrush : explodeBrush);\r
        color &= 0x7F;\r
        if(square)\r
            Rectangle(hdcSeek, boardRect.left+x - squareSize/9, boardRect.top+y - squareSize/9,\r
@@ -3500,6 +3745,16 @@ 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
+\r
+\r
 VOID\r
 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)\r
 {\r
@@ -3720,6 +3975,7 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
         explodes.  The old and new positions both had an empty square\r
         at the destination, but animation has drawn a piece there and\r
         we have to remember to erase it. [HGM] moved until after setting lastDrawn */\r
+\r
       lastDrawn[0][animInfo.to.y][animInfo.to.x] = animInfo.piece;\r
     }\r
   }\r
@@ -3759,6 +4015,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
@@ -3773,8 +4030,7 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
   for (row = 0; row < BOARD_HEIGHT; row++) {\r
     for (column = 0; column < BOARD_WIDTH; column++) {\r
        if (marker[row][column]) { // marker changes only occur with full repaint!\r
-           HBRUSH oldBrush = SelectObject(hdcmem, \r
-                       marker[row][column] == 2 ? markerBrush : explodeBrush);\r
+           HBRUSH oldBrush = SelectObject(hdcmem, markerBrush[marker[row][column]-1]);\r
            SquareToPos(row, column, &x, &y);\r
            Ellipse(hdcmem, x + squareSize/4, y + squareSize/4,\r
                          x + 3*squareSize/4, y + 3*squareSize/4);\r
@@ -3784,6 +4040,7 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
   }\r
 \r
   if( appData.highlightMoveWithArrow ) {\r
+\r
     DrawArrowHighlight(hdcmem);\r
   }\r
 \r
@@ -3800,6 +4057,7 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
     else\r
     if(dragInfo.from.x == BOARD_RGHT+1 )\r
                  board[dragInfo.from.y][dragInfo.from.x-1]++;\r
+\r
     board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;\r
     x = dragInfo.pos.x - squareSize / 2;\r
     y = dragInfo.pos.y - squareSize / 2;\r
@@ -3851,7 +4109,12 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
   if(saveDiagFlag) { \r
     BITMAP b; int i, j=0, m, w, wb, fac=0; char *pData; \r
     BITMAPINFOHEADER bih; int color[16], nrColors=0;\r
+    HBITMAP src = bufferBitmap, obmp; HDC tmp = CreateCompatibleDC(hdc);\r
 \r
+    bufferBitmap = CreateCompatibleBitmap(hdc, boardRect.right-boardRect.left, Rect.bottom-Rect.top-2*OUTER_MARGIN);\r
+    obmp = SelectObject(tmp, bufferBitmap);\r
+    BitBlt(tmp, 0, 0, boardRect.right - boardRect.left, Rect.bottom - Rect.top - 2*OUTER_MARGIN,\r
+           tmphdc, boardRect.left, OUTER_MARGIN, SRCCOPY);\r
     GetObject(bufferBitmap, sizeof(b), &b);\r
     if(pData = malloc(b.bmWidthBytes*b.bmHeight + 10000)) {\r
        bih.biSize = sizeof(BITMAPINFOHEADER);\r
@@ -3919,6 +4182,9 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
                fputc(pData[i], diagFile);\r
        free(pData);\r
      }\r
+     DeleteObject(bufferBitmap); bufferBitmap = src;\r
+     SelectObject(tmp, obmp);\r
+     DeleteDC(tmp);\r
   }\r
 \r
   SelectObject(tmphdc, oldBitmap);\r
@@ -4012,11 +4278,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
@@ -4062,10 +4328,11 @@ 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
@@ -4120,16 +4387,19 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
   }\r
 \r
   shiftKey = GetKeyState(VK_SHIFT) < 0; // [HGM] remember last shift status\r
+  controlKey = GetKeyState(VK_CONTROL) < 0; // [HGM] remember last shift status\r
 \r
   switch (message) {\r
   case WM_LBUTTONDOWN:\r
       if (PtInRect((LPRECT) &whiteRect, pt)) {\r
-        ClockClick(flipClock);\r
+        ClockClick(flipClock); break;\r
       } else if (PtInRect((LPRECT) &blackRect, pt)) {\r
-       ClockClick(!flipClock);\r
+       ClockClick(!flipClock); break;\r
       }\r
+    if(dragging) { // [HGM] lion: don't destroy dragging info if we are already dragging\r
       dragInfo.start.x = dragInfo.start.y = -1;\r
       dragInfo.from = dragInfo.start;\r
+    }\r
     if(fromX == -1 && frozen) { // not sure where this is for\r
                fromX = fromY = -1; \r
       DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */\r
@@ -4149,7 +4419,7 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     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
+       && (wParam & MK_LBUTTON || dragging == 2)\r
        && dragInfo.from.x >= 0) \r
     {\r
       BOOL full_repaint = FALSE;\r
@@ -4158,7 +4428,7 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
        dragInfo.pos = pt;\r
       }\r
       if (appData.highlightDragging) {\r
-       SetHighlights(fromX, fromY, x, y);\r
+       HoverEvent(highlightInfo.sq[1].x, highlightInfo.sq[1].y, x, y);\r
         if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {\r
             full_repaint = TRUE;\r
         }\r
@@ -4206,9 +4476,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
@@ -4234,7 +4504,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
@@ -4293,13 +4563,17 @@ ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
   return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);\r
 }\r
 \r
+static int promoStyle;\r
+\r
 /* Process messages for Promotion dialog box */\r
 LRESULT CALLBACK\r
 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
 {\r
+\r
   char promoChar;\r
 \r
   switch (message) {\r
+\r
   case WM_INITDIALOG: /* message: initialize dialog box */\r
     /* Center the dialog over the application window */\r
     CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));\r
@@ -4323,13 +4597,9 @@ Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
          PieceToChar(BlackMarshall) != '~')   ) ?\r
               SW_SHOW : SW_HIDE);\r
     /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */\r
-    ShowWindow(GetDlgItem(hDlg, PB_Rook),\r
-       gameInfo.variant != VariantShogi ?\r
-              SW_SHOW : SW_HIDE);\r
-    ShowWindow(GetDlgItem(hDlg, PB_Bishop), \r
-       gameInfo.variant != VariantShogi ?\r
-              SW_SHOW : SW_HIDE);\r
-    if(gameInfo.variant == VariantShogi) {\r
+    ShowWindow(GetDlgItem(hDlg, PB_Rook),   !promoStyle ? SW_SHOW : SW_HIDE);\r
+    ShowWindow(GetDlgItem(hDlg, PB_Bishop), !promoStyle ? SW_SHOW : SW_HIDE);\r
+    if(promoStyle) {\r
         SetDlgItemText(hDlg, PB_Queen, "YES");\r
         SetDlgItemText(hDlg, PB_Knight, "NO");\r
         SetWindowText(hDlg, "Promote?");\r
@@ -4350,7 +4620,7 @@ 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 ? '+' : ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteQueen : BlackQueen));\r
+      promoChar = promoStyle ? '+' : ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteQueen : BlackQueen));\r
       break;\r
     case PB_Rook:\r
       promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteRook : BlackRook));\r
@@ -4367,7 +4637,8 @@ Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
       promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteAngel : BlackAngel));\r
       break;\r
     case PB_Knight:\r
-      promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(WhiteOnMove(currentMove) ? WhiteKnight : BlackKnight);\r
+      promoChar = gameInfo.variant == VariantShogi ? '=' : promoStyle ? NULLCHAR : \r
+                  ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteKnight : BlackKnight));\r
       break;\r
     default:\r
       return FALSE;\r
@@ -4398,20 +4669,13 @@ PromotionPopup(HWND hwnd)
 }\r
 \r
 void\r
-PromotionPopUp()\r
+PromotionPopUp(char choice)\r
 {\r
+  promoStyle = (choice == '+' || IS_SHOGI(gameInfo.variant));\r
   DrawPosition(TRUE, NULL);\r
   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
@@ -4545,13 +4809,13 @@ LRESULT CALLBACK
 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)\r
 {\r
   FARPROC lpProc;\r
-  int wmId, wmEvent;\r
+  int wmId;\r
   char *defName;\r
   FILE *f;\r
   UINT number;\r
   char fileTitle[MSG_SIZ];\r
-  char buf[MSG_SIZ];\r
   static SnapData sd;\r
+  static int peek=0;\r
 \r
   switch (message) {\r
 \r
@@ -4579,7 +4843,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
@@ -4608,6 +4888,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       nnew = RealizePalette(hdc);\r
       if (nnew > 0) {\r
        paletteChanged = TRUE;\r
+\r
         InvalidateRect(hwnd, &boardRect, FALSE);\r
       }\r
       ReleaseDC(hwnd, hdc);\r
@@ -4631,7 +4912,6 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 \r
   case WM_COMMAND: /* message: command from application menu */\r
     wmId    = LOWORD(wParam);\r
-    wmEvent = HIWORD(wParam);\r
 \r
     switch (wmId) {\r
     case IDM_NewGame:\r
@@ -4724,6 +5004,20 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       }\r
       break;\r
 \r
+    case IDM_SaveSelected:\r
+      f = OpenFileDialog(hwnd, "a", "",\r
+                        "pgn",\r
+                        GAME_FILT,\r
+                        _("Save Game to File"), NULL, fileTitle, NULL);\r
+      if (f != NULL) {\r
+       SaveSelected(f, 0, "");\r
+      }\r
+      break;\r
+\r
+    case IDM_CreateBook:\r
+      CreateBookEvent();\r
+      break;\r
+\r
     case IDM_CopyGame:\r
       CopyGameToClipboard();\r
       break;\r
@@ -4848,12 +5142,14 @@ 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(matchMode) EnableMenuItem(GetMenu(hwndMain), IDM_Match, MF_BYCOMMAND|MF_GRAYED);\r
       MatchEvent(2); // distinguish from command-line-triggered case (matchMode=1)\r
       break;\r
 \r
     case IDM_TwoMachines:\r
       TwoMachinesEvent();\r
       /*\r
+\r
        * refresh the tags dialog only if it's visible\r
        */\r
       if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {\r
@@ -4866,52 +5162,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
@@ -4942,9 +5199,12 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       EditTagsPopUp(firstChessProgramNames, &firstChessProgramNames);\r
       break;\r
 \r
-    case IDM_EditProgs2:\r
-     LoadEnginePopUp(hwndMain);\r
-//      EditTagsPopUp(secondChessProgramNames, &secondChessProgramNames);\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
@@ -4982,6 +5242,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       break;\r
 \r
     case IDM_Rematch:\r
+\r
       RematchEvent();\r
       break;\r
 \r
@@ -5047,6 +5308,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
@@ -5093,6 +5359,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
@@ -5408,6 +5678,9 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       break;\r
 \r
     default:\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
@@ -5459,7 +5732,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     if( hwnd == hwndMain && appData.useStickyWindows ) {\r
         LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;\r
 \r
-        if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {\r
+        if( ((lpwp->flags & SWP_NOMOVE) == 0) /*&& ((lpwp->flags & SWP_NOSIZE) != 0)*/ ) { // [HGM] in Win8 size always accompanies move?\r
             /* Window is moving */\r
             RECT rcMain;\r
 \r
@@ -5476,6 +5749,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
             ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );\r
            wpMain.x = lpwp->x;\r
             wpMain.y = lpwp->y;\r
+\r
         }\r
     }\r
     break;\r
@@ -5528,6 +5802,8 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
   default:     /* Passes it on if unprocessed */\r
     return (DefWindowProc(hwnd, message, wParam, lParam));\r
   }\r
+\r
+\r
   return 0;\r
 }\r
 \r
@@ -5616,7 +5892,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
@@ -5637,6 +5913,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
@@ -5647,6 +5924,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
@@ -6117,13 +6395,15 @@ 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, singleList ? "/fcp=" : "/scp=", sizeof(buf)/sizeof(buf[0]) );\r
        GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));\r
-        p = buf;
+        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
+\r
        appData.noChessProgram = FALSE;\r
        appData.icsActive = FALSE;\r
       } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {\r
@@ -6214,7 +6494,7 @@ LRESULT CALLBACK
 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
 {\r
   static HANDLE hwndText = NULL;\r
-  int len, newSizeX, newSizeY, flags;\r
+  int len, newSizeX, newSizeY;\r
   static int sizeX, sizeY;\r
   char *str;\r
   RECT rect;\r
@@ -6242,7 +6522,6 @@ CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
     /* Size and position the dialog */\r
     if (!commentDialog) {\r
       commentDialog = hDlg;\r
-      flags = SWP_NOZORDER;\r
       GetClientRect(hDlg, &rect);\r
       sizeX = rect.right;\r
       sizeY = rect.bottom;\r
@@ -6430,10 +6709,10 @@ 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));
+      GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));\r
       TypeInDoneEvent(move);\r
       EndDialog(hDlg, TRUE);\r
       return TRUE;\r
@@ -6488,7 +6767,7 @@ TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
     case IDOK:\r
       GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));\r
       appData.userName = strdup(move);\r
-      SetUserLogo();\r
+      SetUserLogo(); DisplayLogos();\r
       SetGameInfo();\r
       if(gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack) {\r
        snprintf(move, MSG_SIZ, "%s vs. %s", gameInfo.white, gameInfo.black);\r
@@ -6579,7 +6858,6 @@ ErrorPopDown()
 LRESULT CALLBACK\r
 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
 {\r
-  HANDLE hwndText;\r
   RECT rChild;\r
 \r
   switch (message) {\r
@@ -6603,7 +6881,6 @@ ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
 \r
     errorDialog = hDlg;\r
     SetWindowText(hDlg, errorTitle);\r
-    hwndText = GetDlgItem(hDlg, OPT_ErrorText);\r
     SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);\r
     return FALSE;\r
 \r
@@ -6629,7 +6906,6 @@ HWND gothicDialog = NULL;
 LRESULT CALLBACK\r
 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
 {\r
-  HANDLE hwndText;\r
   RECT rChild;\r
   int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);\r
 \r
@@ -6648,7 +6924,6 @@ GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
     */\r
     gothicDialog = hDlg;\r
     SetWindowText(hDlg, errorTitle);\r
-    hwndText = GetDlgItem(hDlg, OPT_ErrorText);\r
     SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);\r
     return FALSE;\r
 \r
@@ -6701,6 +6976,7 @@ GothicPopUp(char *title, VariantClass variant)
 static char *history[HISTORY_SIZE];\r
 int histIn = 0, histP = 0;\r
 \r
+\r
 VOID\r
 SaveInHistory(char *cmd)\r
 {\r
@@ -6713,6 +6989,7 @@ SaveInHistory(char *cmd)
   histIn = (histIn + 1) % HISTORY_SIZE;\r
   if (history[histIn] != NULL) {\r
     free(history[histIn]);\r
+\r
     history[histIn] = NULL;\r
   }\r
   histP = histIn;\r
@@ -7396,7 +7673,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
@@ -7428,8 +7705,9 @@ 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
+    if (tinyLayout == 2)\r
       snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%c %s %s", color[0], TimeString(timeRemaining), flagFell);\r
     else\r
       snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);\r
@@ -7445,6 +7723,7 @@ DisplayAClock(HDC hdc, int timeRemaining, int highlight,
     oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */\r
     oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */\r
   }\r
+\r
   oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);\r
 \r
   JAWS_SILENCE\r
@@ -7522,6 +7801,7 @@ DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
       else\r
        err = GetLastError();\r
     }\r
+\r
   }\r
   return err;\r
 }\r
@@ -7760,6 +8040,7 @@ Enables gnuEnables[] = {
   { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },\r
 \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
@@ -7792,7 +8073,8 @@ Enables icsEnables[] = {
   { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_Book, MF_BYCOMMAND|MF_GRAYED },\r
-  { IDM_EditProgs2, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_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
@@ -7988,6 +8270,8 @@ ModeHighlight()
     nowChecked = 0;\r
     break;\r
   }\r
+  if(prevChecked == IDM_TwoMachines) // [HGM] 'Machine Match' might have gotten disabled when stopping match\r
+    EnableMenuItem(GetMenu(hwndMain), IDM_Match, MF_BYCOMMAND|MF_ENABLED);\r
   CheckMark(prevChecked, MF_UNCHECKED);\r
   CheckMark(nowChecked, MF_CHECKED);\r
   CheckMark(IDM_Match, matchMode && matchGame < appData.matchGames ? MF_CHECKED : MF_UNCHECKED);\r
@@ -8146,8 +8430,8 @@ DisplayMessage(char *str1, char *str2)
     if (len > remain) len = remain;\r
     strncat(messageText, str2, len);\r
   }\r
-  messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
-  safeStrCpy(lastMsg, messageText, MSG_SIZ);
+  messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;\r
+  safeStrCpy(lastMsg, messageText, MSG_SIZ);\r
 \r
   if (hwndMain == NULL || IsIconic(hwndMain)) return;\r
 \r
@@ -8232,6 +8516,7 @@ DisplayFatalError(char *str, int error, int exitStatus)
     fprintf(debugFP, "%s: %s\n", label, str);\r
   }\r
   if (appData.popupExitMessage) {\r
+    if(appData.icsActive) SendToICS("logout\n"); // [HGM] make sure no new games will be started!\r
     (void) MessageBox(hwndMain, str, label, MB_OK|\r
                      (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));\r
   }\r
@@ -8386,6 +8671,7 @@ HWND gameListOptionsDialog;
 \r
 // low-level front-end: clear text edit / list widget\r
 void\r
+\r
 GLT_ClearList()\r
 {\r
     SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );\r
@@ -8494,8 +8780,11 @@ int GameListOptions()
     result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)lpUserGLT );\r
 \r
     if( result == 0 ) {\r
+        char *oldTags = appData.gameListTags;\r
         /* [AS] Memory leak here! */\r
         appData.gameListTags = strdup( lpUserGLT ); \r
+        if(strcmp(oldTags, appData.gameListTags)) // [HGM] redo Game List when we changed something\r
+            GameListToListBox(NULL, TRUE, ".", NULL, FALSE, FALSE); // "." as filter is kludge to select all\r
     }\r
 \r
     return result;\r
@@ -8507,7 +8796,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
@@ -8565,6 +8866,13 @@ EditCommentPopUp(int index, char *title, char *str)
 }\r
 \r
 \r
+int\r
+Roar()\r
+{\r
+  MyPlaySound(&sounds[(int)SoundRoar]);\r
+  return 1;\r
+}\r
+\r
 VOID\r
 RingBell()\r
 {\r
@@ -8597,6 +8905,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
@@ -8716,6 +9030,7 @@ DisplayBlackClock(long timeRemaining, int highlight)
   HDC hdc;\r
   char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";\r
 \r
+\r
   if(appData.noGUI) return;\r
   hdc = GetDC(hwndMain);\r
   if (!IsIconic(hwndMain)) {\r
@@ -8824,11 +9139,43 @@ IDLE_PRIORITY_CLASS         0x00000040
 */\r
         if (nice < -15) return 0x00000080;\r
         if (nice < 0)   return 0x00008000;\r
+\r
         if (nice == 0)  return 0x00000020;\r
         if (nice < 15)  return 0x00004000;\r
         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
@@ -8912,9 +9259,6 @@ StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
    * dir relative to the directory WinBoard loaded from. */\r
   GetCurrentDirectory(MSG_SIZ, buf);\r
   SetCurrentDirectory(installDir);\r
-  // kludgey way to update logos in tourney, as long as back-end can't do it\r
-  if(!strcmp(cmdLine, first.program)) LoadLogo(&first, 0); else\r
-  if(!strcmp(cmdLine, second.program)) LoadLogo(&second, 1);\r
   SetCurrentDirectory(dir);\r
 \r
   /* Now create the child process. */\r
@@ -8999,15 +9343,15 @@ DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
     /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/\r
 \r
     /* [AS] Special termination modes for misbehaving programs... */\r
-    if( signal == 9 ) { \r
+    if( signal & 8 ) { \r
         result = TerminateProcess( cp->hProcess, 0 );\r
 \r
         if ( appData.debugMode) {\r
             fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );\r
         }\r
     }\r
-    else if( signal == 10 ) {\r
-        DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most\r
+    else if( signal & 4 ) {\r
+        DWORD dw = WaitForSingleObject( cp->hProcess, appData.delayAfterQuit*1000 + 50 ); // Wait 3 seconds at most\r
 \r
         if( dw != WAIT_OBJECT_0 ) {\r
             result = TerminateProcess( cp->hProcess, 0 );\r
@@ -9091,6 +9435,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
@@ -9503,6 +9848,7 @@ OutputToProcess(ProcRef pr, char *message, int count, int *outError)
   int outCount = SOCKET_ERROR;\r
   ChildProc *cp = (ChildProc *) pr;\r
   static OVERLAPPED ovl;\r
+\r
   static int line = 0;\r
 \r
   if (pr == NoProc)\r
@@ -9567,6 +9913,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
@@ -9587,7 +9939,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
@@ -9599,8 +9951,10 @@ ICSInitScript()
     if (f != NULL) {\r
       ProcessICSInitScript(f);\r
       fclose(f);\r
+      return TRUE;\r
     }\r
   }\r
+  return FALSE;\r
 }\r
 \r
 \r
@@ -9696,17 +10050,28 @@ AnimateMove(board, fromX, fromY, toX, toY)
      int toX;\r
      int toY;\r
 {\r
-  ChessSquare piece;\r
+  ChessSquare piece, victim = EmptySquare, victim2 = EmptySquare;\r
+  int x = toX, y = toY, x2 = kill2X;\r
   POINT start, finish, mid;\r
   POINT frames[kFactor * 2 + 1];\r
   int nFrames, n;\r
 \r
+  if(killX >= 0 && IS_LION(board[fromY][fromX])) Roar();\r
+\r
   if (!appData.animate) return;\r
   if (doingSizing) return;\r
   if (fromY < 0 || fromX < 0) return;\r
   piece = board[fromY][fromX];\r
   if (piece >= EmptySquare) return;\r
 \r
+  if(x2 >= 0) toX = kill2X, toY = kill2Y,  victim = board[killY][killX], victim2 = board[kill2Y][kill2X]; else\r
+  if(killX >= 0) toX = killX, toY = killY, victim = board[killY][killX]; // [HGM] lion: first to kill square\r
+\r
+  animInfo.from.x = fromX;\r
+  animInfo.from.y = fromY;\r
+\r
+again:\r
+\r
   ScreenSquare(fromX, fromY, &start);\r
   ScreenSquare(toX, toY, &finish);\r
 \r
@@ -9731,20 +10096,31 @@ AnimateMove(board, fromX, fromY, toX, toY)
   else\r
     Tween(&start, &mid, &finish, kFactor, frames, &nFrames);\r
 \r
-  animInfo.from.x = fromX;\r
-  animInfo.from.y = fromY;\r
   animInfo.to.x = toX;\r
   animInfo.to.y = toY;\r
   animInfo.lastpos = start;\r
   animInfo.piece = piece;\r
   for (n = 0; n < nFrames; n++) {\r
     animInfo.pos = frames[n];\r
-    DrawPosition(FALSE, NULL);\r
+    DrawPosition(FALSE, board);\r
     animInfo.lastpos = animInfo.pos;\r
     Sleep(appData.animSpeed);\r
   }\r
   animInfo.pos = finish;\r
-  DrawPosition(FALSE, NULL);\r
+  DrawPosition(FALSE, board);\r
+\r
+  if(toX == x2 && toY == kill2Y) {\r
+    fromX = toX; fromY = toY; toX = killX; toY = killY; x2 = -1;\r
+    board[kill2Y][kill2X] = EmptySquare; goto again;\r
+  } // second leg\r
+  if(toX != x || toY != y) {\r
+    fromX = toX; fromY = toY; toX = x; toY = y;\r
+    board[killY][killX] = EmptySquare; goto again;\r
+  } // second leg\r
+\r
+if(victim2 != EmptySquare) board[kill2Y][kill2X] = victim2;\r
+if(victim  != EmptySquare) board[killY][killX] = victim;\r
+\r
   animInfo.piece = EmptySquare;\r
   Explode(board, fromX, fromY, toX, toY);\r
 }\r
@@ -9756,11 +10132,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
@@ -9808,14 +10184,6 @@ Tween(start, mid, finish, factor, frames, nFrames)
 }\r
 \r
 void\r
-HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )\r
-{\r
-    MoveHistorySet( movelist, first, last, current, pvInfoList );\r
-\r
-    EvalGraphSet( first, last, current, pvInfoList );\r
-}\r
-\r
-void\r
 SettingsPopUp(ChessProgramState *cps)\r
 {     // [HGM] wrapper needed because handles must not be passed through back-end\r
       EngineOptionsPopup(savedHwnd, cps);\r
@@ -9830,9 +10198,31 @@ int flock(int fid, int code)
     ov.OffsetHigh = 0;\r
     switch(code) {\r
       case 1: LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1024, 0, &ov); break;   // LOCK_SH\r
+\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
+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
+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(boardSize, 0);\r
+   InvalidateRect(hwndMain, NULL, TRUE);\r
+}\r