Added internal wrapping ability.
[xboard.git] / winboard / winboard.c
index f08ddb6..62d5072 100644 (file)
@@ -1,11 +1,13 @@
 /*\r
  * WinBoard.c -- Windows NT front end to XBoard\r
- * $Id: winboard.c,v 2.3 2003/11/25 05:25:20 mann Exp $\r
  *\r
  * Copyright 1991 by Digital Equipment Corporation, Maynard,\r
- * Massachusetts.  Enhancements Copyright\r
- * 1992-2001,2002,2003,2004,2005,2006,2007,2008,2009 Free Software\r
- * Foundation, Inc.\r
+ * Massachusetts. \r
+ *\r
+ * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,\r
+ * 2007, 2008, 2009 Free Software Foundation, Inc.\r
+ *\r
+ * Enhancements Copyright 2005 Alessandro Scotti\r
  *\r
  * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,\r
  * which was written and is copyrighted by Wayne Christopher.\r
@@ -88,7 +90,7 @@
 #include "woptions.h"\r
 #include "wsockerr.h"\r
 #include "defaults.h"\r
-\r
+#include "help.h"\r
 #include "wsnap.h"\r
 \r
 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );\r
 \r
 extern int whiteFlag, blackFlag;\r
 Boolean flipClock = FALSE;\r
+extern HANDLE chatHandle[];\r
+extern int ics_type;\r
 \r
 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);\r
 VOID NewVariantPopup(HWND hwnd);\r
 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,\r
                   /*char*/int promoChar));\r
 void AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames);\r
-\r
+void DisplayMove P((int moveNumber));\r
+Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen));\r
+void ChatPopUp P(());\r
 typedef struct {\r
   ChessSquare piece;  \r
   POINT pos;      /* window coordinates of current pos */\r
@@ -143,7 +149,7 @@ char szConsoleName[] = "WBConsole";
 \r
 /* Title bar text */\r
 char szTitle[] = "WinBoard";\r
-char szConsoleTitle[] = "ICS Interaction";\r
+char szConsoleTitle[] = "I C S Interaction";\r
 \r
 char *programName;\r
 char *settingsFileName;\r
@@ -152,9 +158,10 @@ char installDir[MSG_SIZ];
 \r
 BoardSize boardSize;\r
 BOOLEAN chessProgram;\r
-static int boardX, boardY, consoleX, consoleY, consoleW, consoleH;\r
+static int boardX, boardY;\r
+int  minX, minY; // [HGM] placement: volatile limits on upper-left corner\r
 static int squareSize, lineGap, minorSize;\r
-static int winWidth, winHeight;\r
+static int winWidth, winHeight, winW, winH;\r
 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo\r
 static int logoHeight = 0;\r
 static char messageText[MESSAGE_TEXT_MAX];\r
@@ -201,6 +208,7 @@ static HICON iconWhite, iconBlack, iconCurrent;
 static int doingSizing = FALSE;\r
 static int lastSizing = 0;\r
 static int prevStderrPort;\r
+static HBITMAP userLogo;\r
 \r
 /* [AS] Support for background textures */\r
 #define BACK_TEXTURE_MODE_DISABLED      0\r
@@ -217,7 +225,11 @@ static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOAR
 #if __GNUC__ && !defined(_winmajor)\r
 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */\r
 #else\r
+#if defined(_winmajor)\r
 #define oldDialog (_winmajor < 4)\r
+#else\r
+#define oldDialog 0\r
+#endif\r
 #endif\r
 \r
 char *defaultTextAttribs[] = \r
@@ -304,7 +316,7 @@ MyButtonDesc buttonDesc[N_BUTTONS] =
 };\r
 \r
 int tinyLayout = 0, smallLayout = 0;\r
-#define MENU_BAR_ITEMS 6\r
+#define MENU_BAR_ITEMS 7\r
 char *menuBarText[2][MENU_BAR_ITEMS+1] = {\r
   { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },\r
   { "&F", "&M", "&A", "&S", "&O", "&H", NULL },\r
@@ -426,6 +438,8 @@ HWND engineOutputDialog = NULL;
 BOOLEAN engineOutputDialogUp = FALSE;\r
 \r
 WindowPlacement wpEngineOutput;\r
+WindowPlacement wpGameList;\r
+WindowPlacement wpConsole;\r
 \r
 VOID MoveHistoryPopUp();\r
 VOID MoveHistoryPopDown();\r
@@ -442,6 +456,8 @@ VOID EngineOutputPopDown();
 BOOL EngineOutputIsUp();\r
 VOID EngineOutputUpdate( FrontEndProgramStats * stats );\r
 \r
+VOID EngineOptionsPopup(); // [HGM] settings\r
+\r
 VOID GothicPopUp(char *title, VariantClass variant);\r
 /*\r
  * Setting "frozen" should disable all user input other than deleting\r
@@ -478,6 +494,26 @@ void ThawUI()
   DrawMenuBar(hwndMain);\r
 }\r
 \r
+/*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them\r
+\r
+/* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */\r
+#ifdef JAWS\r
+#include "jaws.c"\r
+#else\r
+#define JAWS_INIT\r
+#define JAWS_ARGS\r
+#define JAWS_ALT_INTERCEPT\r
+#define JAWS_KB_NAVIGATION\r
+#define JAWS_MENU_ITEMS\r
+#define JAWS_SILENCE\r
+#define JAWS_REPLAY\r
+#define JAWS_ACCEL\r
+#define JAWS_COPYRIGHT\r
+#define JAWS_DELETE(X) X\r
+#define SAYMACHINEMOVE()\r
+#define SAY(X)\r
+#endif\r
+\r
 /*---------------------------------------------------------------------------*\\r
  *\r
  * WinMain\r
@@ -504,6 +540,8 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
     return (FALSE);\r
   }\r
 \r
+  JAWS_INIT\r
+\r
 //  InitCommonControlsEx(&ex);\r
   InitCommonControls();\r
 \r
@@ -518,6 +556,77 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    0,    /* lowest message to examine */\r
                    0))   /* highest message to examine */\r
     {\r
+\r
+      if(msg.message == WM_CHAR && msg.wParam == '\t') {\r
+       // [HGM] navigate: switch between all windows with tab\r
+       HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;\r
+       int i, currentElement = 0;\r
+\r
+       // first determine what element of the chain we come from (if any)\r
+       if(appData.icsActive) {\r
+           hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);\r
+           hText  = GetDlgItem(hwndConsole, OPT_ConsoleText);\r
+       }\r
+       if(engineOutputDialog && EngineOutputIsUp()) {\r
+           e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);\r
+           e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);\r
+       }\r
+       if(moveHistoryDialog && MoveHistoryIsUp()) {\r
+           mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);\r
+       }\r
+       if(msg.hwnd == hwndMain) currentElement = 7 ; else\r
+       if(msg.hwnd == engineOutputDialog) currentElement = 2; else\r
+       if(msg.hwnd == e1)                 currentElement = 2; else\r
+       if(msg.hwnd == e2)                 currentElement = 3; else\r
+       if(msg.hwnd == moveHistoryDialog) currentElement = 4; else\r
+       if(msg.hwnd == mh)                currentElement = 4; else\r
+       if(msg.hwnd == evalGraphDialog)    currentElement = 6; else\r
+       if(msg.hwnd == hText)  currentElement = 5; else\r
+       if(msg.hwnd == hInput) currentElement = 6; else\r
+       for (i = 0; i < N_BUTTONS; i++) {\r
+           if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }\r
+       }\r
+\r
+       // determine where to go to\r
+       if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;\r
+         do {\r
+           currentElement = (currentElement + direction) % 7;\r
+           switch(currentElement) {\r
+               case 0:\r
+                 h = hwndMain; break; // passing this case always makes the loop exit\r
+               case 1:\r
+                 h = buttonDesc[0].hwnd; break; // could be NULL\r
+               case 2:\r
+                 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows\r
+                 h = e1; break;\r
+               case 3:\r
+                 if(!EngineOutputIsUp()) continue;\r
+                 h = e2; break;\r
+               case 4:\r
+                 if(!MoveHistoryIsUp()) continue;\r
+                 h = mh; break;\r
+//             case 6: // input to eval graph does not seem to get here!\r
+//               if(!EvalGraphIsUp()) continue;\r
+//               h = evalGraphDialog; break;\r
+               case 5:\r
+                 if(!appData.icsActive) continue;\r
+                 SAY("display");\r
+                 h = hText; break;\r
+               case 6:\r
+                 if(!appData.icsActive) continue;\r
+                 SAY("input");\r
+                 h = hInput; break;\r
+           }\r
+         } while(h == 0);\r
+\r
+         if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);\r
+         if(currentElement < 5 && IsIconic(hwndMain))    ShowWindow(hwndMain, SW_RESTORE); // all open together\r
+         SetFocus(h);\r
+\r
+         continue; // this message now has been processed\r
+       }\r
+      }\r
+\r
       if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&\r
           !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&\r
           !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&\r
@@ -525,9 +634,15 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
          !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&\r
          !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&\r
          !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&\r
-         !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) &&\r
+         !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL\r
           !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&\r
          !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {\r
+       int done = 0, i; // [HGM] chat: dispatch cat-box messages\r
+       for(i=0; i<MAX_CHAT; i++) \r
+           if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {\r
+               done = 1; break;\r
+       }\r
+       if(done) continue; // [HGM] chat: end patch\r
        TranslateMessage(&msg); /* Translates virtual key codes */\r
        DispatchMessage(&msg);  /* Dispatches message to window */\r
       }\r
@@ -543,6 +658,21 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  *\r
 \*---------------------------------------------------------------------------*/\r
 \r
