Make book-edit function WB
[xboard.git] / winboard / winboard.c
index f27a1e6..722b9c8 100644 (file)
@@ -73,6 +73,7 @@
 #include <richedit.h>\r
 #include <mmsystem.h>\r
 #include <ctype.h>\r
+#include <io.h>\r
 \r
 #if __GNUC__\r
 #include <errno.h>\r
@@ -123,9 +124,10 @@ typedef struct {
   POINT pos;      /* window coordinates of current pos */\r
   POINT lastpos;  /* window coordinates of last pos - used for clipping */\r
   POINT from;     /* board coordinates of the piece's orig pos */\r
+  ChessSquare piece;\r
 } DragInfo;\r
 \r
-static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };\r
+static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, EmptySquare };\r
 \r
 typedef struct {\r
   POINT sq[2];   /* board coordinates of from, to squares */\r
@@ -154,6 +156,7 @@ char *programName;
 char *settingsFileName;\r
 Boolean saveSettingsOnExit;\r
 char installDir[MSG_SIZ];\r
+char homeDir[MSG_SIZ];\r
 int errorExitStatus;\r
 \r
 BoardSize boardSize;\r
@@ -345,6 +348,7 @@ LoadLanguageFile(char *name)
 \r
     if(!name || name[0] == NULLCHAR) return;\r
       snprintf(buf, MSG_SIZ, "%s%s", name, strchr(name, '.') ? "" : ".lng"); // auto-append lng extension\r
+    appData.language = oldLanguage;\r
     if(!strcmp(buf, oldLanguage)) { barbaric = 1; return; } // this language already loaded; just switch on\r
     if((f = fopen(buf, "r")) == NULL) return;\r
     while((k = fgetc(f)) != EOF) {\r
@@ -443,7 +447,7 @@ TranslateMenus(int addLanguage)
     int i;\r
     WIN32_FIND_DATA fileData;\r
     HANDLE hFind;\r
-#define IDM_English 1895\r
+#define IDM_English 1970\r
     if(1) {\r
         HMENU mainMenu = GetMenu(hwndMain);\r
         for (i=GetMenuItemCount(mainMenu)-1; i>=0; i--) {\r
@@ -651,7 +655,6 @@ LRESULT CALLBACK
   StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);\r
 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);\r
 void ParseIcsTextMenu(char *icsTextMenuString);\r
-VOID PopUpMoveDialog(char firstchar);\r
 VOID PopUpNameDialog(char firstchar);\r
 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);\r
 \r
@@ -953,6 +956,24 @@ EnsureOnScreen(int *x, int *y, int minX, int minY)
   if (*y < minY) *y = minY;\r
 }\r
 \r
+VOID\r
+LoadLogo(ChessProgramState *cps, int n)\r
+{\r
+  if( appData.logo[n] && appData.logo[n][0] != NULLCHAR) {\r
+      cps->programLogo = LoadImage( 0, appData.logo[n], IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );\r
+\r
+      if (cps->programLogo == NULL && appData.debugMode) {\r
+          fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.logo[n] );\r
+      }\r
+  } else if(appData.autoLogo) {\r
+      if(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
+      }\r
+  }\r
+}\r
+\r
 BOOL\r
 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)\r
 {\r
@@ -969,6 +990,7 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
   } else {\r
     GetCurrentDirectory(MSG_SIZ, installDir);\r
   }\r
+  safeStrCpy(homeDir, installDir, MSG_SIZ);\r
   gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise\r
   screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData\r
   InitAppData(lpCmdLine);      /* Get run-time parameters */\r
@@ -1008,19 +1030,7 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
   }\r
 \r
   /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */\r
-  if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {\r
-      first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );\r
-\r
-      if (first.programLogo == NULL && appData.debugMode) {\r
-          fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );\r
-      }\r
-  } else if(appData.autoLogo) {\r
-      if(appData.firstDirectory && appData.firstDirectory[0]) {\r
-       char buf[MSG_SIZ];\r
-         snprintf(buf, MSG_SIZ, "%s/logo.bmp", appData.firstDirectory);\r
-       first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );   \r
-      }\r
-  }\r
+  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
@@ -2223,7 +2233,7 @@ InitDrawingSizes(BoardSize boardSize, int flags)
   }\r
 \r
   if (tinyLayout != oldTinyLayout) {\r
-    long style = GetWindowLong(hwndMain, GWL_STYLE);\r
+    long style = GetWindowLongPtr(hwndMain, GWL_STYLE);\r
     if (tinyLayout) {\r
       style &= ~WS_SYSMENU;\r
       InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,\r
@@ -2232,7 +2242,7 @@ InitDrawingSizes(BoardSize boardSize, int flags)
       style |= WS_SYSMENU;\r
       RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);\r
     }\r
