Fix multi-leg promotions
[xboard.git] / winboard / winboard.c
index 1b8460b..e4b8692 100644 (file)
@@ -5,7 +5,8 @@
  * Massachusetts.\r
  *\r
  * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,\r
- * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 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
@@ -166,7 +167,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, border;\r
+int squareSize, lineGap, minorSize;\r
 static int winW, winH;\r
 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo\r
 static int logoHeight = 0;\r
@@ -260,7 +261,8 @@ int dialogItems[][42] = {
 { 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, 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
+  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
@@ -533,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
@@ -586,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
@@ -600,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
@@ -785,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
@@ -822,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
@@ -889,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
@@ -908,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
@@ -1081,6 +1107,8 @@ InitGeometry()
   screenGeometry.bottom = screenGeometry.top + screenHeight;\r
 }\r
 \r
+ChessProgramState broadcast;\r
+\r
 BOOL\r
 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)\r
 {\r
@@ -1113,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
@@ -1227,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
@@ -1257,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
@@ -1810,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
@@ -2299,6 +2344,7 @@ InitDrawingSizes(BoardSize boardSize, int flags)
   { // 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
@@ -2321,13 +2367,17 @@ InitDrawingSizes(BoardSize boardSize, int flags)
   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
   }\r
 \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
@@ -2363,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
@@ -2484,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
@@ -2553,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
@@ -2654,14 +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
     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
-\r
-    if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */\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
@@ -2761,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
@@ -3677,6 +3753,8 @@ void DrawSeekClose()
 {\r
 }\r
 \r
+\r
+\r
 VOID\r
 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)\r
 {\r
@@ -3897,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
@@ -3961,6 +4040,7 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
   }\r
 \r
   if( appData.highlightMoveWithArrow ) {\r
+\r
     DrawArrowHighlight(hdcmem);\r
   }\r
 \r
@@ -3977,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
@@ -4028,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
@@ -4096,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
@@ -4480,9 +4569,11 @@ static int promoStyle;
 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
@@ -4580,7 +4671,7 @@ PromotionPopup(HWND hwnd)
 void\r
 PromotionPopUp(char choice)\r
 {\r
-  promoStyle = (choice == '+');\r
+  promoStyle = (choice == '+' || IS_SHOGI(gameInfo.variant));\r
   DrawPosition(TRUE, NULL);\r
   PromotionPopup(hwndMain);\r
 }\r
@@ -4718,7 +4809,7 @@ 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
@@ -4821,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
@@ -4914,6 +5004,16 @@ 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
@@ -5042,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
@@ -5630,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
@@ -5647,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
@@ -5699,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
@@ -6389,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
@@ -6417,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
@@ -6663,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
@@ -6754,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
@@ -6778,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
@@ -6804,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
@@ -6823,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
@@ -7607,7 +7707,7 @@ DisplayAClock(HDC hdc, int timeRemaining, int highlight,
 \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
@@ -7623,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
@@ -7939,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
@@ -8168,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
@@ -8412,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
@@ -8675,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
@@ -9031,6 +9139,7 @@ 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
@@ -9234,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
@@ -9739,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
@@ -9940,8 +10050,8 @@ AnimateMove(board, fromX, fromY, toX, toY)
      int toX;\r
      int toY;\r
 {\r
-  ChessSquare piece;\r
-  int x = toX, y = toY;\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
@@ -9954,7 +10064,11 @@ AnimateMove(board, fromX, fromY, toX, toY)
   piece = board[fromY][fromX];\r
   if (piece >= EmptySquare) return;\r
 \r
-  if(killX >= 0) toX = killX, toY = killY; // [HGM] lion: first to kill square\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
@@ -9982,22 +10096,30 @@ again:
   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(toX != x || toY != y) { fromX = toX; fromY = toY; toX = x; toY = y; goto again; } // second leg\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
@@ -10076,6 +10198,7 @@ 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