+void\r
+SetUserLogo()\r
+{   // update user logo if necessary\r
+    static char oldUserName[MSG_SIZ], *curName;\r
+\r
+    if(appData.autoLogo) {\r
+         curName = UserName();\r
+         if(strcmp(curName, oldUserName)) {\r
+               sprintf(oldUserName, "logos\\%s.bmp", curName);\r
+               userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );    \r
+               strcpy(oldUserName, curName);\r
+         }\r
+    }\r
+}\r
+\r
 BOOL\r
 InitApplication(HINSTANCE hInstance)\r
 {\r
@@ -585,16 +715,14 @@ InitApplication(HINSTANCE hInstance)
 int screenHeight, screenWidth;\r
 \r
 void\r
-EnsureOnScreen(int *x, int *y)\r
+EnsureOnScreen(int *x, int *y, int minX, int minY)\r
 {\r
 //  int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);\r
   /* Be sure window at (x,y) is not off screen (or even mostly off screen) */\r
   if (*x > screenWidth - 32) *x = 0;\r
   if (*y > screenHeight - 32) *y = 0;\r
-  if (*x < 0) *x = 0;\r
-  if (*y < 0) *y = 0;\r
-//  if (*x < 10) *x = 10;\r
-//  if (*y < gap) *y = gap;\r
+  if (*x < minX) *x = minX;\r
+  if (*y < minY) *y = minY;\r
 }\r
 \r
 BOOL\r
@@ -613,6 +741,7 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
     GetCurrentDirectory(MSG_SIZ, installDir);\r
   }\r
   gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise\r
+  screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData\r
   InitAppData(lpCmdLine);      /* Get run-time parameters */\r
   if (appData.debugMode) {\r
     debugFP = fopen(appData.nameOfDebugFile, "w");\r
@@ -658,13 +787,19 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
           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
+       sprintf(buf, "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
-       char buf[MSG_SIZ];\r
        sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);\r
        second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );  \r
       }\r
   }\r
 \r
+  SetUserLogo();\r
+\r
   iconWhite = LoadIcon(hInstance, "icon_white");\r
   iconBlack = LoadIcon(hInstance, "icon_black");\r
   iconCurrent = iconWhite;\r
@@ -674,11 +809,11 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
   for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {\r
     /* Compute window size for each board size, and use the largest\r
        size that fits on this screen as the default. */\r
-    InitDrawingSizes((BoardSize)ibs, 0);\r
+    InitDrawingSizes((BoardSize)(ibs+1000), 0);\r
     if (boardSize == (BoardSize)-1 &&\r
-        winHeight <= screenHeight\r
+        winH <= screenHeight\r
            - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10\r
-        && winWidth <= screenWidth) {\r
+        && winW <= screenWidth) {\r
       boardSize = (BoardSize)ibs;\r
     }\r
   }\r
@@ -726,7 +861,7 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
   InitBackEnd2();\r
 \r
   /* Make the window visible; update its client area; and return "success" */\r
-  EnsureOnScreen(&boardX, &boardY);\r
+  EnsureOnScreen(&boardX, &boardY, minX, minY);\r
   wp.length = sizeof(WINDOWPLACEMENT);\r
   wp.flags = 0;\r
   wp.showCmd = nCmdShow;\r
@@ -737,15 +872,9 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
   wp.rcNormalPosition.bottom = boardY + winHeight;\r
   SetWindowPlacement(hwndMain, &wp);\r
 \r
-  SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,\r
+  if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,\r
                0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);\r
 \r
-#if 0\r
-  /* [AS] Disable the FRC stuff if not playing the proper variant */\r
-  if( gameInfo.variant != VariantFischeRandom ) {\r
-      EnableMenuItem( GetMenu(hwndMain), IDM_NewGameFRC, MF_GRAYED );\r
-  }\r
-#endif\r
   if (hwndConsole) {\r
 #if AOT_CONSOLE\r
     SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,\r
@@ -753,7 +882,8 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
 #endif\r
     ShowWindow(hwndConsole, nCmdShow);\r
   }\r
-  UpdateWindow(hwnd);\r
+  if(!appData.noGUI)   UpdateWindow(hwnd);  else ShowWindow(hwnd, SW_MINIMIZE);\r
+  if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file\r
 \r
   return TRUE;\r
 \r