-    SetWindowLong(hwndMain, GWL_STYLE, style);\r
+    SetWindowLongPtr(hwndMain, GWL_STYLE, style);\r
 \r
     for (i=0; menuBarText[tinyLayout][i]; i++) {\r
       ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP, \r
@@ -2381,7 +2391,7 @@ InitDrawingSizes(BoardSize boardSize, int flags)
                     boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),\r
                     messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,\r
                     (HMENU) buttonDesc[i].id,\r
-                    (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);\r
+                    (HINSTANCE) GetWindowLongPtr(hwndMain, GWLP_HINSTANCE), NULL);\r
       if (tinyLayout) {\r
        SendMessage(buttonDesc[i].hwnd, WM_SETFONT, \r
                    (WPARAM)font[boardSize][MESSAGE_FONT]->hf,\r
@@ -2390,7 +2400,7 @@ InitDrawingSizes(BoardSize boardSize, int flags)
       if (buttonDesc[i].id == IDM_Pause)\r
        hwndPause = buttonDesc[i].hwnd;\r
       buttonDesc[i].wndproc = (WNDPROC)\r
-       SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);\r
+       SetWindowLongPtr(buttonDesc[i].hwnd, GWLP_WNDPROC, (LONG_PTR) ButtonProc);\r
     }\r
   }\r
   if (gridPen != NULL) DeleteObject(gridPen);\r
@@ -3795,8 +3805,8 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
     board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;\r
     x = dragInfo.pos.x - squareSize / 2;\r
     y = dragInfo.pos.y - squareSize / 2;\r
-    DrawPieceOnDC(hdcmem, dragged_piece,\r
-                 ((int) dragged_piece < (int) BlackPawn), \r
+    DrawPieceOnDC(hdcmem, dragInfo.piece,\r
+                 ((int) dragInfo.piece < (int) BlackPawn), \r
                   (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);\r
   }   \r
   \r
@@ -3841,11 +3851,11 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
         boardRect.bottom - boardRect.top,\r
         tmphdc, boardRect.left, boardRect.top, SRCCOPY);\r
   if(saveDiagFlag) { \r
-    BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000]; \r
+    BITMAP b; int i, j=0, m, w, wb, fac=0; char *pData; \r
     BITMAPINFOHEADER bih; int color[16], nrColors=0;\r
 \r
     GetObject(bufferBitmap, sizeof(b), &b);\r
-    if(b.bmWidthBytes*b.bmHeight <= 990000) {\r
+    if(pData = malloc(b.bmWidthBytes*b.bmHeight + 10000)) {\r
        bih.biSize = sizeof(BITMAPINFOHEADER);\r
        bih.biWidth = b.bmWidth;\r
        bih.biHeight = b.bmHeight;\r
@@ -3909,6 +3919,7 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
        // write bitmap data\r
        for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++) \r
                fputc(pData[i], diagFile);\r
+       free(pData);\r
      }\r
   }\r
 \r
@@ -3945,11 +3956,8 @@ SaveDiagram(f)
 {\r
     saveDiagFlag = 1; diagFile = f;\r
     HDCDrawPosition(NULL, TRUE, NULL);\r
-\r
     saveDiagFlag = 0;\r
 \r
-//    if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");\r
-    \r
     fclose(f);\r
     return TRUE;\r
 }\r
@@ -4062,6 +4070,7 @@ void DragPieceBegin(int x, int y)
       dragInfo.lastpos.y = boardRect.top + y;\r
       dragInfo.from.x = fromX;\r
       dragInfo.from.y = fromY;\r
+      dragInfo.piece = boards[currentMove][fromY][fromX];\r
       dragInfo.start = dragInfo.from;\r
       SetCapture(hwndMain);\r
 }\r