@@ -763,7 +893,8 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
 typedef enum {\r
   ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone, \r
   ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,\r
-  ArgSettingsFilename\r
+  ArgSettingsFilename,\r
+  ArgX, ArgY, ArgZ // [HGM] placement: for window-placement options stored relative to main window\r
 } ArgType;\r
 \r
 typedef struct {\r
@@ -794,6 +925,7 @@ ArgDescriptor argDescriptors[] = {
   { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },\r
   { "", ArgNone, NULL },\r
   /* keyword arguments */\r
+  JAWS_ARGS\r
   { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },\r
   { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },\r
   { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },\r
@@ -973,10 +1105,6 @@ ArgDescriptor argDescriptors[] = {
   { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },\r
   { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },\r
   { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },\r
-#if 0\r
-  { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },\r
-  { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },\r
-#endif\r
   { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },\r
   { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },\r
   { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },\r
@@ -1099,28 +1227,6 @@ ArgDescriptor argDescriptors[] = {
   { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },\r
   { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },\r
   { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },\r
-  { "x", ArgInt, (LPVOID) &boardX, TRUE },\r
-  { "y", ArgInt, (LPVOID) &boardY, TRUE },\r
-  { "icsX", ArgInt, (LPVOID) &consoleX, TRUE },\r
-  { "icsY", ArgInt, (LPVOID) &consoleY, TRUE },\r
-  { "icsW", ArgInt, (LPVOID) &consoleW, TRUE },\r
-  { "icsH", ArgInt, (LPVOID) &consoleH, TRUE },\r
-  { "analysisX", ArgInt, (LPVOID) &analysisX, TRUE },\r
-  { "analysisY", ArgInt, (LPVOID) &analysisY, TRUE },\r
-  { "analysisW", ArgInt, (LPVOID) &analysisW, TRUE },\r
-  { "analysisH", ArgInt, (LPVOID) &analysisH, TRUE },\r
-  { "commentX", ArgInt, (LPVOID) &commentX, TRUE },\r
-  { "commentY", ArgInt, (LPVOID) &commentY, TRUE },\r
-  { "commentW", ArgInt, (LPVOID) &commentW, TRUE },\r
-  { "commentH", ArgInt, (LPVOID) &commentH, TRUE },\r
-  { "tagsX", ArgInt, (LPVOID) &editTagsX, TRUE },\r
-  { "tagsY", ArgInt, (LPVOID) &editTagsY, TRUE },\r
-  { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },\r
-  { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },\r
-  { "gameListX", ArgInt, (LPVOID) &gameListX, TRUE },\r
-  { "gameListY", ArgInt, (LPVOID) &gameListY, TRUE },\r
-  { "gameListW", ArgInt, (LPVOID) &gameListW, TRUE },\r
-  { "gameListH", ArgInt, (LPVOID) &gameListH, TRUE },\r
   { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },\r
   { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },\r
   { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },\r
@@ -1195,25 +1301,6 @@ ArgDescriptor argDescriptors[] = {
   { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },\r
   { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },\r
 \r
-  /* [AS] Layout stuff */\r
-  { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },\r
-  { "moveHistoryX", ArgInt, (LPVOID) &wpMoveHistory.x, TRUE },\r
-  { "moveHistoryY", ArgInt, (LPVOID) &wpMoveHistory.y, TRUE },\r
-  { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },\r
-  { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },\r
-\r
-  { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },\r
-  { "evalGraphX", ArgInt, (LPVOID) &wpEvalGraph.x, TRUE },\r
-  { "evalGraphY", ArgInt, (LPVOID) &wpEvalGraph.y, TRUE },\r
-  { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },\r
-  { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },\r
-\r
-  { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },\r
-  { "engineOutputX", ArgInt, (LPVOID) &wpEngineOutput.x, TRUE },\r
-  { "engineOutputY", ArgInt, (LPVOID) &wpEngineOutput.y, TRUE },\r
-  { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },\r
-  { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },\r
-\r
   /* [HGM] board-size, adjudication and misc. options */\r
   { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },\r
   { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },\r
@@ -1246,6 +1333,9 @@ ArgDescriptor argDescriptors[] = {
   { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE },\r
   { "firstNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride1, FALSE },\r
   { "secondNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride2, FALSE },\r
+  { "keepAlive", ArgInt, (LPVOID) &appData.keepAlive, FALSE },\r
+  { "icstype", ArgInt, (LPVOID) &ics_type, FALSE },\r
+  { "forceIllegalMoves", ArgTrue, (LPVOID) &appData.forceIllegal, FALSE },\r
 \r
 #ifdef ZIPPY\r
   { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },\r
@@ -1302,6 +1392,56 @@ ArgDescriptor argDescriptors[] = {
   { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },\r
   { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },\r
   { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },\r
+  { "keepLineBreaksICS", ArgBoolean, (LPVOID) &appData.noJoin, TRUE },\r
+  { "wrapContinuationSequence", ArgString, (LPVOID) &appData.wrapContSeq, FALSE },\r
+  { "useInternalWrap", ArgTrue, (LPVOID) &appData.useInternalWrap, FALSE }, /* noJoin usurps this if set */\r
+  \r
+  // [HGM] placement: put all window layouts last in ini file, but man X,Y before all others\r
+  { "minX", ArgZ, (LPVOID) &minX, FALSE }, // [HGM] placement: to make suer auxialary windows can be placed\r
+  { "minY", ArgZ, (LPVOID) &minY, FALSE },\r
+  { "winWidth",  ArgInt, (LPVOID) &winWidth,  TRUE }, // [HGM] placement: dummies to remember right & bottom\r
+  { "winHeight", ArgInt, (LPVOID) &winHeight, TRUE }, //       for attaching auxiliary windows to them\r
+  { "x", ArgInt, (LPVOID) &boardX, TRUE },\r
+  { "y", ArgInt, (LPVOID) &boardY, TRUE },\r
+  { "icsX", ArgX,   (LPVOID) &wpConsole.x, TRUE },\r
+  { "icsY", ArgY,   (LPVOID) &wpConsole.y, TRUE },\r
+  { "icsW", ArgInt, (LPVOID) &wpConsole.width, TRUE },\r
+  { "icsH", ArgInt, (LPVOID) &wpConsole.height, TRUE },\r
+  { "analysisX", ArgX,   (LPVOID) &analysisX, FALSE }, // [HGM] placement: analysis window no longer exists\r
+  { "analysisY", ArgY,   (LPVOID) &analysisY, FALSE }, //       provided for compatibility with old ini files\r
+  { "analysisW", ArgInt, (LPVOID) &analysisW, FALSE },\r
+  { "analysisH", ArgInt, (LPVOID) &analysisH, FALSE },\r
+  { "commentX", ArgX,   (LPVOID) &commentX, TRUE },\r
+  { "commentY", ArgY,   (LPVOID) &commentY, TRUE },\r
+  { "commentW", ArgInt, (LPVOID) &commentW, TRUE },\r
+  { "commentH", ArgInt, (LPVOID) &commentH, TRUE },\r
+  { "tagsX", ArgX,   (LPVOID) &editTagsX, TRUE },\r
+  { "tagsY", ArgY,   (LPVOID) &editTagsY, TRUE },\r
+  { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },\r
+  { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },\r
+  { "gameListX", ArgX,   (LPVOID) &wpGameList.x, TRUE },\r
+  { "gameListY", ArgY,   (LPVOID) &wpGameList.y, TRUE },\r
+  { "gameListW", ArgInt, (LPVOID) &wpGameList.width, TRUE },\r
+  { "gameListH", ArgInt, (LPVOID) &wpGameList.height, TRUE },\r
+  /* [AS] Layout stuff */\r
+  { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },\r
+  { "moveHistoryX", ArgX,   (LPVOID) &wpMoveHistory.x, TRUE },\r
+  { "moveHistoryY", ArgY,   (LPVOID) &wpMoveHistory.y, TRUE },\r
+  { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },\r
+  { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },\r
+\r
+  { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },\r
+  { "evalGraphX", ArgX,   (LPVOID) &wpEvalGraph.x, TRUE },\r
+  { "evalGraphY", ArgY,   (LPVOID) &wpEvalGraph.y, TRUE },\r
+  { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },\r
+  { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },\r
+\r
+  { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },\r
+  { "engineOutputX", ArgX,   (LPVOID) &wpEngineOutput.x, TRUE },\r
+  { "engineOutputY", ArgY,   (LPVOID) &wpEngineOutput.y, TRUE },\r
+  { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },\r
+  { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },\r
+\r
   { NULL, ArgNone, NULL, FALSE }\r
 };\r
 \r
@@ -1632,6 +1772,19 @@ ParseArgs(GetFunc get, void *cl)
       *(int *) ad->argLoc = atoi(argValue);\r
       break;\r
 \r
+    case ArgX:\r
+      *(int *) ad->argLoc = atoi(argValue) + boardX; // [HGM] placement: translate stored relative to absolute \r
+      break;\r
+\r
+    case ArgY:\r
+      *(int *) ad->argLoc = atoi(argValue) + boardY; // (this is really kludgey, it should be done where used...)\r
+      break;\r
+\r
+    case ArgZ:\r
+      *(int *) ad->argLoc = atoi(argValue);\r
+      EnsureOnScreen(&boardX, &boardY, minX, minY); \r
+      break;\r
+\r
     case ArgFloat:\r
       *(float *) ad->argLoc = (float) atof(argValue);\r
       break;\r
@@ -1895,10 +2048,6 @@ InitAppData(LPSTR lpCmdLine)
   saveSettingsOnExit = TRUE;\r
   boardX = CW_USEDEFAULT;\r
   boardY = CW_USEDEFAULT;\r
-  consoleX = CW_USEDEFAULT; \r
-  consoleY = CW_USEDEFAULT; \r
-  consoleW = CW_USEDEFAULT;\r
-  consoleH = CW_USEDEFAULT;\r
   analysisX = CW_USEDEFAULT; \r
   analysisY = CW_USEDEFAULT; \r
   analysisW = CW_USEDEFAULT;\r
@@ -1911,10 +2060,6 @@ InitAppData(LPSTR lpCmdLine)
   editTagsY = CW_USEDEFAULT; \r
   editTagsW = CW_USEDEFAULT;\r
   editTagsH = CW_USEDEFAULT;\r
-  gameListX = CW_USEDEFAULT; \r
-  gameListY = CW_USEDEFAULT; \r
-  gameListW = CW_USEDEFAULT;\r
-  gameListH = CW_USEDEFAULT;\r
   icsTextMenuString = ICS_TEXT_MENU_DEFAULT;\r
   icsNames = ICS_NAMES;\r
   firstChessProgramNames = FCP_NAMES;\r
@@ -1972,9 +2117,11 @@ InitAppData(LPSTR lpCmdLine)
   appData.firstOptions = "";\r
   appData.secondOptions = "";\r
 \r
+  InitWindowPlacement( &wpGameList );\r
   InitWindowPlacement( &wpMoveHistory );\r
   InitWindowPlacement( &wpEvalGraph );\r
   InitWindowPlacement( &wpEngineOutput );\r
+  InitWindowPlacement( &wpConsole );\r
 \r
   /* [HGM] User-selectable board size, adjudication control, miscellaneous */\r
   appData.NrFiles      = -1;\r
@@ -2173,7 +2320,7 @@ SaveSettings(char* name)
     return;\r
   }\r
   fprintf(f, ";\n");\r
-  fprintf(f, "; %s %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);\r
+  fprintf(f, "; %s Save Settings file\n", PACKAGE_STRING);\r
   fprintf(f, ";\n");\r
   fprintf(f, "; You can edit the values of options that are already set in this file,\n");\r
   fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");\r
@@ -2187,10 +2334,10 @@ SaveSettings(char* name)
 \r
   if (hwndConsole) {\r
     GetWindowPlacement(hwndConsole, &wp);\r
-    consoleX = wp.rcNormalPosition.left;\r
-    consoleY = wp.rcNormalPosition.top;\r
-    consoleW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
-    consoleH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
+    wpConsole.x = wp.rcNormalPosition.left;\r
+    wpConsole.y = wp.rcNormalPosition.top;\r
+    wpConsole.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
+    wpConsole.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
   }\r
 \r
   if (analysisDialog) {\r
@@ -2219,10 +2366,10 @@ SaveSettings(char* name)
 \r
   if (gameListDialog) {\r
     GetWindowPlacement(gameListDialog, &wp);\r
-    gameListX = wp.rcNormalPosition.left;\r
-    gameListY = wp.rcNormalPosition.top;\r
-    gameListW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
-    gameListH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
+    wpGameList.x = wp.rcNormalPosition.left;\r
+    wpGameList.y = wp.rcNormalPosition.top;\r
+    wpGameList.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
+    wpGameList.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
   }\r
 \r
   /* [AS] Move history */\r
@@ -2288,8 +2435,15 @@ SaveSettings(char* name)
       }\r
       break;\r
     case ArgInt:\r
+    case ArgZ:\r
       fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);\r
       break;\r
+    case ArgX:\r
+      fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardX); // [HGM] placement: stor relative value\r
+      break;\r
+    case ArgY:\r
+      fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardY);\r
+      break;\r
     case ArgFloat:\r
       fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);\r
       break;\r
@@ -2885,57 +3039,10 @@ void CreatePiecesFromFont()
 \r
             /* Create bitmaps */\r
             hfont_old = SelectObject( hdc, hPieceFont );\r
-#if 0\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );\r
-\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WSG );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WV );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WAB );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WD );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WL );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WS );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BSG );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BV );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BAB );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BD );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BL );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BS );\r
-#else\r
            for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */\r
                if(PieceToChar((ChessSquare)i) != '.')     /* skip unused pieces         */\r
                    CreatePieceMaskFromFont( hdc_window, hdc, i );\r
-#endif\r
+\r
             SelectObject( hdc, hfont_old );\r
 \r
             fontBitmapSquareSize = squareSize;\r
@@ -3078,7 +3185,7 @@ InitDrawingSizes(BoardSize boardSize, int flags)
   char buf[MSG_SIZ];\r
   char *str;\r
   HMENU hmenu = GetMenu(hwndMain);\r
-  RECT crect, wrect;\r
+  RECT crect, wrect, oldRect;\r
   int offby;\r
   LOGBRUSH logbrush;\r
 \r
@@ -3088,6 +3195,11 @@ InitDrawingSizes(BoardSize boardSize, int flags)
   /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */\r
   if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;\r
 \r
+  oldRect.left = boardX; //[HGM] placement: remember previous window params\r
+  oldRect.top = boardY;\r
+  oldRect.right = boardX + winWidth;\r
+  oldRect.bottom = boardY + winHeight;\r
+\r
   tinyLayout = sizeInfo[boardSize].tinyLayout;\r
   smallLayout = sizeInfo[boardSize].smallLayout;\r
   squareSize = sizeInfo[boardSize].squareSize;\r
@@ -3188,13 +3300,25 @@ InitDrawingSizes(BoardSize boardSize, int flags)
 \r
   sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;\r
   sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;\r
-  if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only\r
-  winWidth = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;\r
-  winHeight = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +\r
+  oldBoardSize = boardSize;\r
+  oldTinyLayout = tinyLayout;\r
+  winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;\r
+  winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +\r
     GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;\r
+  if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only\r
+  winWidth = winW;  // [HGM] placement: set through temporary which can used by initial sizing choice\r
+  winHeight = winH; //       without disturbing window attachments\r
   GetWindowRect(hwndMain, &wrect);\r
   SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,\r
               SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);\r
+\r
+  // [HGM] placement: let attached windows follow size change.\r
+  ReattachAfterSize( &oldRect, winWidth, winHeight, moveHistoryDialog, &wpMoveHistory );\r
+  ReattachAfterSize( &oldRect, winWidth, winHeight, evalGraphDialog, &wpEvalGraph );\r
+  ReattachAfterSize( &oldRect, winWidth, winHeight, engineOutputDialog, &wpEngineOutput );\r
+  ReattachAfterSize( &oldRect, winWidth, winHeight, gameListDialog, &wpGameList );\r
+  ReattachAfterSize( &oldRect, winWidth, winHeight, hwndConsole, &wpConsole );\r
+\r
   /* compensate if menu bar wrapped */\r
   GetClientRect(hwndMain, &crect);\r
   offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;\r