@@ -4074,6 +4083,11 @@ void DragPieceEnd(int x, int y)
     dragInfo.pos = dragInfo.lastpos = dragInfo.start;\r
 }\r
 \r
+void ChangeDragPiece(ChessSquare piece)\r
+{\r
+    dragInfo.piece = piece;\r
+}\r
+\r
 /* Event handler for mouse messages */\r
 VOID\r
 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)\r
@@ -4134,6 +4148,7 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 \r
   case WM_MOUSEMOVE:\r
     if(SeekGraphClick(Press, pt.x - boardRect.left, pt.y - boardRect.top, 1)) break;\r
+    if(PromoScroll(pt.x - boardRect.left, pt.y - boardRect.top)) break;\r
     MovePV(pt.x - boardRect.left, pt.y - boardRect.top, boardRect.bottom - boardRect.top);\r
     if ((appData.animateDragging || appData.highlightDragging)\r
        && (wParam & MK_LBUTTON)\r
@@ -4240,7 +4255,7 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 LRESULT CALLBACK\r
 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)\r
 {\r
-  int id = GetWindowLong(hwnd, GWL_ID);\r
+  int id = GetWindowLongPtr(hwnd, GWLP_ID);\r
   int i, dir;\r
 \r
   for (i=0; i<N_BUTTONS; i++) {\r
@@ -4271,7 +4286,7 @@ ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
        SendMessage(h, WM_CHAR, wParam, lParam);\r
        return TRUE;\r
       } else if (isalpha((char)wParam) || isdigit((char)wParam)){\r
-       PopUpMoveDialog((char)wParam);\r
+       TypeInEvent((char)wParam);\r
       }\r
       break;\r
     }\r
@@ -4470,11 +4485,11 @@ void UpdateICSWidth(HWND hText)
     LONG old_width, new_width;\r
 \r
     new_width = get_term_width(hText, FALSE);\r
-    old_width = GetWindowLong(hText, GWL_USERDATA);\r
+    old_width = GetWindowLongPtr(hText, GWLP_USERDATA);\r
     if (new_width != old_width)\r
     {\r
         ics_update_width(new_width);\r
-        SetWindowLong(hText, GWL_USERDATA, new_width);\r
+        SetWindowLongPtr(hText, GWLP_USERDATA, new_width);\r
     }\r
 }\r
 \r
@@ -4580,7 +4595,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
        SendMessage(h, message, wParam, lParam);\r
     } else if(lParam != KF_REPEAT) {\r
        if (isalpha((char)wParam) || isdigit((char)wParam)) {\r
-               PopUpMoveDialog((char)wParam);\r
+               TypeInEvent((char)wParam);\r
        } else if((char)wParam == 003) CopyGameToClipboard();\r
         else if((char)wParam == 026) PasteGameOrFENFromClipboard();\r
     }\r
@@ -4705,7 +4720,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       f = OpenFileDialog(hwnd, "wb", defName,\r
                         "bmp",\r
                         DIAGRAM_FILT,\r
-                        "Save Diagram to File", NULL, fileTitle, NULL);\r
+                        _("Save Diagram to File"), NULL, fileTitle, NULL);\r
       if (f != NULL) {\r
        SaveDiagram(f);\r
       }\r
@@ -4835,13 +4850,8 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       break;\r
 \r
     case IDM_Match: // [HGM] match: flows into next case, after setting Match Mode and nr of Games\r
-      if(gameMode != BeginningOfGame) { // allow menu item to remain enabled for better mode highligting\r
-        DisplayError(_("You can only start a match from the initial position."), 0); break;\r
-      }\r
-      matchMode = 2;// distinguish from command-line-triggered case (matchMode=1)\r
-      appData.matchGames = appData.defaultMatchGames;\r
-      matchGame = 1;\r
-      first.matchWins = second.matchWins = 0;\r
+      MatchEvent(2); // distinguish from command-line-triggered case (matchMode=1)\r
+      break;\r
 \r
     case IDM_TwoMachines:\r
       TwoMachinesEvent();\r
@@ -4935,7 +4945,8 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       break;\r
 \r
     case IDM_EditProgs2:\r
-      EditTagsPopUp(secondChessProgramNames, &secondChessProgramNames);\r
+     LoadEnginePopUp(hwndMain);\r
+//      EditTagsPopUp(secondChessProgramNames, &secondChessProgramNames);\r
       break;\r
 \r
     case IDM_EditServers:\r