@@ -3304,8 +3428,6 @@ InitDrawingSizes(BoardSize boardSize, int flags)
 \r
 \r
 /*  if (boardSize == oldBoardSize) return; [HGM] variant might have changed */\r
-  oldBoardSize = boardSize;\r
-  oldTinyLayout = tinyLayout;\r
 \r
   /* Load piece bitmaps for this board size */\r
   for (i=0; i<=2; i++) {\r
@@ -3716,35 +3838,13 @@ DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y,
         StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);\r
       else\r
         BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);\r
-#if 0\r
-      /* Use black piece color for outline of white pieces */\r
-      /* Not sure this looks really good (though xboard does it).\r
-        Maybe better to have another selectable color, default black */\r
-      SelectObject(hdc, blackPieceBrush); /* could have own brush */\r
-      SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));\r
-      BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);\r
-#else\r
       /* Use black for outline of white pieces */\r
       SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));\r
       if(appData.upsideDown && color==flipView)\r
         StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);\r
       else\r
         BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);\r
-#endif\r
     } else {\r
-#if 0\r
-      /* Use white piece color for details of black pieces */\r
-      /* Requires filled-in solid bitmaps (BLACK_PIECE class); the\r
-        WHITE_PIECE ones aren't always the right shape. */\r
-      /* Not sure this looks really good (though xboard does it).\r
-        Maybe better to have another selectable color, default medium gray? */\r
-      oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));\r
-      oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */\r
-      BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);\r
-      SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));\r
-      SelectObject(hdc, blackPieceBrush);\r
-      BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);\r
-#else\r
       /* Use square color for details of black pieces */\r
       oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));\r
       oldBrush = SelectObject(hdc, blackPieceBrush);\r
@@ -3752,7 +3852,6 @@ DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y,
         StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);\r
       else\r
         BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);\r
-#endif\r
     }\r
     SelectObject(hdc, oldBrush);\r
     SelectObject(tmphdc, oldBitmap);\r
@@ -4234,7 +4333,7 @@ void fputDW(FILE *f, int x)
 #define MAX_CLIPS 200   /* more than enough */\r
 \r
 VOID\r
-DrawLogoOnDC(HDC hdc, RECT logoRect, ChessProgramState *cps)\r
+DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)\r
 {\r
 //  HBITMAP bufferBitmap;\r
   BITMAP bi;\r
@@ -4243,13 +4342,13 @@ DrawLogoOnDC(HDC hdc, RECT logoRect, ChessProgramState *cps)
   HBITMAP hbm;\r
   int w = 100, h = 50;\r
 \r
-  if(cps->programLogo == NULL) return;\r
+  if(logo == NULL) return;\r
 //  GetClientRect(hwndMain, &Rect);\r
 //  bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,\r
 //                                     Rect.bottom-Rect.top+1);\r
   tmphdc = CreateCompatibleDC(hdc);\r
-  hbm = SelectObject(tmphdc, (HBITMAP) cps->programLogo);\r
-  if( GetObject( cps->programLogo, sizeof(bi), &bi ) > 0 ) {\r
+  hbm = SelectObject(tmphdc, logo);\r
+  if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {\r
             w = bi.bmWidth;\r
             h = bi.bmHeight;\r
   }\r
@@ -4289,17 +4388,6 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
       fullrepaint = TRUE;\r
   }\r
 \r
-#if 0\r
-  if( fullrepaint ) {\r
-      static int repaint_count = 0;\r
-      char buf[128];\r
-\r
-      repaint_count++;\r
-      sprintf( buf, "FULL repaint: %d\n", repaint_count );\r
-      OutputDebugString( buf );\r
-  }\r
-#endif\r
-\r
   if (board == NULL) {\r
     if (!lastReqValid) {\r
       return;\r
@@ -4329,35 +4417,6 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
     releaseDC = FALSE;\r
   }\r
 \r
-#if 0\r
-  fprintf(debugFP, "*******************************\n"\r
-                   "repaint = %s\n"\r
-                   "dragInfo.from (%d,%d)\n"\r
-                   "dragInfo.start (%d,%d)\n"\r
-                   "dragInfo.pos (%d,%d)\n"\r
-                   "dragInfo.lastpos (%d,%d)\n", \r
-                    repaint ? "TRUE" : "FALSE",\r
-                    dragInfo.from.x, dragInfo.from.y, \r
-                    dragInfo.start.x, dragInfo.start.y,\r
-                    dragInfo.pos.x, dragInfo.pos.y,\r
-                    dragInfo.lastpos.x, dragInfo.lastpos.y);\r
-  fprintf(debugFP, "prev:  ");\r
-  for (row = 0; row < BOARD_HEIGHT; row++) {\r
-    for (column = 0; column < BOARD_WIDTH; column++) {\r
-      fprintf(debugFP, "%d ", lastDrawn[row][column]);\r
-    }\r
-  }\r
-  fprintf(debugFP, "\n");\r
-  fprintf(debugFP, "board: ");\r
-  for (row = 0; row < BOARD_HEIGHT; row++) {\r
-    for (column = 0; column < BOARD_WIDTH; column++) {\r
-      fprintf(debugFP, "%d ", board[row][column]);\r
-    }\r
-  }\r
-  fprintf(debugFP, "\n");\r
-  fflush(debugFP);\r
-#endif\r
-\r
   /* Create some work-DCs */\r
   hdcmem = CreateCompatibleDC(hdc);\r
   tmphdc = CreateCompatibleDC(hdc);\r
@@ -4532,8 +4591,39 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
     DrawBoardOnDC(hdcmem, board, tmphdc);\r
   }\r
   if(logoHeight) {\r
-       DrawLogoOnDC(hdc, leftLogoRect, flipClock ? &second : &first);\r
-       DrawLogoOnDC(hdc, rightLogoRect, flipClock ? &first : &second);\r
+       HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;\r
+       if(appData.autoLogo) {\r
+         \r
+         switch(gameMode) { // pick logos based on game mode\r
+           case IcsObserving:\r
+               whiteLogo = second.programLogo; // ICS logo\r
+               blackLogo = second.programLogo;\r
+           default:\r
+               break;\r
+           case IcsPlayingWhite:\r
+               if(!appData.zippyPlay) whiteLogo = userLogo;\r
+               blackLogo = second.programLogo; // ICS logo\r
+               break;\r
+           case IcsPlayingBlack:\r
+               whiteLogo = second.programLogo; // ICS logo\r
+               blackLogo = appData.zippyPlay ? first.programLogo : userLogo;\r
+               break;\r
+           case TwoMachinesPlay:\r
+               if(first.twoMachinesColor[0] == 'b') {\r
+                   whiteLogo = second.programLogo;\r
+                   blackLogo = first.programLogo;\r
+               }\r
+               break;\r
+           case MachinePlaysWhite:\r
+               blackLogo = userLogo;\r
+               break;\r
+           case MachinePlaysBlack:\r
+               whiteLogo = userLogo;\r
+               blackLogo = first.programLogo;\r
+         }\r
+       }\r
+       DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);\r
+       DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);\r
   }\r
 \r
   if( appData.highlightMoveWithArrow ) {\r
@@ -4616,7 +4706,6 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
        GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);\r
 //     fprintf(diagFile, "%8x\n", (int) pData);\r
 \r
-#if 1\r
        wb = b.bmWidthBytes;\r
        // count colors\r
        for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {\r
@@ -4664,7 +4753,6 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
        // write bitmap data\r
        for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++) \r
                fputc(pData[i], diagFile);\r
-#endif\r
      }\r
   }\r
 \r
@@ -4753,8 +4841,8 @@ PaintProc(HWND hwnd)
  * The offset boardRect.left or boardRect.top must already have been\r
  *   subtracted from x.\r
  */\r
-int\r
-EventToSquare(int x)\r
+int EventToSquare(x, limit)\r
+     int x;\r
 {\r
   if (x <= 0)\r
     return -2;\r
@@ -4764,7 +4852,7 @@ EventToSquare(int x)
   if ((x % (squareSize + lineGap)) >= squareSize)\r
     return -1;\r
   x /= (squareSize + lineGap);\r
-  if (x >= BOARD_SIZE)\r
+    if (x >= limit)\r
     return -2;\r
   return x;\r
 }\r
@@ -4806,7 +4894,23 @@ SetupDropMenu(HMENU hmenu)
   }\r
 }\r
 \r
-static int fromX = -1, fromY = -1, toX, toY;\r
+void DragPieceBegin(int x, int y)\r
+{\r
+      dragInfo.lastpos.x = boardRect.left + x;\r
+      dragInfo.lastpos.y = boardRect.top + y;\r
+      dragInfo.from.x = fromX;\r
+      dragInfo.from.y = fromY;\r
+      dragInfo.start = dragInfo.from;\r
+      SetCapture(hwndMain);\r
+}\r
+\r
+void DragPieceEnd(int x, int y)\r
+{\r
+    ReleaseCapture();\r
+    dragInfo.start.x = dragInfo.start.y = -1;\r
+    dragInfo.from = dragInfo.start;\r
+    dragInfo.pos = dragInfo.lastpos = dragInfo.start;\r
+}\r
 \r
 /* Event handler for mouse messages */\r
 VOID\r
@@ -4816,11 +4920,7 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
   POINT pt;\r
   static int recursive = 0;\r
   HMENU hmenu;\r
-//  BOOLEAN needsRedraw = FALSE;\r
-  BOOLEAN saveAnimate;\r
   BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */\r
-  static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;\r
-  ChessMove moveType;\r
 \r
   if (recursive) {\r
     if (message == WM_MBUTTONUP) {\r
@@ -4836,8 +4936,8 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
   \r
   pt.x = LOWORD(lParam);\r
   pt.y = HIWORD(lParam);\r
-  x = EventToSquare(pt.x - boardRect.left);\r
-  y = EventToSquare(pt.y - boardRect.top);\r
+  x = EventToSquare(pt.x - boardRect.left, BOARD_WIDTH);\r
+  y = EventToSquare(pt.y - boardRect.top, BOARD_HEIGHT);\r
   if (!flipView && y >= 0) {\r
     y = BOARD_HEIGHT - 1 - y;\r
   }\r
@@ -4847,29 +4947,6 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 \r
   switch (message) {\r
   case WM_LBUTTONDOWN:\r
-    if(promotionChoice) { // we are waiting for a click to indicate promotion piece\r
-       promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel\r
-       if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);\r
-       if(gameInfo.holdingsWidth && \r
-               (WhiteOnMove(currentMove) \r
-                       ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0\r
-                       : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {\r
-           // click in right holdings, for determining promotion piece\r
-           ChessSquare p = boards[currentMove][y][x];\r
-           if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);\r
-           if(p != EmptySquare) {\r
-               FinishMove(WhitePromotionQueen, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));\r
-               fromX = fromY = -1;\r
-               break;\r
-           }\r
-       }\r
-       DrawPosition(FALSE, boards[currentMove]);\r
-       break;\r
-    }\r
-    ErrorPopDown();\r
-    sameAgain = FALSE;\r
-    if (y == -2) {\r
-      /* Downclick vertically off board; check if on clock */\r
       if (PtInRect((LPRECT) &whiteRect, pt)) {\r
         if (gameMode == EditPosition) {\r
          SetWhiteToPlayEvent();\r
@@ -4889,194 +4966,20 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
           AdjustClock(!flipClock, -1);\r
        }\r
       }\r
-      if (!appData.highlightLastMove) {\r
-        ClearHighlights();\r
-       DrawPosition((int) (forceFullRepaint || FALSE), NULL);\r
-      }\r
-      fromX = fromY = -1;\r
       dragInfo.start.x = dragInfo.start.y = -1;\r
       dragInfo.from = dragInfo.start;\r
-      break;\r
-    } else if (x < 0 || y < 0\r
-      /* [HGM] block clicks between board and holdings */\r
-              || x == BOARD_LEFT-1 || x == BOARD_RGHT\r
-              || (x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize)\r
-              || (x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize)\r
-       /* EditPosition, empty square, or different color piece;\r
-          click-click move is possible */\r
-                               ) {\r
-      break;\r
-    } else if (fromX == x && fromY == y) {\r
-      /* Downclick on same square again */\r
-      ClearHighlights();\r
-      DrawPosition(forceFullRepaint || FALSE, NULL);\r
-      sameAgain = TRUE;  \r
-    } else if (fromX != -1 &&\r
-               x != BOARD_LEFT-2 && x != BOARD_RGHT+1 \r
-                                                                        ) {\r
-      /* Downclick on different square. */\r
-      /* [HGM] if on holdings file, should count as new first click ! */\r
-      { /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */\r
-       toX = x;\r
-       toY = y;\r
-        /* [HGM] <popupFix> UserMoveEvent requires two calls now,\r
-           to make sure move is legal before showing promotion popup */\r
-        moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);\r
-       if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */\r
+    if(fromX == -1 && frozen) { // not sure where this is for\r
                fromX = fromY = -1; \r
-               ClearHighlights();\r
-               DrawPosition(FALSE, boards[currentMove]);\r
-               break; \r
-       } else \r
-        if(moveType != ImpossibleMove) {\r
-          /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */\r
-          if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||\r
-            ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&\r
-              appData.alwaysPromoteToQueen)) {\r
-                  FinishMove(moveType, fromX, fromY, toX, toY, 'q');\r
-                  if (!appData.highlightLastMove) {\r
-                      ClearHighlights();\r
-                      DrawPosition(forceFullRepaint || FALSE, NULL);\r
-                  }\r
-          } else\r
-          if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {\r
-                  SetHighlights(fromX, fromY, toX, toY);\r
-                  DrawPosition(forceFullRepaint || FALSE, NULL);\r
-                  /* [HGM] <popupFix> Popup calls FinishMove now.\r
-                     If promotion to Q is legal, all are legal! */\r
-                 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)\r
-                 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];\r
-                   // kludge to temporarily execute move on display, wthout promotng yet\r
-                   promotionChoice = TRUE;\r
-                   boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank\r
-                   boards[currentMove][toY][toX] = p;\r
-                   DrawPosition(FALSE, boards[currentMove]);\r
-                   boards[currentMove][fromY][fromX] = p; // take back, but display stays\r
-                   boards[currentMove][toY][toX] = q;\r
-                 } else\r
-                  PromotionPopup(hwnd);\r
-          } else {       /* not a promotion */\r
-             if (appData.animate || appData.highlightLastMove) {\r
-                 SetHighlights(fromX, fromY, toX, toY);\r
-             } else {\r
-                 ClearHighlights();\r
-             }\r
-             FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);\r
-            fromX = fromY = -1;\r
-             if (appData.animate && !appData.highlightLastMove) {\r
-                  ClearHighlights();\r
-                  DrawPosition(forceFullRepaint || FALSE, NULL);\r
-             }\r
-          }\r
-          break;\r
-        }\r
-        if (gotPremove) {\r
-            /* [HGM] it seemed that braces were missing here */\r
-            SetPremoveHighlights(fromX, fromY, toX, toY);\r
-            fromX = fromY = -1;\r
-            break;\r
-        }\r
-      }\r
-      ClearHighlights();\r
-      DrawPosition(forceFullRepaint || FALSE, NULL);\r
-    }\r
-    /* First downclick, or restart on a square with same color piece */\r
-    if (!frozen && OKToStartUserMove(x, y)) {\r
-      fromX = x;\r
-      fromY = y;\r
-      dragInfo.lastpos = pt;\r
-      dragInfo.from.x = fromX;\r
-      dragInfo.from.y = fromY;\r
-      dragInfo.start = dragInfo.from;\r
-      SetCapture(hwndMain);\r
-    } else {\r
-      fromX = fromY = -1;\r
-      dragInfo.start.x = dragInfo.start.y = -1;\r
-      dragInfo.from = dragInfo.start;\r
       DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */\r
+      break;\r
     }\r
+      LeftClick(Press, pt.x - boardRect.left, pt.y - boardRect.top);\r
+      DrawPosition(TRUE, NULL);\r
     break;\r
 \r
   case WM_LBUTTONUP:\r
-    ReleaseCapture();\r
-    if (fromX == -1) break;\r
-    if (x == fromX && y == fromY) {\r
-      dragInfo.from.x = dragInfo.from.y = -1;\r
-      /* Upclick on same square */\r
-      if (sameAgain) {\r
-       /* Clicked same square twice: abort click-click move */\r
-       fromX = fromY = -1;\r
-       gotPremove = 0;\r
-       ClearPremoveHighlights();\r
-      } else {\r
-       /* First square clicked: start click-click move */\r
-       SetHighlights(fromX, fromY, -1, -1);\r
-      }\r
-      DrawPosition(forceFullRepaint || FALSE, NULL);\r
-    } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {\r
-      /* Errant click; ignore */\r
-      break;\r
-    } else {\r
-      /* Finish drag move. */\r
-    if (appData.debugMode) {\r
-        fprintf(debugFP, "release\n");\r
-    }\r
-      dragInfo.from.x = dragInfo.from.y = -1;\r
-      toX = x;\r
-      toY = y;\r
-      saveAnimate = appData.animate; /* sorry, Hawk :) */\r
-      appData.animate = appData.animate && !appData.animateDragging;\r
-      moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);\r
-      if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */\r
-               fromX = fromY = -1; \r
-               ClearHighlights();\r
-               DrawPosition(FALSE, boards[currentMove]);\r
-               break; \r
-      } else \r
-      if(moveType != ImpossibleMove) {\r
-          /* [HGM] use move type to determine if move is promotion.\r
-             Knight is Shogi kludge for mandatory promotion, Queen means choice */\r
-          if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||\r
-            ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&\r
-              appData.alwaysPromoteToQueen)) \r
-               FinishMove(moveType, fromX, fromY, toX, toY, 'q');\r
-          else \r
-          if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {\r
-               DrawPosition(forceFullRepaint || FALSE, NULL);\r
-                 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)\r
-                 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];\r
-                   // kludge to temporarily execute move on display, wthout promotng yet\r
-                   promotionChoice = TRUE;\r
-                   boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank\r
-                   boards[currentMove][toY][toX] = p;\r
-                   DrawPosition(FALSE, boards[currentMove]);\r
-                   boards[currentMove][fromY][fromX] = p; // take back, but display stays\r
-                   boards[currentMove][toY][toX] = q;\r
-                   break;\r
-                 } else\r
-               PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */\r
-          } else {\r
-           if(saveAnimate /* ^$!%@#$!$ */  && gameInfo.variant == VariantAtomic \r
-                         && (boards[currentMove][toY][toX] != EmptySquare || \r
-                                       moveType == WhiteCapturesEnPassant || \r
-                                       moveType == BlackCapturesEnPassant   ) )\r
-               AnimateAtomicCapture(fromX, fromY, toX, toY, 20);\r
-           FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);\r
-         }\r
-      }\r
-      if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);\r
-      appData.animate = saveAnimate;\r
-      fromX = fromY = -1;\r
-      if (appData.highlightDragging && !appData.highlightLastMove) {\r
-       ClearHighlights();\r
-      }\r
-      if (appData.animate || appData.animateDragging ||\r
-         appData.highlightDragging || gotPremove) {\r
-       DrawPosition(forceFullRepaint || FALSE, NULL);\r
-      }\r
-    }\r
-    dragInfo.start.x = dragInfo.start.y = -1; \r
-    dragInfo.pos = dragInfo.lastpos = dragInfo.start;\r
+      LeftClick(Release, pt.x - boardRect.left, pt.y - boardRect.top);\r
+      DrawPosition(TRUE, NULL);\r
     break;\r
 \r
   case WM_MOUSEMOVE:\r