@@ -4947,6 +4958,10 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       EditTagsProc();\r
       break;\r
 \r
+    case IDM_EditBook:\r
+      EditBookEvent();\r
+      break;\r
+\r
     case IDM_EditComment:\r
     case IDM_Comment:\r
       if (commentUp && editComment) {\r
@@ -5005,7 +5020,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       break;\r
 \r
     case IDM_TypeInMove:\r
-      PopUpMoveDialog('\000');\r
+      TypeInEvent('\000');\r
       break;\r
 \r
     case IDM_TypeInName:\r
@@ -5090,7 +5105,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 \r
     case IDM_Engine2Options:\r
       savedHwnd = hwnd;\r
-      if(WaitForSecond(SettingsMenuIfReady)) break;\r
+      if(WaitForEngine(&second, SettingsMenuIfReady)) break;\r
       EngineOptionsPopup(hwnd, &second);\r
       break;\r
 \r
@@ -5098,6 +5113,10 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       UciOptionsPopup(hwnd);\r
       break;\r
 \r
+    case IDM_Tourney:\r
+      TourneyPopup(hwnd);\r
+      break;\r
+\r
     case IDM_IcsOptions:\r
       IcsOptionsPopup(hwnd);\r
       break;\r
@@ -5383,7 +5402,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       break;\r
 \r
     case IDM_English:\r
-      barbaric = 0;\r
+      barbaric = 0; appData.language = "";\r
       TranslateMenus(0);\r
       CheckMenuItem(GetMenu(hwndMain), lastChecked, MF_BYCOMMAND|MF_UNCHECKED);\r
       CheckMenuItem(GetMenu(hwndMain), IDM_English, MF_BYCOMMAND|MF_CHECKED);\r
@@ -5391,7 +5410,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       break;\r
 \r
     default:\r
-      if(wmId > IDM_English && wmId < IDM_English+5) {\r
+      if(wmId > IDM_English && wmId < IDM_English+20) {\r
           LoadLanguageFile(languageFile[wmId - IDM_English - 1]);\r
           TranslateMenus(0);\r
           CheckMenuItem(GetMenu(hwndMain), lastChecked, MF_BYCOMMAND|MF_UNCHECKED);\r
@@ -6063,8 +6082,8 @@ StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
                  appData.firstChessProgram, "fd", appData.firstDirectory,\r
                  firstChessProgramNames);\r
     InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),\r
-                 appData.secondChessProgram, "sd", appData.secondDirectory,\r
-                 secondChessProgramNames);\r
+                 appData.secondChessProgram, singleList ? "fd" : "sd", appData.secondDirectory,\r
+                 singleList ? firstChessProgramNames : secondChessProgramNames); //[HGM] single: use first list in second combo\r
     hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);\r
     InitComboStringsFromOption(hwndCombo, icsNames);    \r
       snprintf(buf, MSG_SIZ, "%s /icsport=%s", appData.icsHost, appData.icsPort);\r
@@ -6101,10 +6120,12 @@ StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
        GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));\r
         p = buf;\r
        ParseArgs(StringGet, &p);\r
-       safeStrCpy(buf, "/scp=", sizeof(buf)/sizeof(buf[0]) );\r
+       safeStrCpy(buf, singleList ? "/fcp=" : "/scp=", sizeof(buf)/sizeof(buf[0]) );\r
        GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));\r
-        p = buf;\r
+        p = buf;
+       SwapEngines(singleList); // temporarily swap first and second, to load a second 'first', ...\r
        ParseArgs(StringGet, &p);\r