@@ -5086,7 +4989,6 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     {\r
       BOOL full_repaint = FALSE;\r
 \r
-      sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */\r
       if (appData.animateDragging) {\r
        dragInfo.pos = pt;\r
       }\r
@@ -5153,16 +5055,6 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
        else\r
          MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);\r
       } else { /* message == WM_RBUTTONDOWN */\r
-#if 0\r
-       if (buttonCount == 3) {\r
-         if (wParam & MK_SHIFT) \r
-           MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);\r
-         else\r
-           MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);\r
-       } else {\r
-         MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);\r
-       }\r
-#else\r
        /* Just have one menu, on the right button.  Windows users don't\r
           think to try the middle one, and sometimes other software steals\r
           it, or it doesn't really exist. */\r
@@ -5170,7 +5062,6 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
             MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);\r
         else\r
             MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);\r
-#endif\r
       }\r
       break;\r
     case IcsPlayingWhite:\r
@@ -5223,24 +5114,9 @@ ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     case '\r':\r
       SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);\r
       return TRUE;\r
-    case '\t':\r
-      if (appData.icsActive) {\r
-       if (GetKeyState(VK_SHIFT) < 0) {\r
-         /* shifted */\r
-         HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);\r
-         if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);\r
-         SetFocus(h);\r
-       } else {\r
-         /* unshifted */\r
-         HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);\r
-         if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);\r
-         SetFocus(h);\r
-       }\r
-       return TRUE;\r
-      }\r
-      break;\r
     default:\r
-      if (appData.icsActive) {\r
+      if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {\r
+       // [HGM] movenum: only letters or leading zero should go to ICS input\r
         HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);\r
        if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);\r
        SetFocus(h);\r
@@ -5337,7 +5213,8 @@ Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
        only show the popup when we are already sure the move is valid or\r
        legal. We pass a faulty move type, but the kludge is that FinishMove\r
        will figure out it is a promotion from the promoChar. */\r
-    FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);\r
+    UserMoveEvent(fromX, fromY, toX, toY, promoChar);\r
+    fromX = fromY = -1;\r
     if (!appData.highlightLastMove) {\r
       ClearHighlights();\r
       DrawPosition(FALSE, NULL);\r
@@ -5359,6 +5236,13 @@ PromotionPopup(HWND hwnd)
   FreeProcInstance(lpProc);\r
 }\r
 \r
+void\r
+PromotionPopUp()\r
+{\r
+  DrawPosition(TRUE, NULL);\r
+  PromotionPopup(hwndMain);\r
+}\r
+\r
 /* Toggle ShowThinking */\r
 VOID\r
 ToggleShowThinking()\r
@@ -5395,6 +5279,57 @@ LoadGameDialog(HWND hwnd, char* title)
   }\r
 }\r
 \r
+int get_term_width()\r
+{\r
+    HDC hdc;\r
+    TEXTMETRIC tm;\r
+    RECT rc;\r
+    HFONT hfont, hold_font;\r
+    LOGFONT lf;\r
+    HWND hText;\r
+\r
+    if (hwndConsole)\r
+        hText = GetDlgItem(hwndConsole, OPT_ConsoleText);\r
+    else\r
+        return 79;\r
+\r
+    // get the text metrics\r
+    hdc = GetDC(hText);\r
+    lf = font[boardSize][CONSOLE_FONT]->lf;\r
+    if (consoleCF.dwEffects & CFE_BOLD)\r
+        lf.lfWeight = FW_BOLD;\r
+    if (consoleCF.dwEffects & CFE_ITALIC)\r
+        lf.lfItalic = TRUE;\r
+    if (consoleCF.dwEffects & CFE_STRIKEOUT)\r
+        lf.lfStrikeOut = TRUE;\r
+    if (consoleCF.dwEffects & CFE_UNDERLINE)\r
+        lf.lfUnderline = TRUE;\r
+    hfont = CreateFontIndirect(&lf);\r
+    hold_font = SelectObject(hdc, hfont);\r
+    GetTextMetrics(hdc, &tm);\r
+    SelectObject(hdc, hold_font);\r
+    DeleteObject(hfont);\r
+    ReleaseDC(hText, hdc);\r
+\r
+    // get the rectangle\r
+    SendMessage(hText, EM_GETRECT, 0, (LPARAM)&rc);\r
+\r
+    return (rc.right-rc.left) / tm.tmAveCharWidth;\r
+}\r
+\r
+void UpdateICSWidth(HWND hText)\r
+{\r
+    LONG old_width, new_width;\r
+\r
+    new_width = get_term_width(hText, FALSE);\r
+    old_width = GetWindowLong(hText, GWL_USERDATA);\r
+    if (new_width != old_width)\r
+    {\r
+        ics_update_width(new_width);\r
+        SetWindowLong(hText, GWL_USERDATA, new_width);\r
+    }\r
+}\r
+\r
 VOID\r
 ChangedConsoleFont()\r
 {\r
@@ -5434,6 +5369,7 @@ ChangedConsoleFont()
   paraf.dxOffset = WRAP_INDENT;\r
   SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) &paraf);\r
   SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);\r
+  UpdateICSWidth(hText);\r
 }\r
 \r
 /*---------------------------------------------------------------------------*\\r
@@ -5481,30 +5417,25 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     MouseEvent(hwnd, message, wParam, lParam);\r
     break;\r
 \r
+  JAWS_KB_NAVIGATION\r
+\r
   case WM_CHAR:\r
     \r
-    if (appData.icsActive) {\r
-      if (wParam == '\t') {\r
-       if (GetKeyState(VK_SHIFT) < 0) {\r
-         /* shifted */\r
-         HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);\r
-         if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);\r
-         SetFocus(h);\r
-       } else {\r
-         /* unshifted */\r
-         HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);\r
-         if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);\r
-         SetFocus(h);\r
-       }\r
-      } else {\r
+    JAWS_ALT_INTERCEPT\r
+\r
+    if (appData.icsActive && (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9')) { \r
+       // [HGM] movenum: for non-zero digits we always do type-in dialog\r
        HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);\r
        if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);\r
        SetFocus(h);\r
        SendMessage(h, message, wParam, lParam);\r
-      }\r
-    } else if (isalpha((char)wParam) || isdigit((char)wParam)) {\r
-      PopUpMoveDialog((char)wParam);\r
+    } else if(lParam != KF_REPEAT) {\r
+       if (isalpha((char)wParam) || isdigit((char)wParam)) {\r
+               PopUpMoveDialog((char)wParam);\r
+       } else if((char)wParam == 003) CopyGameToClipboard();\r
+        else if((char)wParam == 026) PasteGameOrFENFromClipboard();\r
     }\r
+\r
     break;\r
 \r
   case WM_PALETTECHANGED:\r
@@ -5515,11 +5446,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       nnew = RealizePalette(hdc);\r
       if (nnew > 0) {\r
        paletteChanged = TRUE;\r
-#if 0\r
-        UpdateColors(hdc);\r
-#else\r
-        InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/\r
-#endif\r
+        InvalidateRect(hwnd, &boardRect, FALSE);\r
       }\r
       ReleaseDC(hwnd, hdc);\r
     }\r
@@ -5547,13 +5474,12 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     switch (wmId) {\r
     case IDM_NewGame:\r
       ResetGameEvent();\r
-      AnalysisPopDown();\r
+      SAY("new game enter a move to play against the computer with white");\r
       break;\r
 \r
     case IDM_NewGameFRC:\r
       if( NewGameFRC() == 0 ) {\r
         ResetGameEvent();\r
-        AnalysisPopDown();\r
       }\r
       break;\r
 \r
@@ -5670,6 +5596,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
         }\r
         else {\r
             EvalGraphPopUp();\r
+           SetFocus(hwndMain);\r
         }\r
         break;\r
 \r
@@ -5701,6 +5628,10 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       GameListOptions();\r
       break;\r
 \r
+    case IDM_NewChat:\r
+      ChatPopUp();\r
+      break;\r
+\r
     case IDM_CopyPosition:\r
       CopyFENToClipboard();\r
       break;\r
@@ -5737,6 +5668,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
          TagsPopUp(tags, CmailMsg());\r
          free(tags);\r
       }\r
+      SAY("computer starts playing white");\r
       break;\r
 \r
     case IDM_MachineBlack:\r
@@ -5750,6 +5682,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
          TagsPopUp(tags, CmailMsg());\r
          free(tags);\r
       }\r
+      SAY("computer starts playing black");\r
       break;\r
 \r
     case IDM_TwoMachines:\r
@@ -5763,6 +5696,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
          TagsPopUp(tags, CmailMsg());\r
          free(tags);\r
       }\r
+      SAY("programs start playing each other");\r
       break;\r
 \r
     case IDM_AnalysisMode:\r
@@ -5770,6 +5704,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
         sprintf(buf, "%s does not support analysis", first.tidy);\r
         DisplayError(buf, 0);\r
       } else {\r
+       SAY("analyzing current position");\r
         /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */\r
         if (appData.icsActive) {\r
                if (gameMode != IcsObserving) {\r
@@ -5819,10 +5754,12 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 \r
     case IDM_EditGame:\r
       EditGameEvent();\r
+      SAY("edit game");\r
       break;\r
 \r
     case IDM_EditPosition:\r
       EditPositionEvent();\r
+      SAY("to set up a position type a FEN");\r
       break;\r
 \r
     case IDM_Training:\r
@@ -5902,6 +5839,8 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       SetFocus(hwndMain);\r
       break;\r
 \r
+    JAWS_MENU_ITEMS\r
+\r
     case IDM_Forward:\r
       ForwardEvent();\r
       SetFocus(hwndMain);\r
@@ -5944,6 +5883,12 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       DrawPosition(FALSE, NULL);\r
       break;\r
 \r
+    case IDM_MuteSounds:\r
+      mute = !mute; // [HGM] mute: keep track of global muting variable\r
+      CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds, \r
+                               MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));\r
+      break;\r
+\r
     case IDM_GeneralOptions:\r
       GeneralOptionsPopup(hwnd);\r
       DrawPosition(TRUE, NULL);\r
@@ -5957,6 +5902,14 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       EnginePlayOptionsPopup(hwnd);\r
       break;\r
 \r
+    case IDM_Engine1Options:\r
+      EngineOptionsPopup(hwnd, &first);\r
+      break;\r
+\r
+    case IDM_Engine2Options:\r
+      EngineOptionsPopup(hwnd, &second);\r
+      break;\r
+\r
     case IDM_OptionsUCI:\r
       UciOptionsPopup(hwnd);\r
       break;\r
@@ -6028,15 +5981,17 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       break;\r
 \r
     case IDM_HELPCONTENTS:\r
-      if (!WinHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {\r
-       MessageBox (GetFocus(),\r
+      if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&\r
+         !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {\r
+         MessageBox (GetFocus(),\r
                    "Unable to activate help",\r
                    szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);\r
       }\r
       break;\r
 \r
     case IDM_HELPSEARCH:\r
-      if (!WinHelp(hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) {\r
+        if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&\r
+           !HtmlHelp(hwnd, "winboard.chm", 0, 0)       ) {\r
        MessageBox (GetFocus(),\r
                    "Unable to activate help",\r
                    szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);\r
@@ -6300,6 +6255,8 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
             ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );\r
             ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );\r
             ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );\r
+            ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );\r
+            ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );\r
            boardX = lpwp->x;\r
             boardY = lpwp->y;\r
         }\r
@@ -6490,8 +6447,11 @@ BOOLEAN
 MyPlaySound(MySound *ms)\r
 {\r
   BOOLEAN ok = FALSE;\r
+\r
+  if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted\r
   switch (ms->name[0]) {\r
   case NULLCHAR:\r
+       if(appData.debugMode) fprintf(debugFP, "silence\n");\r
     /* Silence */\r
     ok = TRUE;\r
     break;\r
@@ -6521,13 +6481,6 @@ MyPlaySound(MySound *ms)
   /* Don't print an error: this can happen innocently if the sound driver\r
      is busy; for instance, if another instance of WinBoard is playing\r
      a sound at about the same time. */\r
-#if 0\r
-  if (!ok) {\r
-    char buf[MSG_SIZ];\r
-    sprintf(buf, "Error playing sound %s", ms->name);\r
-    DisplayError(buf, GetLastError());\r
-  }\r
-#endif\r
   return ok;\r
 }\r
 \r
@@ -7013,6 +6966,7 @@ About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
     /* Center the dialog over the application window */\r
     CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));\r
     SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);\r
+    JAWS_COPYRIGHT\r
     return (TRUE);\r
 \r
   case WM_COMMAND: /* message: received a command */\r
@@ -7070,7 +7024,7 @@ CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
       if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&\r
          commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {\r
        WINDOWPLACEMENT wp;\r
-       EnsureOnScreen(&commentX, &commentY);\r
+       EnsureOnScreen(&commentX, &commentY, 0, 0);\r
        wp.length = sizeof(WINDOWPLACEMENT);\r
        wp.flags = 0;\r
        wp.showCmd = SW_SHOW;\r
@@ -7217,12 +7171,35 @@ TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
   case WM_COMMAND:\r
     switch (LOWORD(wParam)) {\r
     case IDOK:\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
+         currentMove = 2*n-1;\r
+         if(currentMove > forwardMostMove)  currentMove = forwardMostMove;\r
+         if(currentMove < backwardMostMove) currentMove = backwardMostMove;\r
+         EndDialog(hDlg, TRUE);\r
+         DrawPosition(TRUE, boards[currentMove]);\r
+         if(currentMove > backwardMostMove) DisplayMove(currentMove - 1);\r
+         else DisplayMessage("", "");\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));\r
-       if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove, \r
+//     GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream\r
+       int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove, \r
+         &moveType, &fromX, &fromY, &toX, &toY, &promoChar);\r
+       if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized\r
+       if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove, \r
          &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {\r
          if (gameMode != Training)\r
              forwardMostMove = currentMove;\r
@@ -7254,6 +7231,9 @@ PopUpMoveDialog(char firstchar)
        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
       lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);\r
       DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),\r
@@ -7290,6 +7270,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
 \r
       EndDialog(hDlg, TRUE);\r
       return TRUE;\r
@@ -7718,6 +7699,7 @@ ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     }\r
     break;\r
   case WM_CHAR:\r
+   if(wParam != '\022') {\r
     if (wParam == '\t') {\r
       if (GetKeyState(VK_SHIFT) < 0) {\r
        /* shifted */\r
@@ -7733,10 +7715,31 @@ ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       }\r
     } else {\r
       hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);\r
-      SetFocus(hInput);\r
+      JAWS_DELETE( SetFocus(hInput); )\r
       SendMessage(hInput, message, wParam, lParam);\r
     }\r
     return 0;\r
+   } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu\r
+  case WM_RBUTTONUP:\r
+    if (GetKeyState(VK_SHIFT) & ~1) {\r
+      SendDlgItemMessage(hwndConsole, OPT_ConsoleText, \r
+        WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);\r
+    } else {\r
+      POINT pt;\r
+      HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);\r
+      SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);\r
+      if (sel.cpMin == sel.cpMax) {\r
+        EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);\r
+        EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);\r
+      }\r
+      if (!IsClipboardFormatAvailable(CF_TEXT)) {\r
+        EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);\r
+      }\r
+      pt.x = LOWORD(lParam);\r
+      pt.y = HIWORD(lParam);\r
+      MenuPopup(hwnd, pt, hmenu, -1);\r
+    }\r
+    return 0;\r
   case WM_PASTE:\r
     hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);\r
     SetFocus(hInput);\r
@@ -7758,26 +7761,6 @@ ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);\r
     }\r
     return 0;\r
-  case WM_RBUTTONUP:\r
-    if (GetKeyState(VK_SHIFT) & ~1) {\r
-      SendDlgItemMessage(hwndConsole, OPT_ConsoleText, \r
-        WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);\r
-    } else {\r
-      POINT pt;\r
-      HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);\r
-      SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);\r
-      if (sel.cpMin == sel.cpMax) {\r
-        EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);\r
-        EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);\r
-      }\r
-      if (!IsClipboardFormatAvailable(CF_TEXT)) {\r
-        EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);\r
-      }\r
-      pt.x = LOWORD(lParam);\r
-      pt.y = HIWORD(lParam);\r
-      MenuPopup(hwnd, pt, hmenu, -1);\r
-    }\r
-    return 0;\r
   case WM_COMMAND:\r
     switch (LOWORD(wParam)) {\r
     case IDM_QuickPaste:\r
@@ -7894,6 +7877,7 @@ ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     case '\021': /* Ctrl+Q */\r
       quoteNextChar = TRUE;\r
       return 0;\r
+    JAWS_REPLAY\r
     default:\r
       break;\r
     }\r
@@ -7988,18 +7972,35 @@ LRESULT CALLBACK
 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
 {\r
   static SnapData sd;\r
-  static HWND hText, hInput /*, hFocus*/;\r
-//  InputSource *is = consoleInputSource;\r
+  HWND hText, hInput;\r
   RECT rect;\r
   static int sizeX, sizeY;\r
   int newSizeX, newSizeY;\r
   MINMAXINFO *mmi;\r
+  WORD wMask;\r
+\r
+  hText = GetDlgItem(hDlg, OPT_ConsoleText);\r
+  hInput = GetDlgItem(hDlg, OPT_ConsoleInput);\r
 \r
   switch (message) {\r
+  case WM_NOTIFY:\r
+    if (((NMHDR*)lParam)->code == EN_LINK)\r
+    {\r
+      ENLINK *pLink = (ENLINK*)lParam;\r
+      if (pLink->msg == WM_LBUTTONUP)\r
+      {\r
+        TEXTRANGE tr;\r
+\r
+        tr.chrg = pLink->chrg;\r
+        tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);\r
+        SendMessage(hText, EM_GETTEXTRANGE, 0, (LPARAM)&tr);\r
+        ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);\r
+        free(tr.lpstrText);\r
+      }\r
+    }\r
+    break;\r
   case WM_INITDIALOG: /* message: initialize dialog box */\r
     hwndConsole = hDlg;\r
-    hText = GetDlgItem(hDlg, OPT_ConsoleText);\r
-    hInput = GetDlgItem(hDlg, OPT_ConsoleInput);\r
     SetFocus(hInput);\r
     consoleTextWindowProc = (WNDPROC)\r
       SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);\r
@@ -8013,40 +8014,46 @@ ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
     GetClientRect(hDlg, &rect);\r
     sizeX = rect.right;\r
     sizeY = rect.bottom;\r
-    if (consoleX != CW_USEDEFAULT && consoleY != CW_USEDEFAULT &&\r
-       consoleW != CW_USEDEFAULT && consoleH != CW_USEDEFAULT) {\r
+    if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&\r
+       wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {\r
       WINDOWPLACEMENT wp;\r
-      EnsureOnScreen(&consoleX, &consoleY);\r
+      EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);\r
       wp.length = sizeof(WINDOWPLACEMENT);\r
       wp.flags = 0;\r
       wp.showCmd = SW_SHOW;\r
       wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;\r
-      wp.rcNormalPosition.left = consoleX;\r
-      wp.rcNormalPosition.right = consoleX + consoleW;\r
-      wp.rcNormalPosition.top = consoleY;\r
-      wp.rcNormalPosition.bottom = consoleY + consoleH;\r
+      wp.rcNormalPosition.left = wpConsole.x;\r
+      wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;\r
+      wp.rcNormalPosition.top = wpConsole.y;\r
+      wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;\r
       SetWindowPlacement(hDlg, &wp);\r
     }\r