+       SwapEngines(singleList); // ... and then make it 'second'\r
        appData.noChessProgram = FALSE;\r
        appData.icsActive = FALSE;\r
       } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {\r
@@ -6396,9 +6417,6 @@ TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
 {\r
   char move[MSG_SIZ];\r
   HWND hInput;\r
-  ChessMove moveType;\r
-  int fromX, fromY, toX, toY;\r
-  char promoChar;\r
 \r
   switch (message) {\r
   case WM_INITDIALOG:\r
@@ -6417,36 +6435,8 @@ TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
     case IDOK:
 \r
       shiftKey = GetKeyState(VK_SHIFT) < 0; // [HGM] remember last shift status\r
-      GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));\r
-      { int n; Board board;\r
-       // [HGM] FENedit\r
-       if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {\r
-               EditPositionPasteFEN(move);\r
-               EndDialog(hDlg, TRUE);\r
-               return TRUE;\r
-       }\r
-       // [HGM] movenum: allow move number to be typed in any mode\r
-       if(sscanf(move, "%d", &n) == 1 && n != 0 ) {\r
-         ToNrEvent(2*n-1);\r
-         EndDialog(hDlg, TRUE);\r
-         return TRUE;\r
-       }\r
-      }\r
-      if (gameMode != EditGame && currentMove != forwardMostMove && \r
-       gameMode != Training) {\r
-       DisplayMoveError(_("Displayed move is not current"));\r
-      } else {\r
-//     GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream\r
-       int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove, \r
-         &moveType, &fromX, &fromY, &toX, &toY, &promoChar);\r
-       if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized\r
-       if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove, \r
-         &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {\r
-         UserMoveEvent(fromX, fromY, toX, toY, promoChar);     \r
-       } else {\r
-         DisplayMoveError(_("Could not parse move"));\r
-       }\r
-      }\r
+      GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
+      TypeInDoneEvent(move);\r
       EndDialog(hDlg, TRUE);\r
       return TRUE;\r
     case IDCANCEL:\r
@@ -6464,21 +6454,11 @@ VOID
 PopUpMoveDialog(char firstchar)\r
 {\r
     FARPROC lpProc;\r
-    \r
-    if ((gameMode == BeginningOfGame && !appData.icsActive) || \r
-        gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||\r
-       gameMode == AnalyzeMode || gameMode == EditGame || \r
-       gameMode == EditPosition || gameMode == IcsExamining ||\r
-       gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||\r
-       isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes\r
-               ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||\r
-                 gameMode == IcsObserving || gameMode == TwoMachinesPlay    ) ||\r
-       gameMode == Training) {\r
+\r
       lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);\r
       DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),\r
        hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);\r
       FreeProcInstance(lpProc);\r
-    }\r
 }\r
 \r
 /*---------------------------------------------------------------------------*\\r
@@ -7189,10 +7169,10 @@ ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
     hwndConsole = hDlg;\r
     SetFocus(hInput);\r
     consoleTextWindowProc = (WNDPROC)\r
-      SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);\r
+      SetWindowLongPtr(hText, GWLP_WNDPROC, (LONG_PTR) ConsoleTextSubclass);\r
     SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);\r
     consoleInputWindowProc = (WNDPROC)\r
-      SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);\r
+      SetWindowLongPtr(hInput, GWLP_WNDPROC, (LONG_PTR) ConsoleInputSubclass);\r
     SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);\r
     Colorize(ColorNormal, TRUE);\r
     SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);\r
@@ -7238,7 +7218,7 @@ ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
    wMask = (WORD) SendMessage(hText, EM_GETEVENTMASK, 0, 0L);\r
    SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);\r
    SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);\r
-   SetWindowLong(hText, GWL_USERDATA, 79); // initialize the text window's width\r
+   SetWindowLongPtr(hText, GWLP_USERDATA, 79); // initialize the text window's width\r
 \r
     return FALSE;\r
 \r
@@ -7781,6 +7761,22 @@ Enables gnuEnables[] = {
   { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },\r
+\r
+  // Needed to switch from ncp to GNU mode on Engine Load\r
+  { ACTION_POS, MF_BYPOSITION|MF_ENABLED },\r
+  { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_Match, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_AnalyzeFile, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_Engine2Options, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_TimeControl, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_Book, MF_BYCOMMAND|MF_ENABLED },\r
   { -1, -1 }\r
 };\r
 \r
@@ -7798,10 +7794,12 @@ 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_IcsOptions, MF_BYCOMMAND|MF_ENABLED },\r
   { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_Tourney, MF_BYCOMMAND|MF_GRAYED },\r
   { -1, -1 }\r
 };\r
 \r
@@ -7893,7 +7891,7 @@ Enables machineThinkingEnables[] = {
   { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },\r
-  { IDM_Match, MF_BYCOMMAND|MF_GRAYED },\r
+//  { IDM_Match, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },\r
   { -1, -1 }\r
@@ -7913,7 +7911,7 @@ Enables userThinkingEnables[] = {
   { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },\r
   { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },\r
   { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },\r
-  { IDM_Match, MF_BYCOMMAND|MF_ENABLED },\r
+//  { IDM_Match, MF_BYCOMMAND|MF_ENABLED },\r
   { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },\r
   { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },\r
   { -1, -1 }\r
@@ -7926,6 +7924,12 @@ Enables userThinkingEnables[] = {
  * \r
 \*---------------------------------------------------------------------------*/\r
 VOID\r