-#if 0 \r
+\r
    // [HGM] Chessknight's change 2004-07-13\r
    else { /* Determine Defaults */\r
        WINDOWPLACEMENT wp;\r
-       consoleX = winWidth + 1;\r
-       consoleY = boardY;\r
-       consoleW = screenWidth -  winWidth;\r
-       consoleH = winHeight;\r
-       EnsureOnScreen(&consoleX, &consoleY);\r
+       wpConsole.x = winWidth + 1;\r
+       wpConsole.y = boardY;\r
+       wpConsole.width = screenWidth -  winWidth;\r
+       wpConsole.height = winHeight;\r
+       EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);\r
        wp.length = sizeof(WINDOWPLACEMENT);\r
        wp.flags = 0;\r
        wp.showCmd = SW_SHOW;\r
        wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;\r
-       wp.rcNormalPosition.left = consoleX;\r
-       wp.rcNormalPosition.right = consoleX + consoleW;\r
-       wp.rcNormalPosition.top = consoleY;\r
-       wp.rcNormalPosition.bottom = consoleY + consoleH;\r
+       wp.rcNormalPosition.left = wpConsole.x;\r
+       wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;\r
+       wp.rcNormalPosition.top = wpConsole.y;\r
+       wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;\r
        SetWindowPlacement(hDlg, &wp);\r
     }\r
-#endif\r
+\r
+   // Allow hText to highlight URLs and send notifications on them\r
+   wMask = (WORD) SendMessage(hText, EM_GETEVENTMASK, 0, 0L);\r
+   SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);\r
+   SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);\r
+   SetWindowLong(hText, GWL_USERDATA, 79); // initialize the text window's width\r
+\r
     return FALSE;\r
 \r
   case WM_SETFOCUS:\r
@@ -8106,6 +8113,7 @@ ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
     return OnMoving( &sd, hDlg, wParam, lParam );\r
 \r
   case WM_EXITSIZEMOVE:\r
+       UpdateICSWidth(hText);\r
     return OnExitSizeMove( &sd, hDlg, wParam, lParam );\r
   }\r
 \r
@@ -8274,12 +8282,14 @@ DisplayAClock(HDC hdc, int timeRemaining, int highlight,
   }\r
   oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);\r
 \r
+  JAWS_SILENCE\r
+\r
   ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,\r
             rect->top, ETO_CLIPPED|ETO_OPAQUE,\r
             rect, str, strlen(str), NULL);\r
   if(logoHeight > 0 && appData.clockMode) {\r
       RECT r;\r
-      sprintf(buf, "%s %s", TimeString(timeRemaining), flagFell);\r
+      sprintf(buf, "%s %s", buf+7, flagFell);\r
       r.top = rect->top + logoHeight/2;\r
       r.left = rect->left;\r
       r.right = rect->right;\r
@@ -8573,6 +8583,7 @@ Enables gnuEnables[] = {
   { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },\r
   { -1, -1 }\r
 };\r
 \r
@@ -8582,6 +8593,7 @@ Enables icsEnables[] = {
   { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },\r
   { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },\r
@@ -8589,6 +8601,8 @@ Enables icsEnables[] = {
   { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_Book, 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
   { -1, -1 }\r
 };\r
 \r
@@ -8597,6 +8611,7 @@ Enables zippyEnables[] = {
   { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },\r
   { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },\r
   { IDM_Book, MF_BYCOMMAND|MF_ENABLED },\r
+  { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },\r
   { -1, -1 }\r
 };\r
 #endif\r
@@ -8617,6 +8632,10 @@ Enables ncpEnables[] = {
   { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_Book, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },\r
   { -1, -1 }\r
 };\r
 \r
@@ -8928,6 +8947,9 @@ DisplayMessage(char *str1, char *str2)
   messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;\r
 \r
   if (hwndMain == NULL || IsIconic(hwndMain)) return;\r
+\r
+  SAYMACHINEMOVE();\r
+\r
   hdc = GetDC(hwndMain);\r
   oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);\r
   ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,\r
@@ -9171,6 +9193,7 @@ static GLT_Item GLT_ItemInfo[] = {
     { GLT_TIME_CONTROL,"Time Control" },\r
     { GLT_VARIANT,    "Variant" },\r
     { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },\r
+    { GLT_RESULT_COMMENT, "Result Comment" }, // [HGM] rescom\r
     { 0, 0 }\r
 };\r
 \r
@@ -9370,6 +9393,11 @@ DrawPosition(int fullRedraw, Board board)
   HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board); \r
 }\r
 \r
+void NotifyFrontendLogin()\r
+{\r
+       if (hwndConsole)\r
+               UpdateICSWidth(GetDlgItem(hwndConsole, OPT_ConsoleText));\r
+}\r
 \r
 VOID\r
 ResetFrontEnd()\r
@@ -9392,6 +9420,7 @@ CommentPopUp(char *title, char *str)
 {\r
   HWND hwnd = GetActiveWindow();\r
   EitherCommentPopUp(0, title, str, FALSE);\r
+  SAY(str);\r
   SetActiveWindow(hwnd);\r
 }\r
 \r
@@ -9627,11 +9656,12 @@ void
 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)\r
 {\r
   if (delayedTimerEvent != 0) {\r
-    if (appData.debugMode) {\r
+    if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug\r
       fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");\r
     }\r
     KillTimer(hwndMain, delayedTimerEvent);\r
     delayedTimerEvent = 0;\r
+    if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it\r
     delayedTimerCallback();\r
   }\r
   delayedTimerCallback = cb;\r
@@ -10333,6 +10363,11 @@ RemoveInputSource(InputSourceRef isr)
   }\r
 }\r
 \r
+int no_wrap(char *message, int count)\r
+{\r
+    ConsoleOutput(message, count, FALSE);\r
+    return count;\r
+}\r
 \r
 int\r
 OutputToProcess(ProcRef pr, char *message, int count, int *outError)\r
@@ -10341,11 +10376,32 @@ OutputToProcess(ProcRef pr, char *message, int count, int *outError)
   int outCount = SOCKET_ERROR;\r
   ChildProc *cp = (ChildProc *) pr;\r
   static OVERLAPPED ovl;\r
+  static int line = 0;\r
 \r
-  if (pr == NoProc) {\r
-    ConsoleOutput(message, count, FALSE);\r
-    return count;\r
-  } \r
+  if (pr == NoProc)\r
+  {\r
+    if (appData.noJoin || !appData.useInternalWrap)\r
+      return no_wrap(message, count);\r
+    else\r
+    {\r
+      int width = get_term_width();\r
+      int len = wrap(NULL, message, count, width, &line);\r
+      char *msg = malloc(len);\r
+      int dbgchk;\r
+\r
+      if (!msg)\r
+        return no_wrap(message, count);\r
+      else\r
+      {\r
+        dbgchk = wrap(msg, message, count, width, &line);\r
+        if (dbgchk != len && appData.debugMode)\r
+            fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);\r
+        ConsoleOutput(msg, len, FALSE);\r
+        free(msg);\r
+        return len;\r
+      }\r
+    }\r
+  }\r
 \r
   if (ovl.hEvent == NULL) {\r
     ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);\r
@@ -10454,7 +10510,7 @@ AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
       if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&\r
          analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {\r
        WINDOWPLACEMENT wp;\r
-       EnsureOnScreen(&analysisX, &analysisY);\r
+       EnsureOnScreen(&analysisX, &analysisY, 0, 0);\r
        wp.length = sizeof(WINDOWPLACEMENT);\r
        wp.flags = 0;\r
        wp.showCmd = SW_SHOW;\r
@@ -10509,51 +10565,6 @@ AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
   return FALSE;\r
 }\r
 \r
-VOID\r
-AnalysisPopUp(char* title, char* str)\r
-{\r
-  FARPROC lpProc;\r
-  char *p, *q;\r
-\r
-  /* [AS] */\r
-  EngineOutputPopUp();\r
-  return;\r
-\r
-  if (str == NULL) str = "";\r
-  p = (char *) malloc(2 * strlen(str) + 2);\r
-  q = p;\r
-  while (*str) {\r
-    if (*str == '\n') *q++ = '\r';\r
-    *q++ = *str++;\r
-  }\r
-  *q = NULLCHAR;\r
-  if (analysisText != NULL) free(analysisText);\r
-  analysisText = p;\r
-\r
-  if (analysisDialog) {\r
-    SetWindowText(analysisDialog, title);\r
-    SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);\r
-    ShowWindow(analysisDialog, SW_SHOW);\r
-  } else {\r
-    analysisTitle = title;\r
-    lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);\r
-    CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),\r
-                hwndMain, (DLGPROC)lpProc);\r
-    FreeProcInstance(lpProc);\r
-  }\r
-  analysisDialogUp = TRUE;  \r
-}\r
-\r
-VOID\r
-AnalysisPopDown()\r
-{\r
-  if (analysisDialog) {\r
-    ShowWindow(analysisDialog, SW_HIDE);\r
-  }\r
-  analysisDialogUp = FALSE;  \r
-}\r
-\r
-\r
 VOID\r
 SetHighlights(int fromX, int fromY, int toX, int toY)\r
 {\r
@@ -10754,15 +10765,6 @@ Tween(start, mid, finish, factor, frames, nFrames)
 void\r
 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )\r
 {\r
-#if 0\r
-    char buf[256];\r
-\r
-    sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",\r
-        first, last, current, current >= 0 ? movelist[current] : "n/a" );\r
-\r
-    OutputDebugString( buf );\r
-#endif\r
-\r
     MoveHistorySet( movelist, first, last, current, pvInfoList );\r
 \r
     EvalGraphSet( first, last, current, pvInfoList );\r
@@ -10770,14 +10772,5 @@ HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
 \r
 void SetProgramStats( FrontEndProgramStats * stats )\r
 {\r
-#if 0\r
-    char buf[1024];\r
-\r
-    sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",\r
-        stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );\r
-\r
-    OutputDebugString( buf );\r
-#endif\r
-\r
     EngineOutputUpdate( stats );\r
 }\r