+CheckMark(UINT item, int state)\r
+{\r
+    if(item) CheckMenuItem(GetMenu(hwndMain), item, MF_BYCOMMAND|state);\r
+}\r
+\r
+VOID\r
 ModeHighlight()\r
 {\r
   static UINT prevChecked = 0;\r
@@ -7955,7 +7959,7 @@ ModeHighlight()
     nowChecked = IDM_MachineWhite;\r
     break;\r
   case TwoMachinesPlay:\r
-    nowChecked = matchMode ? IDM_Match : IDM_TwoMachines; // [HGM] match\r
+    nowChecked = IDM_TwoMachines;\r
     break;\r
   case AnalyzeMode:\r
     nowChecked = IDM_AnalysisMode;\r
@@ -7986,12 +7990,9 @@ ModeHighlight()
     nowChecked = 0;\r
     break;\r
   }\r
-  if (prevChecked != 0)\r
-    (void) CheckMenuItem(GetMenu(hwndMain),\r
-                        prevChecked, MF_BYCOMMAND|MF_UNCHECKED);\r
-  if (nowChecked != 0)\r
-    (void) CheckMenuItem(GetMenu(hwndMain),\r
-                        nowChecked, MF_BYCOMMAND|MF_CHECKED);\r
+  CheckMark(prevChecked, MF_UNCHECKED);\r
+  CheckMark(nowChecked, MF_CHECKED);\r
+  CheckMark(IDM_Match, matchMode && matchGame < appData.matchGames ? MF_CHECKED : MF_UNCHECKED);\r
 \r
   if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {\r
     (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training, \r
@@ -8006,11 +8007,9 @@ ModeHighlight()
   /* [DM] icsEngineAnalyze - Do a sceure check too */\r
   if (appData.icsActive) {\r
        if (appData.icsEngineAnalyze) {\r
-               (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,\r
-                       MF_BYCOMMAND|MF_CHECKED);\r
+               CheckMark(IDM_AnalysisMode, MF_CHECKED);\r
        } else {\r
-               (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,\r
-                       MF_BYCOMMAND|MF_UNCHECKED);\r
+               CheckMark(IDM_AnalysisMode, MF_UNCHECKED);\r
        }\r
   }\r
   DisplayLogos(); // [HGM] logos: mode change could have altered logos\r
@@ -8149,7 +8148,8 @@ DisplayMessage(char *str1, char *str2)
     if (len > remain) len = remain;\r
     strncat(messageText, str2, len);\r
   }\r
-  messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;\r
+  messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
+  safeStrCpy(lastMsg, messageText, MSG_SIZ);
 \r
   if (hwndMain == NULL || IsIconic(hwndMain)) return;\r
 \r
@@ -8914,6 +8914,9 @@ 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
@@ -9819,3 +9822,19 @@ SettingsPopUp(ChessProgramState *cps)
 {     // [HGM] wrapper needed because handles must not be passed through back-end\r
       EngineOptionsPopup(savedHwnd, cps);\r
 }\r
+\r
+int flock(int fid, int code)\r
+{\r
+    HANDLE hFile = (HANDLE) _get_osfhandle(fid);\r
+    OVERLAPPED ov;\r
+    ov.hEvent = NULL;\r
+    ov.Offset = 0;\r
+    ov.OffsetHigh = 0;\r
+    switch(code) {\r
+      case 1: LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1024, 0, &ov); break;   // LOCK_SH\r
+      case 2: LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1024, 0, &ov); break;   // LOCK_EX\r
+      case 3: UnlockFileEx(hFile, 0, 1024, 0, &ov); break; // LOCK_UN\r
+      default: return -1;\r
+    }\r
+    return 0;\r
+}\r