changes from Alessandro Scotti from 20050322
authorA. Scotti <dev@ascotti.org>
Thu, 16 Apr 2009 20:53:41 +0000 (13:53 -0700)
committerArun Persaud <arun@nubati.net>
Thu, 16 Apr 2009 20:53:41 +0000 (13:53 -0700)
backend.c
backend.h
common.h
readme.htm [new file with mode: 0644]
winboard/resource.h
winboard/wclipbrd.c
winboard/wclipbrd.h
winboard/winboard.c
winboard/winboard.ini [new file with mode: 0644]
winboard/winboard.rc
winboard/woptions.c

index f28d863..958f503 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -1,6 +1,6 @@
 /*
  * backend.c -- Common back end for X and Windows NT versions of
- * XBoard $Id$
+ * XBoard $Id: backend.c,v 2.6 2003/11/28 09:37:36 mann Exp $
  *
  * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts.
  * Enhancements Copyright 1992-2001 Free Software Foundation, Inc.
  *
  * See the file ChangeLog for a revision history.  */
 
+/* [AS] For debugging purposes */
+#ifdef WIN32
+#include <windows.h>
+
+#define DoSleep( n ) if( (n) != 0 ) Sleep( (n) );
+
+#else
+
+#define DoSleep( n )
+
+#endif
+
 #include "config.h"
 
+#include <assert.h>
 #include <stdio.h>
 #include <ctype.h>
 #include <errno.h>
@@ -131,6 +144,12 @@ typedef struct {
   int seen_stat;          /* 1 if we've seen the stat01: line */
 } ChessProgramStats;
 
+/* [AS] Search stats from chessprogram, for the played move */
+typedef struct {
+    int score;
+    int depth;
+} ChessProgramStats_Move;
+
 int establish P((void));
 void read_from_player P((InputSourceRef isr, VOIDSTAR closure,
                         char *buf, int count, int error));
@@ -245,6 +264,35 @@ static ChessProgramStats programStats;
 #define TN_SGA  0003
 #define TN_PORT 23
 
+/* [AS] */
+static char * safeStrCpy( char * dst, const char * src, size_t count )
+{
+    assert( dst != NULL );
+    assert( src != NULL );
+    assert( count > 0 );
+
+    strncpy( dst, src, count );
+    dst[ count-1 ] = '\0';
+    return dst;
+}
+
+static char * safeStrCat( char * dst, const char * src, size_t count )
+{
+    size_t  dst_len;
+
+    assert( dst != NULL );
+    assert( src != NULL );
+    assert( count > 0 );
+
+    dst_len = strlen(dst);
+
+    assert( count > dst_len ); /* Buffer size must be greater than current length */
+
+    safeStrCpy( dst + dst_len, src, count - dst_len );
+
+    return dst;
+}
+
 /* Fake up flags for now, as we aren't keeping track of castling
    availability yet */
 int
@@ -275,6 +323,15 @@ PosFlags(index)
 
 FILE *gameFileFP, *debugFP;
 
+/*
+    [AS] Note: sometimes, the sscanf() function is used to parse the input
+    into a fixed-size buffer. Because of this, we must be prepared to
+    receive strings as long as the size of the input buffer, which is currently
+    set to 4K for Windows and 8K for the rest.
+    So, we must either allocate sufficiently large buffers here, or
+    reduce the size of the input buffer in the input reading part.
+*/
+
 char cmailMove[CMAIL_MAX_GAMES][MOVE_LEN], cmailMsg[MSG_SIZ];
 char bookOutput[MSG_SIZ*10], thinkOutput[MSG_SIZ*10], lastHint[MSG_SIZ];
 char thinkOutput1[MSG_SIZ*10];
@@ -317,12 +374,17 @@ InputSourceRef telnetISR = NULL, fromUserISR = NULL, cmailISR = NULL;
 GameMode gameMode = BeginningOfGame;
 char moveList[MAX_MOVES][MOVE_LEN], parseList[MAX_MOVES][MOVE_LEN * 2];
 char *commentList[MAX_MOVES], *cmailCommentList[CMAIL_MAX_GAMES];
+ChessProgramStats_Move pvInfoList[MAX_MOVES]; /* [AS] Info about engine thinking */
+int hiddenThinkOutputState = 0; /* [AS] */
+int adjudicateLossThreshold = 0; /* [AS] Automatic adjudication */
+int adjudicateLossPlies = 6;
 char white_holding[64], black_holding[64];
 TimeMark lastNodeCountTime;
 long lastNodeCount=0;
 int have_sent_ICS_logon = 0;
 int movesPerSession;
 long whiteTimeRemaining, blackTimeRemaining, timeControl, timeIncrement;
+long timeControl_2; /* [AS] Allow separate time controls */
 long timeRemaining[2][MAX_MOVES];
 int matchGame = 0;
 TimeMark programStartTime;
@@ -446,6 +508,15 @@ InitBackEnd1()
        appData.zippyTalk = appData.zippyPlay = FALSE;
     }
 
+    /* [AS] Initialize pv info list */
+    {
+        int i;
+
+        for( i=0; i<MAX_MOVES; i++ ) {
+            pvInfoList[i].depth = 0;
+        }
+    }
+
     /*
      * Parse timeControl resource
      */
@@ -472,6 +543,9 @@ InitBackEnd1()
        }
     }
     
+    /* [AS] Adjudication threshold */
+    adjudicateLossThreshold = appData.adjudicateLossThreshold;
+
     first.which = "first";
     second.which = "second";
     first.maybeThinking = second.maybeThinking = FALSE;
@@ -523,6 +597,9 @@ InitBackEnd1()
     first.analyzing = second.analyzing = FALSE;
     first.initDone = second.initDone = FALSE;
 
+    first.scoreIsAbsolute = appData.firstScoreIsAbsolute; /* [AS] */
+    second.scoreIsAbsolute = appData.secondScoreIsAbsolute; /* [AS] */
+
     if (appData.firstProtocolVersion > PROTOVER ||
        appData.firstProtocolVersion < 1) {
       char buf[MSG_SIZ];
@@ -626,12 +703,73 @@ InitBackEnd1()
     }
 }
 
+int NextIntegerFromString( char ** str, long * value )
+{
+    int result = -1;
+    char * s = *str;
+
+    while( *s == ' ' || *s == '\t' ) {
+        s++;
+    }
+
+    *value = 0;
+
+    if( *s >= '0' && *s <= '9' ) {
+        while( *s >= '0' && *s <= '9' ) {
+            *value = *value * 10 + (*s - '0');
+            s++;
+        }
+
+        result = 0;
+    }
+
+    *str = s;
+
+    return result;
+}
+
+int NextTimeControlFromString( char ** str, long * value )
+{
+    long temp;
+    int result = NextIntegerFromString( str, &temp );
+
+    if( result == 0 ) {
+        *value = temp * 60; /* Minutes */
+        if( **str == ':' ) {
+            (*str)++;
+            result = NextIntegerFromString( str, &temp );
+            *value += temp; /* Seconds */
+        }
+    }
+
+    return result;
+}
+
+int GetTimeControlForWhite()
+{
+    int result = timeControl;
+
+    return result;
+}
+
+int GetTimeControlForBlack()
+{
+    int result = timeControl;
+
+    if( timeControl_2 > 0 ) {
+        result = timeControl_2;
+    }
+
+    return result;
+}
+
 int
 ParseTimeControl(tc, ti, mps)
      char *tc;
      int ti;
      int mps;
 {
+#if 0
     int matched, min, sec;
 
     matched = sscanf(tc, "%d:%d", &min, &sec);
@@ -642,6 +780,38 @@ ParseTimeControl(tc, ti, mps)
     } else {
        return FALSE;
     }
+#else
+    long tc1;
+    long tc2;
+
+    if( NextTimeControlFromString( &tc, &tc1 ) != 0 ) {
+        return FALSE;
+    }
+
+    if( *tc == '/' ) {
+        /* Parse second time control */
+        tc++;
+
+        if( NextTimeControlFromString( &tc, &tc2 ) != 0 ) {
+            return FALSE;
+        }
+
+        if( tc2 == 0 ) {
+            return FALSE;
+        }
+
+        timeControl_2 = tc2 * 1000;
+    }
+    else {
+        timeControl_2 = 0;
+    }
+
+    if( tc1 == 0 ) {
+        return FALSE;
+    }
+
+    timeControl = tc1 * 1000;
+#endif
 
     if (ti >= 0) {
        timeIncrement = ti * 1000;  /* convert to ms */
@@ -2725,6 +2895,7 @@ ParseBoard12(string)
        gameInfo.white = StrSave(white);
        gameInfo.black = StrSave(black);
        timeControl = basetime * 60 * 1000;
+        timeControl_2 = 0;
        timeIncrement = increment * 1000;
        movesPerSession = 0;
        gameInfo.timeControl = TimeControlTagValue();
@@ -3242,6 +3413,16 @@ InitPosition(redraw)
      int redraw;
 {
     currentMove = forwardMostMove = backwardMostMove = 0;
+
+    /* [AS] Initialize pv info list */
+    {
+        int i;
+
+        for( i=0; i<MAX_MOVES; i++ ) {
+            pvInfoList[i].depth = 0;
+        }
+    }
+
     switch (gameInfo.variant) {
     default:
       CopyBoard(boards[0], initialPosition);
@@ -3872,6 +4053,13 @@ HandleMachineMove(message, cps)
        strcat(machineMove, "\n");
        strcpy(moveList[forwardMostMove], machineMove);
     
+        /* [AS] Save move info and clear stats for next move */
+        pvInfoList[ forwardMostMove ].score = programStats.score;
+        pvInfoList[ forwardMostMove ].depth = programStats.depth;
+        ClearProgramStats();
+        thinkOutput[0] = NULLCHAR;
+        hiddenThinkOutputState = 0;
+
        MakeMove(fromX, fromY, toX, toY, promoChar);/*updates forwardMostMove*/
     
        if (gameMode == TwoMachinesPlay) {
@@ -3891,15 +4079,44 @@ HandleMachineMove(message, cps)
        }
 
        ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/
+
        if (!pausing && appData.ringBellAfterMoves) {
            RingBell();
        }
+
        /* 
         * Reenable menu items that were disabled while
         * machine was thinking
         */
        if (gameMode != TwoMachinesPlay)
            SetUserThinkingEnables();
+
+
+        /* [AS] Adjudicate game if needed (note: forwardMostMove now points past the last move */
+        if( gameMode == TwoMachinesPlay && adjudicateLossThreshold != 0 && forwardMostMove >= adjudicateLossPlies ) {
+            int count = 0;
+
+            while( count < adjudicateLossPlies ) {
+                int score = pvInfoList[ forwardMostMove - count - 1 ].score;
+
+                if( count & 1 ) {
+                    score = -score; /* Flip score for winning side */
+                }
+
+                if( score > adjudicateLossThreshold ) {
+                    break;
+                }
+
+                count++;
+            }
+
+            if( count >= adjudicateLossPlies ) {
+                GameEnds( WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins,
+                    "Xboard adjudication",
+                    GE_XBOARD );
+            }
+        }
+
        return;
     }
 
@@ -4315,7 +4532,7 @@ HandleMachineMove(message, cps)
     /*
      * Look for thinking output
      */
-    if (appData.showThinking) {
+    if ( appData.showThinking) {
        int plylev, mvleft, mvtot, curscore, time;
        char mvname[MOVE_LEN];
        unsigned long nodes;
@@ -4337,8 +4554,7 @@ HandleMachineMove(message, cps)
          case AnalyzeFile:
            break;
          case TwoMachinesPlay:
-           if ((cps->twoMachinesColor[0] == 'w') !=
-               WhiteOnMove(forwardMostMove)) {
+           if ((cps->twoMachinesColor[0] == 'w') != WhiteOnMove(forwardMostMove)) {
                ignore = TRUE;
            }
            break;
@@ -4361,6 +4577,13 @@ HandleMachineMove(message, cps)
                programStats.score = curscore;
                programStats.got_only_move = 0;
 
+                /* [AS] Negate score if machine is playing black and it's reporting absolute scores */
+                if( cps->scoreIsAbsolute &&
+                    ((gameMode == MachinePlaysBlack) || (gameMode == TwoMachinesPlay && cps->twoMachinesColor[0] == 'b')) )
+                {
+                    programStats.score = -curscore;
+                }
+
                /* Buffer overflow protection */
                if (buf1[0] != NULLCHAR) {
                    if (strlen(buf1) >= sizeof(programStats.movelist)
@@ -4369,10 +4592,8 @@ HandleMachineMove(message, cps)
                                "PV is too long; using the first %d bytes.\n",
                                sizeof(programStats.movelist) - 1);
                    }
-                   strncpy(programStats.movelist, buf1,
-                           sizeof(programStats.movelist));
-                   programStats.movelist[sizeof(programStats.movelist) - 1]
-                     = NULLCHAR;
+
+                    safeStrCpy( programStats.movelist, buf1, sizeof(programStats.movelist) );
                } else {
                    sprintf(programStats.movelist, " no PV\n");
                }
@@ -4389,16 +4610,32 @@ HandleMachineMove(message, cps)
                    programStats.line_is_book = 0;
                }
                  
-               sprintf(thinkOutput, "[%d]%c%+.2f %s%s%s",
+                /*
+                    [AS] Protect the thinkOutput buffer from overflow... this
+                    is only useful if buf1 hasn't overflowed first!
+                */
+               sprintf(thinkOutput, "[%d]%c%+.2f %s%s",
                        plylev, 
                        (gameMode == TwoMachinesPlay ?
                         ToUpper(cps->twoMachinesColor[0]) : ' '),
                        ((double) curscore) / 100.0,
                        prefixHint ? lastHint : "",
-                       prefixHint ? " " : "", buf1);
+                       prefixHint ? " " : "" );
+
+                if( buf1[0] != NULLCHAR ) {
+                    unsigned max_len = sizeof(thinkOutput) - strlen(thinkOutput) - 1;
 
-               if (currentMove == forwardMostMove ||
-                   gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
+                    if( strlen(buf1) > max_len ) {
+                       if( appData.debugMode) {
+                           fprintf(debugFP,"PV is too long for thinkOutput, truncating.\n");
+                        }
+                        buf1[max_len+1] = '\0';
+                    }
+
+                    strcat( thinkOutput, buf1 );
+                }
+
+               if (currentMove == forwardMostMove || gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
                    DisplayMove(currentMove - 1);
                    DisplayAnalysis();
                }
@@ -4423,8 +4660,7 @@ HandleMachineMove(message, cps)
                   isn't searching, so stats won't change) */
                programStats.line_is_book = 1;
                  
-               if (currentMove == forwardMostMove || gameMode==AnalyzeMode ||
-                   gameMode == AnalyzeFile) {
+               if (currentMove == forwardMostMove || gameMode==AnalyzeMode || gameMode == AnalyzeFile) {
                    DisplayMove(currentMove - 1);
                    DisplayAnalysis();
                }
@@ -4462,14 +4698,25 @@ HandleMachineMove(message, cps)
 
            } else if (thinkOutput[0] != NULLCHAR &&
                       strncmp(message, "    ", 4) == 0) {
+                unsigned message_len;
+
                p = message;
                while (*p && *p == ' ') p++;
+
+                message_len = strlen( p );
+
+                /* [AS] Avoid buffer overflow */
+                if( sizeof(thinkOutput) - strlen(thinkOutput) - 1 > message_len ) {
                strcat(thinkOutput, " ");
                strcat(thinkOutput, p);
+                }
+
+                if( sizeof(programStats.movelist) - strlen(programStats.movelist) - 1 > message_len ) {
                strcat(programStats.movelist, " ");
                strcat(programStats.movelist, p);
-               if (currentMove == forwardMostMove || gameMode==AnalyzeMode ||
-                   gameMode == AnalyzeFile) {
+                }
+
+               if (currentMove == forwardMostMove || gameMode==AnalyzeMode || gameMode == AnalyzeFile) {
                    DisplayMove(currentMove - 1);
                    DisplayAnalysis();
                }
@@ -4987,6 +5234,23 @@ NextMatchGame P((void))
     TwoMachinesEventIfReady();
 }
 
+void UserAdjudicationEvent( int result )
+{
+    ChessMove gameResult = GameIsDrawn;
+
+    if( result > 0 ) {
+        gameResult = WhiteWins;
+    }
+    else if( result < 0 ) {
+        gameResult = BlackWins;
+    }
+
+    if( gameMode == TwoMachinesPlay ) {
+        GameEnds( gameResult, "User adjudication", GE_XBOARD );
+    }
+}
+
+
 void
 GameEnds(result, resultDetails, whosays)
      ChessMove result;
@@ -5166,7 +5430,9 @@ GameEnds(result, resultDetails, whosays)
     
        if (first.pr != NoProc) {
            ExitAnalyzeMode();
+            DoSleep( appData.delayBeforeQuit );
            SendToProgram("quit\n", &first);
+            DoSleep( appData.delayAfterQuit );
            DestroyChildProcess(first.pr, first.useSigterm);
        }
        first.pr = NoProc;
@@ -5189,7 +5455,9 @@ GameEnds(result, resultDetails, whosays)
        second.isr = NULL;
     
        if (second.pr != NoProc) {
+            DoSleep( appData.delayBeforeQuit );
            SendToProgram("quit\n", &second);
+            DoSleep( appData.delayAfterQuit );
            DestroyChildProcess(second.pr, second.useSigterm);
        }
        second.pr = NoProc;
@@ -6526,6 +6794,7 @@ SaveGamePGN(f)
     char *movetext;
     char numtext[32];
     int movelen, numlen, blank;
+    char move_buffer[100]; /* [AS] Buffer for move+PV info */
     
     tm = time((time_t *) NULL);
     
@@ -6585,6 +6854,17 @@ SaveGamePGN(f)
 
        /* Get move */
        movetext = SavePart(parseList[i]);
+
+        /* [AS] Add PV info if present */
+        if( i > 0 && appData.saveExtendedInfoInPGN && pvInfoList[i].depth > 0 ) {
+            sprintf( move_buffer, "%s {%s%.2f/%d}",
+                movetext,
+                pvInfoList[i].score >= 0 ? "+" : "",
+                pvInfoList[i].score / 100.0,
+                pvInfoList[i].depth );
+            movetext = move_buffer;
+        }
+
        movelen = strlen(movetext);
 
        /* Print move */
@@ -7132,11 +7412,16 @@ ExitEvent(status)
     /* Kill off chess programs */
     if (first.pr != NoProc) {
        ExitAnalyzeMode();
+
+        DoSleep( appData.delayBeforeQuit );
        SendToProgram("quit\n", &first);
+        DoSleep( appData.delayAfterQuit );
        DestroyChildProcess(first.pr, first.useSigterm);
     }
     if (second.pr != NoProc) {
+        DoSleep( appData.delayBeforeQuit );
        SendToProgram("quit\n", &second);
+        DoSleep( appData.delayAfterQuit );
        DestroyChildProcess(second.pr, second.useSigterm);
     }
     if (first.isr != NULL) {
@@ -8834,6 +9119,13 @@ ReceiveFromProgram(isr, closure, message, count, error)
                    "Error reading from %s chess program (%s)",
                    cps->which, cps->program);
            RemoveInputSource(cps->isr);
+
+            /* [AS] Program is misbehaving badly... kill it */
+            if( count == -2 ) {
+                DestroyChildProcess( cps->pr, 9 );
+                cps->pr = NoProc;
+            }
+
            DisplayFatalError(buf, error, 1);
        }
        GameEnds((ChessMove) 0, NULL, GE_PLAYER);
@@ -8865,6 +9157,12 @@ SendTimeControl(cps, mps, tc, inc, sd, st)
     char buf[MSG_SIZ];
     int seconds = (tc / 1000) % 60;
 
+    if( timeControl_2 > 0 ) {
+        if( (gameMode == MachinePlaysBlack) || (gameMode == TwoMachinesPlay && cps->twoMachinesColor[0] == 'b') ) {
+            tc = timeControl_2;
+        }
+    }
+
     if (st > 0) {
       /* Set exact time per move, normally using st command */
       if (cps->stKludge) {
@@ -9157,13 +9455,29 @@ DisplayMove(moveNumber)
     if (moveNumber == forwardMostMove - 1 || 
        gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
 
-       strcpy(cpThinkOutput, thinkOutput);
-       if (strchr(cpThinkOutput, '\n'))
+       safeStrCpy(cpThinkOutput, thinkOutput, sizeof(cpThinkOutput));
+
+        if (strchr(cpThinkOutput, '\n')) {
          *strchr(cpThinkOutput, '\n') = NULLCHAR;
+        }
     } else {
        *cpThinkOutput = NULLCHAR;
     }
 
+    /* [AS] Hide thinking from human user */
+    if( appData.hideThinkingFromHuman && gameMode != TwoMachinesPlay ) {
+        *cpThinkOutput = NULLCHAR;
+        if( thinkOutput[0] != NULLCHAR ) {
+            int i;
+
+            for( i=0; i<=hiddenThinkOutputState; i++ ) {
+                cpThinkOutput[i] = '.';
+            }
+            cpThinkOutput[i] = NULLCHAR;
+            hiddenThinkOutputState = (hiddenThinkOutputState + 1) % 3;
+        }
+    }
+
     if (moveNumber == forwardMostMove - 1 &&
        gameInfo.resultDetails != NULL) {
        if (gameInfo.resultDetails[0] == NULLCHAR) {
@@ -9214,6 +9528,7 @@ void
 DisplayAnalysis()
 {
     char buf[MSG_SIZ];
+    char lst[MSG_SIZ / 2];
     double nps;
     static char *xtra[] = { "", " (--)", " (++)" };
     int h, m, s, cs;
@@ -9223,8 +9538,10 @@ DisplayAnalysis()
     }
   
     if (programStats.got_only_move) {
-       strcpy(buf, programStats.movelist);
+       safeStrCpy(buf, programStats.movelist, sizeof(buf));
     } else {
+        safeStrCpy( lst, programStats.movelist, sizeof(lst));
+
        nps = (((double)programStats.nodes) /
               (((double)programStats.time)/100.0));
 
@@ -9241,8 +9558,8 @@ DisplayAnalysis()
                    programStats.depth,
                    programStats.nr_moves-programStats.moves_left,
                    programStats.nr_moves, programStats.move_name,
-                   ((float)programStats.score)/100.0, programStats.movelist,
-                   only_one_move(programStats.movelist)?
+                   ((float)programStats.score)/100.0, lst,
+                   only_one_move(lst)?
                    xtra[programStats.got_fail] : "",
                    programStats.nodes, (int)nps, h, m, s, cs);
          } else {
@@ -9250,8 +9567,8 @@ DisplayAnalysis()
                    programStats.depth,
                    programStats.nr_moves-programStats.moves_left,
                    programStats.nr_moves, ((float)programStats.score)/100.0,
-                   programStats.movelist,
-                   only_one_move(programStats.movelist)?
+                   lst,
+                   only_one_move(lst)?
                    xtra[programStats.got_fail] : "",
                    programStats.nodes, (int)nps, h, m, s, cs);
          }
@@ -9259,8 +9576,8 @@ DisplayAnalysis()
            sprintf(buf, "depth=%d %+.2f %s%s\nNodes: %lu NPS: %d\nTime: %02d:%02d:%02d.%02d",
                    programStats.depth,
                    ((float)programStats.score)/100.0,
-                   programStats.movelist,
-                   only_one_move(programStats.movelist)?
+                   lst,
+                   only_one_move(lst)?
                    xtra[programStats.got_fail] : "",
                    programStats.nodes, (int)nps, h, m, s, cs);
        }
@@ -9390,11 +9707,11 @@ CheckTimeControl()
       switch ((forwardMostMove + 1) % (movesPerSession * 2)) {
       case 0:
        /* White made time control */
-       whiteTimeRemaining += timeControl;
+       whiteTimeRemaining += GetTimeControlForWhite();
        break;
       case 1:
        /* Black made time control */
-       blackTimeRemaining += timeControl;
+       blackTimeRemaining += GetTimeControlForBlack();
        break;
       default:
        break;
@@ -9498,7 +9815,8 @@ ResetClocks()
     if (appData.icsActive) {
        whiteTimeRemaining = blackTimeRemaining = 0;
     } else {
-       whiteTimeRemaining = blackTimeRemaining = timeControl;
+       whiteTimeRemaining = GetTimeControlForWhite();
+        blackTimeRemaining = GetTimeControlForBlack();
     }
     if (whiteFlag || blackFlag) {
        DisplayTitle("");
index 9e1fbb0..f311074 100644 (file)
--- a/backend.h
+++ b/backend.h
@@ -1,6 +1,6 @@
 /*
  * backend.h -- Interface exported by XBoard back end
- * $Id$
+ * $Id: backend.h,v 2.1 2003/10/27 19:21:00 mann Exp $
  *
  * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts.
  * Enhancements Copyright 1992-95 Free Software Foundation, Inc.
@@ -112,6 +112,7 @@ void DrawEvent P((void));
 void AbortEvent P((void));
 void AdjournEvent P((void));
 void ResignEvent P((void));
+void UserAdjudicationEvent P((int result));
 void StopObservingEvent P((void));
 void StopExaminingEvent P((void));
 void PonderNextMoveEvent P((int newState));
@@ -236,6 +237,7 @@ typedef struct _CPS {
     int analyzing;
     int protocolVersion;
     int initDone;
+    int scoreIsAbsolute; /* [AS] 0=don't know (standard), 1=score is always from white side */
 } ChessProgramState;
 
 extern ChessProgramState first, second;
index 62281a4..61741a1 100644 (file)
--- a/common.h
+++ b/common.h
@@ -1,6 +1,6 @@
 /*
  * common.h -- Common definitions for X and Windows NT versions of XBoard
- * $Id$
+ * $Id: common.h,v 2.1 2003/10/27 19:21:00 mann Exp $
  *
  * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts.
  * Enhancements Copyright 1992-95 Free Software Foundation, Inc.
@@ -407,6 +407,27 @@ typedef struct {
     int firstProtocolVersion;
     int secondProtocolVersion;
     Boolean showButtonBar;
+    /* [AS] New properties */
+    Boolean firstScoreIsAbsolute;  /* If true, engine score is always from white side */
+    Boolean secondScoreIsAbsolute; /* If true, engine score is always from white side */
+    Boolean saveExtendedInfoInPGN; /* If true, saved PGN games contain extended info */
+    Boolean hideThinkingFromHuman; /* If true, program thinking is generated but not displayed in human/computer matches */
+    char * liteBackTextureFile; /* Name of texture bitmap for lite squares */
+    char * darkBackTextureFile; /* Name of texture bitmap for dark squares */
+    int liteBackTextureMode;
+    int darkBackTextureMode;
+    char * renderPiecesWithFont; /* Name of font for rendering chess pieces */
+    char * fontToPieceTable; /* Map to translate font character to chess pieces */
+    int fontBackColorWhite;
+    int fontForeColorWhite;
+    int fontBackColorBlack;
+    int fontForeColorBlack;
+    int fontPieceSize; /* Size of font relative to square (percentage) */
+    int overrideLineGap; /* If >= 0 overrides the lineGap value of the board size properties */
+    int adjudicateLossThreshold; /* Adjudicate a two-machine game if both engines agree the score is below this for 6 plies */
+    int delayBeforeQuit;
+    int delayAfterQuit;
+    char * nameOfDebugFile;
 #if ZIPPY
     char *zippyLines;
     char *zippyPinhead;
diff --git a/readme.htm b/readme.htm
new file mode 100644 (file)
index 0000000..ca59e5c
--- /dev/null
@@ -0,0 +1,223 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">\r
+<html>\r
+<head>\r
+</head>\r
+<body>\r
+<big><span style="font-weight: bold;">Tinkering with Winboard<br>\r
+by Alessandro Scotti<br>\r
+</span></big><br>\r
+Last update: March 22, 2005.<br>\r
+<br>\r
+This readme is about some modifications I made to Winboard 4.2.7. Some\r
+will work in Xboard too, while others are for Winboard only.\r
+Regardless, everything here is absolutely experimental and has been\r
+tested very little... so no warranties ok?<br>\r
+<br>\r
+All modified sources are included in this archive, the rest can be\r
+downloaded from <a href="http://www.tim-mann.org/xboard.html">Tim\r
+Mann's Xboard page</a>. Please feel free to take my changes and use\r
+them as you like, they are released under the GPL.<br>\r
+<br>\r
+<big><span style="font-weight: bold;">Game adjudication</span></big><br>\r
+<br>\r
+User can adjudicate a game between two machines, using the "Action"\r
+menu. Note that this only works if two machines are playing.<br>\r
+<br>\r
+Also, it is possible to adjudicate a game automatically with this\r
+parameter:<br>\r
+<br>\r
+<div style="margin-left: 40px;">/adjudicateLossThreshold=-700<br>\r
+</div>\r
+<br>\r
+if set to a negative value, Winboard will adjudicate a game if a engine\r
+can't get a score above the specified threshold for 3 full moves (6\r
+plies). Note that both engines must agree on the score value, and also\r
+the game is only adjudicated after the last move from the losing engine.<br>\r
+<br>\r
+Adjudication is still under test!<br>\r
+<br>\r
+<big><span style="font-weight: bold;">Background textures</span></big><br>\r
+<br>\r
+Add the following to winboard.ini:<br>\r
+<br>\r
+<div style="margin-left: 40px;">/liteBackTextureFile="sandstone_w.bmp"<br>\r
+/darkBackTextureFile="sandstone_b.bmp"<br>\r
+/liteBackTextureMode=1<br>\r
+/darkBackTextureMode=1<br>\r
+</div>\r
+<br>\r
+Of course you can choose any file you like for texturing the light and\r
+dark squares, as long as it's a valid BMP (Windows bitmap) file. <br>\r
+<br>\r
+Valid texture modes are 1 (default) and 2. In mode 1 the squares are\r
+taken from portions of the texture bitmap and copied without further\r
+processing. In mode 2, squares can also be rotated, mirrored and so on\r
+in order to provide a little more variety to the texture. The\r
+operations are selected at random so the board will look slightly\r
+different every time the program is run.<br>\r
+<br>\r
+Note: to "comment out" a filename, put an asterisk in front of it, i.e.\r
+"*sandstone.bmp" will be skipped.<br>\r
+<br>\r
+Additionally it is possible to override the size of the "gap" between\r
+the squares, which is otherwise selected automatically. Add this to\r
+winboard.ini:<br>\r
+<br>\r
+<div style="margin-left: 40px;">/overrideLineGap=2<br>\r
+</div>\r
+<br>\r
+I have added this because textures usually look better with a smaller\r
+or no gap. Any negative value will ignore the override and use the\r
+standard value from Winboard.<br>\r
+<br>\r
+The combination of these parameters can produce very interesting\r
+effects, see for example <a\r
+ href="http://usuarios.lycos.es/alexwbtm/Test/">Alex Guerrero's page</a>.<br>\r
+<br>\r
+<big><span style="font-weight: bold;">Font-based rendering of chess\r
+pieces</span></big><br>\r
+<br>\r
+It is possible to use chess fonts to draw pieces, in place of the usual\r
+bitmaps. You have to specify the font name by adding the following to\r
+winboard.ini:<br>\r
+<br>\r
+<div style="margin-left: 40px;">/renderPiecesWithFont="Chess Leipzig"<br>\r
+</div>\r
+<br>\r
+Chances are the program will automatically recognize the font and\r
+select the proper mapping, i.e. the correspondence between a chess\r
+piece and the corresponding font character. So if the board looks good\r
+you're set and there's nothing else to do, otherwise you'll have to\r
+find the proper mapping and tell it to the program with&nbsp; this\r
+setting:<br>\r
+<br>\r
+<div style="margin-left: 40px;">/fontPieceToCharTable="phbrqkojntwl"<br>\r
+</div>\r
+<br>\r
+The piece are in order: white pawn, knight, bishop, rook, queen, king\r
+and black pawn, knight, bishop, rook, queen, king. So the example above\r
+tells the program to use the letter "p" for a white pawn, the letter\r
+"h" for a white knight, the letter "t" for a black rook and so on.<br>\r
+<br>\r
+Note: to "comment out" a font name, put an asterisk in front of it,\r
+i.e. "*Chess Merida" will be skipped because of the asterisk.<br>\r
+<br>\r
+It is possible to customize the font foreground and background color,\r
+with these settings:<br>\r
+<br>\r
+<div style="margin-left: 40px;">/fontPieceBackColorWhite=#ffffcc<br>\r
+/fontPieceForeColorWhite=#402010<br>\r
+/fontPieceBackColorBlack=#ffffcc<br>\r
+/fontPieceForeColorBlack=#301008<br>\r
+</div>\r
+<br>\r
+Colors are expressed in RGB notation. If you are not familiar with the\r
+RGB notation&nbsp; I would suggest to leave them alone until I manage\r
+to update the GUI. In this case, the program will take the board\r
+settings as for the usual piece set.<br>\r
+<br>\r
+It is also possible to control the size of the piece with respect to\r
+the square, for example this entry:<br>\r
+<br>\r
+<div style="margin-left: 40px;">/fontPieceSize=80<br>\r
+</div>\r
+<br>\r
+tells the program to make the pieces about 20% smaller than a square\r
+(i.e. the piece size is 80%). Note that different fonts may require\r
+different values for this parameter. Usually values in the 70-80 range\r
+provide the best values, however the program accepts anything from 50\r
+to 150.<br>\r
+<br>\r
+Font-based pieces are automatically given a "roundish" look. For now,\r
+this option is not mapped to a user-definable setting.<br>\r
+<br>\r
+<big><span style="font-weight: bold;">Fast clipboard pasting</span></big><br>\r
+<br>\r
+Press Ctrl-V to paste a PGN game or a FEN position from the clipboard,\r
+the program will try to autodetect the proper type.<br>\r
+<br>\r
+<big><span style="font-weight: bold;">Thread initialization bug</span></big><br>\r
+<br>\r
+I've tried to fix a bug reported (and fixed) by Anastasios Milikas (of\r
+AICE), where a thread could try to access a not yet initialized\r
+variable. I've used a different approach here, where threads are\r
+started in a "suspended" state and then released only when the variable\r
+has been initialized (this has the advantage of putting all the\r
+required fix code in one place, and the disadvantage of not having been\r
+tested by Anastasios).<br>\r
+<br>\r
+<big><span style="font-weight: bold;">Protection from some buffer\r
+overflows</span></big><br>\r
+<br>\r
+In just a few cases, I've tried to put some guard against buffer\r
+overflows. These are just quick attempts... a lot more work would be\r
+needed to provide some measurable benefits. I hope that bug **353 is\r
+finally fixed now. The buffer overflows were propagated across several\r
+functions so as soon as one was fixed another would crash!<br>\r
+<br>\r
+<big><span style="font-weight: bold;">Absolute scores can be converted\r
+to relative</span></big><br>\r
+<br>\r
+Some engines (e.g. Crafty, Delphi) always report scores from the white\r
+side (i.e. absolute), rather than the engine side (i.e. relative). This\r
+leads to confusion and breaks features such as automatic adjudication.\r
+In order to convert the scores to relative add the following to\r
+winboard.ini:<br>\r
+<br>\r
+<div style="margin-left: 40px;">/firstScoreAbs=false<br>\r
+</div>\r
+<br>\r
+If true, the score of the first program is absolute and will be negated\r
+when playing black. And similarly:<br>\r
+<br>\r
+<div style="margin-left: 40px;">/secondScoreAbs=false<br>\r
+</div>\r
+<br>\r
+if true, the score of the second program is absolute and will be\r
+negated when playing black.<br>\r
+<br>\r
+<big><span style="font-weight: bold;">Engine search info can be saved\r
+in a PGN file</span></big><br>\r
+<br>\r
+Add the following to winboard.ini:<br>\r
+<br>\r
+<div style="margin-left: 40px;">/pgnExtendedInfo=true<br>\r
+</div>\r
+<br>\r
+If true, and the PGN save game option is enabled, each move will be\r
+followed by a comment&nbsp; containing the engine score and thinking\r
+depth (when available).<br>\r
+<br>\r
+Note: can also be set from the General options dialog.<br>\r
+<br>\r
+<big><span style="font-weight: bold;">Engine search info can be hidden\r
+in human-computer games</span></big><br>\r
+<br>\r
+When "show thinking" is disabled, engine thinking is not generated at\r
+all, rather than simply hidden. It is now possible to generate the\r
+think lines (e.g. for logging or saving in the PGN) yet hide them when\r
+the engine is playing against a human player. Add the following to\r
+winboard.ini:<br>\r
+<br>\r
+<div style="margin-left: 40px;">/hideThinkingFromHuman=true<br>\r
+</div>\r
+<br>\r
+Note: can also be set from the General options dialog.<br>\r
+<br>\r
+<big><span style="font-weight: bold;">Asymmetric time controls</span></big><br>\r
+<br>\r
+Very experimental! You can enter two time controls in the usual dialog,\r
+separated by "/". If so, white will be assigned the first time and\r
+black the second. So for example "0:30/2:00" will give 30 seconds to\r
+white and 2 minutes to black.<br>\r
+<br>\r
+Note: for now these times stay with black and white, rather than the\r
+corresponding player.<br>\r
+<br>\r
+<big><span style="font-weight: bold;">User interface</span></big><br>\r
+<br>\r
+Options to "hide thinking from human" and "save extended info in PGN"\r
+now appears in the "General" options dialog.<br>\r
+<br>\r
+</body>\r
+</html>\r
index 8da09ae..1f4411b 100644 (file)
 #define IDM_GeneralOptions              1299\r
 #define IDM_BoardOptions                1300\r
 #define IDM_Fonts                       1301\r
+#define IDM_UserAdjudication_White      1302
+#define IDM_UserAdjudication_Black      1303
+#define IDM_UserAdjudication_Draw       1304
 #define PB_King                         1307\r
 #define OPT_Bold                        1312\r
 #define OPT_Italic                      1313\r
 #define OPT_DefaultFonts                1419\r
 #define OPT_AutoRaiseBoard              1421\r
 #define OPT_ShowButtonBar               1422\r
+#define OPT_SaveExtPGN                  1423
+#define OPT_HideThinkFromHuman          1424
 #define IDC_STATIC                      -1\r
 \r
 // Next default values for new objects\r
 #ifndef APSTUDIO_READONLY_SYMBOLS\r
 #define _APS_NO_MFC                     1\r
 #define _APS_NEXT_RESOURCE_VALUE        457\r
-#define _APS_NEXT_COMMAND_VALUE         1302\r
-#define _APS_NEXT_CONTROL_VALUE         1423\r
+#define _APS_NEXT_COMMAND_VALUE         1305
+#define _APS_NEXT_CONTROL_VALUE         1425
 #define _APS_NEXT_SYMED_VALUE           1404\r
 #endif\r
 #endif\r
index 79ff2a2..dbb47a7 100644 (file)
@@ -1,6 +1,6 @@
 /*\r
  * wclipbrd.c -- Clipboard routines for WinBoard\r
- * $Id$\r
+ * $Id: wclipbrd.c,v 2.1 2003/10/27 19:21:02 mann Exp $
  *\r
  * Copyright 2000 Free Software Foundation, Inc.\r
  *\r
@@ -194,6 +194,16 @@ CopyTextToClipboard(char *text)
   return TRUE;\r
 }\r
 \r
+/* [AS] Reworked paste functions so they can work with strings too */
+
+VOID PasteFENFromString( char * fen )
+{
+  if (appData.debugMode) {
+    fprintf(debugFP, "PasteFenFromString(): fen '%s'\n", fen);
+  }
+  EditPositionPasteFEN(fen); /* call into backend */
+  free(fen);
+}
 \r
 \r
 VOID\r
@@ -204,42 +214,68 @@ PasteFENFromClipboard()
       DisplayError("Unable to paste FEN from clipboard.", 0);\r
       return;\r
   }\r
-  if (appData.debugMode) {\r
-    fprintf(debugFP, "PasteFenFromClipboard(): fen '%s'\n", fen);\r
-  }\r
-  EditPositionPasteFEN(fen); /* call into backend */\r
-  free(fen);\r
+  PasteFENFromString( fen );
 }\r
 \r
-\r
-VOID\r
-PasteGameFromClipboard()\r
+VOID PasteGameFromString( char * buf )
 {\r
-  /* Write the clipboard to a temp file, then let LoadGameFromFile()\r
-   * do all the work.  */\r
-  char *buf;\r
   FILE *f;\r
   size_t len;\r
-  if (!PasteTextFromClipboard(&buf)) {\r
-    return;\r
-  }\r
   if (!pasteTemp) {\r
     pasteTemp = tempnam(NULL, "wbpt");\r
   }\r
   f = fopen(pasteTemp, "w");\r
   if (!f) {\r
     DisplayError("Unable to create temporary file.", 0);\r
+    free(buf); /* [AS] */
     return;\r
   }\r
   len = fwrite(buf, sizeof(char), strlen(buf), f);\r
   fclose(f);\r
   if (len != strlen(buf)) {\r
     DisplayError("Error writing to temporary file.", 0);\r
+    free(buf); /* [AS] */
     return;\r
   }\r
   LoadGameFromFile(pasteTemp, 0, "Clipboard", TRUE);\r
+  free( buf ); /* [AS] */
+}
+
+
+VOID
+PasteGameFromClipboard()
+{
+  /* Write the clipboard to a temp file, then let LoadGameFromFile()
+   * do all the work.  */
+  char *buf;
+  if (!PasteTextFromClipboard(&buf)) {
+    return;
+  }
+  PasteGameFromString( buf );
 }\r
 \r
+/* [AS] Try to detect whether the clipboard contains FEN or PGN data */
+VOID PasteGameOrFENFromClipboard()
+{
+  char *buf;
+  char *tmp;
+
+  if (!PasteTextFromClipboard(&buf)) {
+    return;
+  }
+
+  tmp = buf;
+  while( *tmp == ' ' || *tmp == '\t' || *tmp == '\r' || *tmp == '\n' ) {
+      tmp++;
+  }
+
+  if( *tmp == '[' ) {
+      PasteGameFromString( buf );
+  }
+  else {
+      PasteFENFromString( buf );
+  }
+}
 \r
 int \r
 PasteTextFromClipboard(char **text)\r
index c575d8a..03c2a56 100644 (file)
@@ -1,6 +1,6 @@
 /*\r
  * wclipbrd.c -- Clipboard routines for WinBoard\r
- * $Id$\r
+ * $Id: wclipbrd.h,v 2.1 2003/10/27 19:21:02 mann Exp $
  *\r
  * Copyright 2000 Free Software Foundation, Inc.\r
  *\r
@@ -30,3 +30,5 @@ VOID PasteGameFromClipboard();
 int PasteTextFromClipboard(char **text);\r
 \r
 VOID DeleteClipboardTempFiles();\r
+
+VOID PasteGameOrFENFromClipboard(); /* [AS] */
index 7bd3de0..2ad3bcf 100644 (file)
@@ -1,6 +1,6 @@
 /* \r
  * WinBoard.c -- Windows NT front end to XBoard\r
- * $Id$\r
+ * $Id: winboard.c,v 2.3 2003/11/25 05:25:20 mann Exp $
  *\r
  * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts.\r
  * Enhancements Copyright 1992-2001 Free Software Foundation, Inc.\r
@@ -57,6 +57,7 @@
 \r
 #include <stdio.h>\r
 #include <stdlib.h>\r
+#include <time.h>
 #include <malloc.h>\r
 #include <sys/stat.h>\r
 #include <fcntl.h>\r
@@ -83,6 +84,9 @@
 #include "wsockerr.h"\r
 #include "defaults.h"\r
 \r
+int myrandom(void);
+void mysrandom(unsigned int seed);
+
 typedef struct {\r
   ChessSquare piece;  \r
   POINT pos;      /* window coordinates of current pos */\r
@@ -140,7 +144,7 @@ char *icsNames;
 char *firstChessProgramNames;\r
 char *secondChessProgramNames;\r
 \r
-#define ARG_MAX 20000\r
+#define ARG_MAX 64*1024 /* [AS] For Roger Brown's very long list! */
 \r
 #define PALETTESIZE 256\r
 \r
@@ -171,6 +175,18 @@ static int doingSizing = FALSE;
 static int lastSizing = 0;\r
 static int prevStderrPort;\r
 \r
+/* [AS] Support for background textures */
+#define BACK_TEXTURE_MODE_DISABLED      0
+#define BACK_TEXTURE_MODE_PLAIN         1
+#define BACK_TEXTURE_MODE_FULL_RANDOM   2
+
+static HBITMAP liteBackTexture = NULL;
+static HBITMAP darkBackTexture = NULL;
+static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
+static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
+static int backTextureSquareSize = 0;
+static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];
+
 #if __GNUC__ && !defined(_winmajor)\r
 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */\r
 #else\r
@@ -557,7 +573,7 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
   }\r
   InitAppData(lpCmdLine);      /* Get run-time parameters */\r
   if (appData.debugMode) {\r
-    debugFP = fopen("winboard.debug", "w");\r
+    debugFP = fopen(appData.nameOfDebugFile, "w");
     setbuf(debugFP, NULL);\r
   }\r
 \r
@@ -594,6 +610,29 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
   InitMenuChecks();\r
   buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);\r
 \r
+  /* [AS] Load textures if specified */
+  ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
+
+  if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
+      liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
+      liteBackTextureMode = appData.liteBackTextureMode;
+
+      if (liteBackTexture == NULL && appData.debugMode) {
+          fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
+      }
+  }
+
+  if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
+      darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
+      darkBackTextureMode = appData.darkBackTextureMode;
+
+      if (darkBackTexture == NULL && appData.debugMode) {
+          fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
+      }
+  }
+
+  mysrandom( (unsigned) time(NULL) );
+
   /* Make a console window if needed */\r
   if (appData.icsActive) {\r
     ConsoleCreate();\r
@@ -1005,14 +1044,35 @@ ArgDescriptor argDescriptors[] = {
   { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },\r
   { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },\r
   { "variant", ArgString, (LPVOID) &appData.variant, FALSE },\r
-  { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion,\r
-    FALSE },\r
-  { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,\r
-    FALSE },\r
+  { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
+  { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
   { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },\r
   { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },\r
   { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },\r
   { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },\r
+  /* [AS] New features */
+  { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, TRUE },
+  { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, TRUE },
+  { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
+  { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
+  { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
+  { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
+  { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
+  { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
+  { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
+  { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
+  { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
+  { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
+  { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
+  { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
+  { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
+  { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
+  { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
+  { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
+  { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
+  { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
+  { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
+  { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
 #ifdef ZIPPY\r
   { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },\r
   { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },\r
@@ -1667,6 +1727,30 @@ InitAppData(LPSTR lpCmdLine)
   appData.firstProtocolVersion = PROTOVER;\r
   appData.secondProtocolVersion = PROTOVER;\r
   appData.showButtonBar = TRUE;\r
+
+   /* [AS] New properties (see comments in header file) */
+  appData.firstScoreIsAbsolute = FALSE;
+  appData.secondScoreIsAbsolute = FALSE;
+  appData.saveExtendedInfoInPGN = FALSE;
+  appData.hideThinkingFromHuman = FALSE;
+  appData.liteBackTextureFile = "";
+  appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
+  appData.darkBackTextureFile = "";
+  appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
+  appData.renderPiecesWithFont = "";
+  appData.fontToPieceTable = "";
+  appData.fontBackColorWhite = 0;
+  appData.fontForeColorWhite = 0;
+  appData.fontBackColorBlack = 0;
+  appData.fontForeColorBlack = 0;
+  appData.fontPieceSize = 80;
+  appData.overrideLineGap = 1;
+  appData.adjudicateLossThreshold = 0;
+  appData.delayBeforeQuit = 0;
+  appData.delayAfterQuit = 0;
+  appData.nameOfDebugFile = "winboard.debug";
+  appData.pgnEventHeader = "Computer Chess Game";
+
 #ifdef ZIPPY\r
   appData.zippyTalk = ZIPPY_TALK;\r
   appData.zippyPlay = ZIPPY_PLAY;\r
@@ -1961,6 +2045,431 @@ SaveSettings(char* name)
  *\r
 \*---------------------------------------------------------------------------*/\r
 \r
+/* [AS] Draw square using background texture */
+static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
+{
+    XFORM   x;
+
+    if( mode == 0 ) {
+        return; /* Should never happen! */
+    }
+
+    SetGraphicsMode( dst, GM_ADVANCED );
+
+    switch( mode ) {
+    case 1:
+        /* Identity */
+        break;
+    case 2:
+        /* X reflection */
+        x.eM11 = -1.0;
+        x.eM12 = 0;
+        x.eM21 = 0;
+        x.eM22 = 1.0;
+        x.eDx = (FLOAT) dw + dx - 1;
+        x.eDy = 0;
+        dx = 0;
+        SetWorldTransform( dst, &x );
+        break;
+    case 3:
+        /* Y reflection */
+        x.eM11 = 1.0;
+        x.eM12 = 0;
+        x.eM21 = 0;
+        x.eM22 = -1.0;
+        x.eDx = 0;
+        x.eDy = (FLOAT) dh + dy - 1;
+        dy = 0;
+        SetWorldTransform( dst, &x );
+        break;
+    case 4:
+        /* X/Y flip */
+        x.eM11 = 0;
+        x.eM12 = 1.0;
+        x.eM21 = 1.0;
+        x.eM22 = 0;
+        x.eDx = (FLOAT) dx;
+        x.eDy = (FLOAT) dy;
+        dx = 0;
+        dy = 0;
+        SetWorldTransform( dst, &x );
+        break;
+    }
+
+    BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
+
+    x.eM11 = 1.0;
+    x.eM12 = 0;
+    x.eM21 = 0;
+    x.eM22 = 1.0;
+    x.eDx = 0;
+    x.eDy = 0;
+    SetWorldTransform( dst, &x );
+
+    ModifyWorldTransform( dst, 0, MWT_IDENTITY );
+}
+
+/* [AS] */
+enum {
+    PM_WP = 0,
+    PM_WN = 1,
+    PM_WB = 2,
+    PM_WR = 3,
+    PM_WQ = 4,
+    PM_WK = 5,
+    PM_BP = 6,
+    PM_BN = 7,
+    PM_BB = 8,
+    PM_BR = 9,
+    PM_BQ = 10,
+    PM_BK = 11
+};
+
+static HFONT hPieceFont = NULL;
+static HBITMAP hPieceMask[12];
+static HBITMAP hPieceFace[12];
+static int fontBitmapSquareSize = 0;
+static char pieceToFontChar[12] = { 'p', 'n', 'b', 'r', 'q', 'k', 'o', 'm', 'v', 't', 'w', 'l' };
+
+static BOOL SetPieceToFontCharTable( const char * map )
+{
+    BOOL result = FALSE;
+
+    if( map != NULL && strlen(map) == 12 ) {
+        int i;
+
+        for( i=0; i<12; i++ ) {
+            pieceToFontChar[i] = map[i];
+        }
+
+        result = TRUE;
+    }
+
+    return result;
+}
+
+static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
+{
+    HBRUSH hbrush;
+    BYTE r1 = GetRValue( color );
+    BYTE g1 = GetGValue( color );
+    BYTE b1 = GetBValue( color );
+    BYTE r2 = r1 / 2;
+    BYTE g2 = g1 / 2;
+    BYTE b2 = b1 / 2;
+    RECT rc;
+
+    /* Create a uniform background first */
+    hbrush = CreateSolidBrush( color );
+    SetRect( &rc, 0, 0, squareSize, squareSize );
+    FillRect( hdc, &rc, hbrush );
+    DeleteObject( hbrush );
+
+    if( mode == 1 ) {
+        /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
+        int steps = squareSize / 2;
+        int i;
+
+        for( i=0; i<steps; i++ ) {
+            BYTE r = r1 - (r1-r2) * i / steps;
+            BYTE g = g1 - (g1-g2) * i / steps;
+            BYTE b = b1 - (b1-b2) * i / steps;
+
+            hbrush = CreateSolidBrush( RGB(r,g,b) );
+            SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
+            FillRect( hdc, &rc, hbrush );
+            DeleteObject(hbrush);
+        }
+    }
+    else if( mode == 2 ) {
+        /* Diagonal gradient, good more or less for every piece */
+        POINT triangle[3];
+        HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
+        HBRUSH hbrush_old;
+        int steps = squareSize;
+        int i;
+
+        triangle[0].x = squareSize - steps;
+        triangle[0].y = squareSize;
+        triangle[1].x = squareSize;
+        triangle[1].y = squareSize;
+        triangle[2].x = squareSize;
+        triangle[2].y = squareSize - steps;
+
+        for( i=0; i<steps; i++ ) {
+            BYTE r = r1 - (r1-r2) * i / steps;
+            BYTE g = g1 - (g1-g2) * i / steps;
+            BYTE b = b1 - (b1-b2) * i / steps;
+
+            hbrush = CreateSolidBrush( RGB(r,g,b) );
+            hbrush_old = SelectObject( hdc, hbrush );
+            Polygon( hdc, triangle, 3 );
+            SelectObject( hdc, hbrush_old );
+            DeleteObject(hbrush);
+            triangle[0].x++;
+            triangle[2].y++;
+        }
+
+        SelectObject( hdc, hpen );
+    }
+}
+
+/*
+    [AS] The method I use to create the bitmaps it a bit tricky, but it
+    seems to work ok. The main problem here is to find the "inside" of a chess
+    piece: follow the steps as explained below.
+*/
+static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
+{
+    HBITMAP hbm;
+    HBITMAP hbm_old;
+    COLORREF chroma = RGB(0xFF,0x00,0xFF);
+    RECT rc;
+    SIZE sz;
+    POINT pt;
+    int backColor = whitePieceColor;
+    int foreColor = blackPieceColor;
+    int shapeIndex = index < 6 ? index+6 : index;
+
+    if( index < 6 && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
+        backColor = appData.fontBackColorWhite;
+        foreColor = appData.fontForeColorWhite;
+    }
+    else if( index >= 6 && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
+        backColor = appData.fontBackColorBlack;
+        foreColor = appData.fontForeColorBlack;
+    }
+
+    /* Mask */
+    hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
+
+    hbm_old = SelectObject( hdc, hbm );
+
+    rc.left = 0;
+    rc.top = 0;
+    rc.right = squareSize;
+    rc.bottom = squareSize;
+
+    /* Step 1: background is now black */
+    FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
+
+    GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
+
+    pt.x = (squareSize - sz.cx) / 2;
+    pt.y = (squareSize - sz.cy) / 2;
+
+    SetBkMode( hdc, TRANSPARENT );
+    SetTextColor( hdc, chroma );
+    /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
+    TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
+
+    SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
+    /* Step 3: the area outside the piece is filled with white */
+    FloodFill( hdc, 0, 0, chroma );
+    SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
+    /*
+        Step 4: this is the tricky part, the area inside the piece is filled with black,
+        but if the start point is not inside the piece we're lost!
+        There should be a better way to do this... if we could create a region or path
+        from the fill operation we would be fine for example.
+    */
+    FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
+
+    SetTextColor( hdc, 0 );
+    /*
+        Step 5: some fonts have "disconnected" areas that are skipped by the fill:
+        draw the piece again in black for safety.
+    */
+    TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
+
+    SelectObject( hdc, hbm_old );
+
+    if( hPieceMask[index] != NULL ) {
+        DeleteObject( hPieceMask[index] );
+    }
+
+    hPieceMask[index] = hbm;
+
+    /* Face */
+    hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
+
+    SelectObject( hdc, hbm );
+
+    {
+        HDC dc1 = CreateCompatibleDC( hdc_window );
+        HDC dc2 = CreateCompatibleDC( hdc_window );
+        HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
+
+        SelectObject( dc1, hPieceMask[index] );
+        SelectObject( dc2, bm2 );
+        FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
+        BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
+
+        /*
+            Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
+            the piece background and deletes (makes transparent) the rest.
+            Thanks to that mask, we are free to paint the background with the greates
+            freedom, as we'll be able to mask off the unwanted parts when finished.
+            We use this, to make gradients and give the pieces a "roundish" look.
+        */
+        SetPieceBackground( hdc, backColor, 2 );
+        BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
+
+        DeleteDC( dc2 );
+        DeleteDC( dc1 );
+        DeleteObject( bm2 );
+    }
+
+    SetTextColor( hdc, foreColor );
+    TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
+
+    SelectObject( hdc, hbm_old );
+
+    hPieceFace[index] = hbm;
+}
+
+static int TranslatePieceToFontPiece( int piece )
+{
+    switch( piece ) {
+    case BlackPawn:
+        return PM_BP;
+    case BlackKnight:
+        return PM_BN;
+    case BlackBishop:
+        return PM_BB;
+    case BlackRook:
+        return PM_BR;
+    case BlackQueen:
+        return PM_BQ;
+    case BlackKing:
+        return PM_BK;
+    case WhitePawn:
+        return PM_WP;
+    case WhiteKnight:
+        return PM_WN;
+    case WhiteBishop:
+        return PM_WB;
+    case WhiteRook:
+        return PM_WR;
+    case WhiteQueen:
+        return PM_WQ;
+    case WhiteKing:
+        return PM_WK;
+    }
+
+    return 0;
+}
+
+void CreatePiecesFromFont()
+{
+    LOGFONT lf;
+    HDC hdc_window = NULL;
+    HDC hdc = NULL;
+    HFONT hfont_old;
+    int fontHeight;
+    int i;
+
+    if( fontBitmapSquareSize < 0 ) {
+        /* Something went seriously wrong in the past: do not try to recreate fonts! */
+        return;
+    }
+
+    if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
+        fontBitmapSquareSize = -1;
+        return;
+    }
+
+    if( fontBitmapSquareSize != squareSize ) {
+        hdc_window = GetDC( hwndMain );
+        hdc = CreateCompatibleDC( hdc_window );
+
+        if( hPieceFont != NULL ) {
+            DeleteObject( hPieceFont );
+        }
+        else {
+            for( i=0; i<12; i++ ) {
+                hPieceMask[i] = NULL;
+            }
+        }
+
+        fontHeight = 75;
+
+        if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
+            fontHeight = appData.fontPieceSize;
+        }
+
+        fontHeight = (fontHeight * squareSize) / 100;
+
+        lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
+        lf.lfWidth = 0;
+        lf.lfEscapement = 0;
+        lf.lfOrientation = 0;
+        lf.lfWeight = FW_NORMAL;
+        lf.lfItalic = 0;
+        lf.lfUnderline = 0;
+        lf.lfStrikeOut = 0;
+        lf.lfCharSet = DEFAULT_CHARSET;
+        lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
+        lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
+        lf.lfQuality = PROOF_QUALITY;
+        lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+        strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
+        lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
+
+        hPieceFont = CreateFontIndirect( &lf );
+
+        if( hPieceFont == NULL ) {
+            fontBitmapSquareSize = -2;
+        }
+        else {
+            /* Setup font-to-piece character table */
+            if( ! SetPieceToFontCharTable(appData.fontToPieceTable) ) {
+                /* No (or wrong) global settings, try to detect the font */
+                if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
+                    /* Alpha */
+                    SetPieceToFontCharTable("phbrqkojntwl");
+                }
+                else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
+                    /* DiagramTT* family */
+                    SetPieceToFontCharTable("PNLRQKpnlrqk");
+                }
+                else {
+                    /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
+                    SetPieceToFontCharTable("pnbrqkomvtwl");
+                }
+            }
+
+            /* Create bitmaps */
+            hfont_old = SelectObject( hdc, hPieceFont );
+
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
+
+            SelectObject( hdc, hfont_old );
+
+            fontBitmapSquareSize = squareSize;
+        }
+    }
+
+    if( hdc != NULL ) {
+        DeleteDC( hdc );
+    }
+
+    if( hdc_window != NULL ) {
+        ReleaseDC( hwndMain, hdc_window );
+    }
+}
+
 HBITMAP\r
 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)\r
 {\r
@@ -2032,13 +2541,24 @@ InitDrawingColors()
   whitePieceBrush = CreateSolidBrush(whitePieceColor);\r
   blackPieceBrush = CreateSolidBrush(blackPieceColor);\r
   iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));\r
+
+  /* [AS] Force rendering of the font-based pieces */
+  if( fontBitmapSquareSize > 0 ) {
+    fontBitmapSquareSize = 0;
+  }
 }\r
 \r
 \r
 int\r
 BoardWidth(int boardSize)\r
 {\r
-  return (BOARD_SIZE + 1) * sizeInfo[boardSize].lineGap +\r
+  int lineGap = sizeInfo[boardSize].lineGap;
+
+  if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
+      lineGap = appData.overrideLineGap;
+  }
+
+  return (BOARD_SIZE + 1) * lineGap +
          BOARD_SIZE * sizeInfo[boardSize].squareSize;\r
 }\r
 \r
@@ -2084,6 +2604,10 @@ InitDrawingSizes(BoardSize boardSize, int flags)
   squareSize = sizeInfo[boardSize].squareSize;\r
   lineGap = sizeInfo[boardSize].lineGap;\r
 \r
+  if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
+      lineGap = appData.overrideLineGap;
+  }
+
   if (tinyLayout != oldTinyLayout) {\r
     long style = GetWindowLong(hwndMain, GWL_STYLE);\r
     if (tinyLayout) {\r
@@ -2430,6 +2954,36 @@ DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y,
 \r
   if (appData.blindfold) return;\r
 \r
+  /* [AS] Use font-based pieces if needed */
+  if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
+    /* Create piece bitmaps, or do nothing if piece set is up to data */
+    CreatePiecesFromFont();
+
+    if( fontBitmapSquareSize == squareSize ) {
+        int index = TranslatePieceToFontPiece( piece );
+
+        SelectObject( tmphdc, hPieceMask[ index ] );
+
+        BitBlt( hdc,
+            x, y,
+            squareSize, squareSize,
+            tmphdc,
+            0, 0,
+            SRCAND );
+
+        SelectObject( tmphdc, hPieceFace[ index ] );
+
+        BitBlt( hdc,
+            x, y,
+            squareSize, squareSize,
+            tmphdc,
+            0, 0,
+            SRCPAINT );
+
+        return;
+    }
+  }
+
   if (appData.monoMode) {\r
     SelectObject(tmphdc, PieceBitmap(piece, \r
       color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));\r
@@ -2477,12 +3031,93 @@ DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y,
   }\r
 }\r
 \r
+/* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
+int GetBackTextureMode( int algo )
+{
+    int result = BACK_TEXTURE_MODE_DISABLED;
+
+    switch( algo )
+    {
+        case BACK_TEXTURE_MODE_PLAIN:
+            result = 1; /* Always use identity map */
+            break;
+        case BACK_TEXTURE_MODE_FULL_RANDOM:
+            result = 1 + (myrandom() % 3); /* Pick a transformation at random */
+            break;
+    }
+
+    return result;
+}
+
+/*
+    [AS] Compute and save texture drawing info, otherwise we may not be able
+    to handle redraws cleanly (as random numbers would always be different).
+*/
+VOID RebuildTextureSquareInfo()
+{
+    BITMAP bi;
+    int lite_w = 0;
+    int lite_h = 0;
+    int dark_w = 0;
+    int dark_h = 0;
+    int row;
+    int col;
+
+    ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
+
+    if( liteBackTexture != NULL ) {
+        if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
+            lite_w = bi.bmWidth;
+            lite_h = bi.bmHeight;
+        }
+    }
+
+    if( darkBackTexture != NULL ) {
+        if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
+            dark_w = bi.bmWidth;
+            dark_h = bi.bmHeight;
+        }
+    }
+
+    for( row=0; row<BOARD_SIZE; row++ ) {
+        for( col=0; col<BOARD_SIZE; col++ ) {
+            if( (col + row) & 1 ) {
+                /* Lite square */
+                if( lite_w >= squareSize && lite_h >= squareSize ) {
+                    backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / BOARD_SIZE;
+                    backTextureSquareInfo[row][col].y = row * (lite_h - squareSize) / BOARD_SIZE;
+                    backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
+                }
+            }
+            else {
+                /* Dark square */
+                if( dark_w >= squareSize && dark_h >= squareSize ) {
+                    backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / BOARD_SIZE;
+                    backTextureSquareInfo[row][col].y = row * (dark_h - squareSize) / BOARD_SIZE;
+                    backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
+                }
+            }
+        }
+    }
+}
+
 VOID\r
 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)\r
 {\r
   int row, column, x, y, square_color, piece_color;\r
   ChessSquare piece;\r
   HBRUSH oldBrush;\r
+  HDC texture_hdc = NULL;
+
+  /* [AS] Initialize background textures if needed */
+  if( liteBackTexture != NULL || darkBackTexture != NULL ) {
+      if( backTextureSquareSize != squareSize ) {
+          backTextureSquareSize = squareSize;
+          RebuildTextureSquareInfo();
+      }
+
+      texture_hdc = CreateCompatibleDC( hdc );
+  }
 \r
   for (row = 0; row < BOARD_SIZE; row++) {\r
     for (column = 0; column < BOARD_SIZE; column++) {\r
@@ -2501,7 +3136,26 @@ DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
         } else {\r
           DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);\r
         }\r
-      } else {\r
+      }
+      else if( backTextureSquareInfo[row][column].mode > 0 ) {
+          /* [AS] Draw the square using a texture bitmap */
+          HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
+
+          DrawTile( x, y,
+              squareSize, squareSize,
+              hdc,
+              texture_hdc,
+              backTextureSquareInfo[row][column].mode,
+              backTextureSquareInfo[row][column].x,
+              backTextureSquareInfo[row][column].y );
+
+          SelectObject( texture_hdc, hbm );
+
+          if (piece != EmptySquare) {
+              DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
+          }
+      }
+      else {
         oldBrush = SelectObject(hdc, square_color ?\r
                                lightSquareBrush : darkSquareBrush);\r
         BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);\r
@@ -2511,6 +3165,10 @@ DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
       }\r
     }\r
   }\r
+
+  if( texture_hdc != NULL ) {
+    DeleteDC( texture_hdc );
+  }
 }\r
 \r
 #define MAX_CLIPS 200   /* more than enough */\r
@@ -3559,6 +4217,24 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       PasteGameFromClipboard();\r
       break;\r
 \r
+    /* [AS] Autodetect FEN or PGN data */
+    case IDM_Paste:
+      PasteGameOrFENFromClipboard();
+      break;
+
+    /* [AS] User adjudication */
+    case IDM_UserAdjudication_White:
+        UserAdjudicationEvent( +1 );
+        break;
+
+    case IDM_UserAdjudication_Black:
+        UserAdjudicationEvent( -1 );
+        break;
+
+    case IDM_UserAdjudication_Draw:
+        UserAdjudicationEvent( 0 );
+        break;
+
     case IDM_CopyPosition:\r
       CopyFENToClipboard();\r
       break;\r
@@ -3833,7 +4509,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
        char dir[MSG_SIZ];\r
        GetCurrentDirectory(MSG_SIZ, dir);\r
        SetCurrentDirectory(installDir);\r
-       debugFP = fopen("WinBoard.debug", "w");\r
+       debugFP = fopen(appData.nameOfDebugFile, "w");
         SetCurrentDirectory(dir);\r
         setbuf(debugFP, NULL);\r
       } else {\r
@@ -4620,13 +5296,17 @@ StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
       SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);\r
       SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);\r
     }\r
-    if (chessProgram) {\r
-      CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);\r
-    } else if (appData.icsActive) {\r
+
+    if (appData.icsActive) {
       CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);\r
-    } else if (appData.noChessProgram) {\r
+    }
+    else if (appData.noChessProgram) {
       CheckDlgButton(hDlg, OPT_View, BST_CHECKED);\r
     }\r
+    else {
+      CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
+    }
+
     SetStartupDialogEnables(hDlg);\r
     return TRUE;\r
 \r
@@ -5827,6 +6507,28 @@ DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
   return err;\r
 }\r
 \r
+/* [AS] If input is line by line and a line exceed the buffer size, force an error */
+void CheckForInputBufferFull( InputSource * is )
+{
+    if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
+        /* Look for end of line */
+        char * p = is->buf;
+
+        while( p < is->next && *p != '\n' ) {
+            p++;
+        }
+
+        if( p >= is->next ) {
+            if (appData.debugMode) {
+                fprintf( debugFP, "Input line exceeded buffer size (source id=%u)\n", is->id );
+            }
+
+            is->error = ERROR_BROKEN_PIPE; /* [AS] Just a non-successful code! */
+            is->count = (DWORD) -2;
+            is->next = is->buf;
+        }
+    }
+}
 \r
 DWORD\r
 InputThread(LPVOID arg)\r
@@ -5851,6 +6553,9 @@ InputThread(LPVOID arg)
        is->count = (DWORD) -1;\r
       }\r
     }\r
+
+    CheckForInputBufferFull( is );
+
     SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);\r
     if (is->count <= 0) break;  /* Quit on EOF or error */\r
   }\r
@@ -5905,6 +6610,9 @@ NonOvlInputThread(LPVOID arg)
        is->count = (DWORD) -1;\r
       }\r
     }\r
+
+    CheckForInputBufferFull( is );
+
     SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);\r
     if (is->count < 0) break;  /* Quit on error */\r
   }\r
@@ -5953,12 +6661,14 @@ InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
        p = q;\r
       }\r
     }\r
+
     /* Move any partial line to the start of the buffer */\r
     q = is->buf;\r
     while (p < is->next) {\r
       *q++ = *p++;\r
     }\r
     is->next = q;\r
+
     if (is->error != NO_ERROR || is->count == 0) {\r
       /* Notify backend of the error.  Note: If there was a partial\r
         line at the end, it is not flushed through. */\r
@@ -6354,10 +7064,8 @@ DisplayMessage(char *str1, char *str2)
 VOID\r
 DisplayError(char *str, int error)\r
 {\r
-  FARPROC lpProc;\r
   char buf[MSG_SIZ*2], buf2[MSG_SIZ];\r
   int len;\r
-  char *p, *q;\r
 \r
   if (error == 0) {\r
     strcpy(buf, str);\r
@@ -6958,6 +7666,27 @@ DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
        we could arrange for this even though neither WinBoard\r
        nor the chess program uses a console for stdio? */\r
     /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/\r
+
+    /* [AS] Special termination modes for misbehaving programs... */
+    if( signal == 9 ) {
+        if ( appData.debugMode) {
+            fprintf( debugFP, "Terminating process %u\n", cp->pid );
+        }
+
+        TerminateProcess( cp->hProcess, 0 );
+    }
+    else if( signal == 10 ) {
+        DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
+
+        if( dw != WAIT_OBJECT_0 ) {
+            if ( appData.debugMode) {
+                fprintf( debugFP, "Process %u still alive after timeout, killing...\n", cp->pid );
+            }
+
+            TerminateProcess( cp->hProcess, 0 );
+        }
+    }
+
     CloseHandle(cp->hProcess);\r
     break;\r
 \r
@@ -7344,7 +8073,7 @@ InputSourceRef
 AddInputSource(ProcRef pr, int lineByLine,\r
               InputCallback func, VOIDSTAR closure)\r
 {\r
-  InputSource *is, *is2;\r
+  InputSource *is, *is2 = NULL;
   ChildProc *cp = (ChildProc *) pr;\r
 \r
   is = (InputSource *) calloc(1, sizeof(InputSource));\r
@@ -7358,13 +8087,18 @@ AddInputSource(ProcRef pr, int lineByLine,
     consoleInputSource = is;\r
   } else {\r
     is->kind = cp->kind;\r
+    /*
+        [AS] Try to avoid a race condition if the thread is given control too early:
+        we create all threads suspended to that the is->hThread variable can be
+        safely assigned, then let the threads start with ResumeThread.
+    */
     switch (cp->kind) {\r
     case CPReal:\r
       is->hFile = cp->hFrom;\r
       cp->hFrom = NULL; /* now owned by InputThread */\r
       is->hThread =\r
        CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,\r
-                    (LPVOID) is, 0, &is->id);\r
+                    (LPVOID) is, CREATE_SUSPENDED, &is->id);
       break;\r
 \r
     case CPComm:\r
@@ -7372,14 +8106,14 @@ AddInputSource(ProcRef pr, int lineByLine,
       cp->hFrom = NULL; /* now owned by InputThread */\r
       is->hThread =\r
        CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,\r
-                    (LPVOID) is, 0, &is->id);\r
+                    (LPVOID) is, CREATE_SUSPENDED, &is->id);
       break;\r
 \r
     case CPSock:\r
       is->sock = cp->sock;\r
       is->hThread =\r
        CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,\r
-                    (LPVOID) is, 0, &is->id);\r
+                    (LPVOID) is, CREATE_SUSPENDED, &is->id);
       break;\r
 \r
     case CPRcmd:\r
@@ -7391,13 +8125,22 @@ AddInputSource(ProcRef pr, int lineByLine,
       is2->second = is2;\r
       is->hThread =\r
        CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,\r
-                    (LPVOID) is, 0, &is->id);\r
+                    (LPVOID) is, CREATE_SUSPENDED, &is->id);
       is2->hThread =\r
        CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,\r
-                    (LPVOID) is2, 0, &is2->id);\r
+                    (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
       break;\r
     }\r
+
+    if( is->hThread != NULL ) {
+        ResumeThread( is->hThread );
   }\r
+
+    if( is2 != NULL && is2->hThread != NULL ) {
+        ResumeThread( is2->hThread );
+    }
+  }
+
   return (InputSourceRef) is;\r
 }\r
 \r
diff --git a/winboard/winboard.ini b/winboard/winboard.ini
new file mode 100644 (file)
index 0000000..5e2eb0a
--- /dev/null
@@ -0,0 +1,266 @@
+;
+; WinBoard 4.2.7 Save Settings file
+;
+; You can edit the values of options that are already set in this file,
+; but if you add other options, the next Save Settings will not save them.
+; Use a shortcut, an @indirection file, or a .bat file instead.
+;
+/whitePieceColor=#ffffcc
+/blackPieceColor=#202020
+/lightSquareColor=#c8c365
+/darkSquareColor=#77a26d
+/highlightSquareColor=#ffff00
+/premoveHighlightColor=#ff0000
+/movesPerSession=40
+/timeDelay=1
+/timeControl="5"
+/timeIncrement=-1
+/saveGameFile=""
+/autoSaveGames=false
+/monoMode=false
+/showCoords=false
+/showThinking=false
+/ponderNextMove=true
+/periodicUpdates=true
+/popupExitMessage=true
+/popupMoveErrors=false
+/size=tiny /clockFont="Arial:9 b"
+/size=teeny /clockFont="Arial:9 b"
+/size=dinky /clockFont="Arial:10 b"
+/size=petite /clockFont="Arial:10 b"
+/size=slim /clockFont="Arial:12 b"
+/size=small /clockFont="Arial:14 b"
+/size=mediocre /clockFont="Arial:14 b"
+/size=middling /clockFont="Arial:14 b"
+/size=average /clockFont="Arial:15 b"
+/size=moderate /clockFont="Arial:16 b"
+/size=medium /clockFont="Arial:16 b"
+/size=bulky /clockFont="Arial:17 b"
+/size=large /clockFont="Arial:19 b"
+/size=big /clockFont="Arial:20 b"
+/size=huge /clockFont="Arial:21 b"
+/size=giant /clockFont="Arial:22 b"
+/size=colossal /clockFont="Arial:23 b"
+/size=titanic /clockFont="Arial:24 b"
+/size=tiny /messageFont="Small Fonts:6"
+/size=teeny /messageFont="Small Fonts:6"
+/size=dinky /messageFont="Small Fonts:7"
+/size=petite /messageFont="Small Fonts:7"
+/size=slim /messageFont="Arial:8 b"
+/size=small /messageFont="Arial:9 b"
+/size=mediocre /messageFont="Arial:9 b"
+/size=middling /messageFont="Arial:9 b"
+/size=average /messageFont="Arial:10 b"
+/size=moderate /messageFont="Arial:10 b"
+/size=medium /messageFont="Arial:10 b"
+/size=bulky /messageFont="Arial:10 b"
+/size=large /messageFont="Arial:10 b"
+/size=big /messageFont="Arial:11 b"
+/size=huge /messageFont="Arial:11 b"
+/size=giant /messageFont="Arial:11 b"
+/size=colossal /messageFont="Arial:12 b"
+/size=titanic /messageFont="Arial:12 b"
+/size=tiny /coordFont="Small Fonts:4"
+/size=teeny /coordFont="Small Fonts:4"
+/size=dinky /coordFont="Small Fonts:5"
+/size=petite /coordFont="Small Fonts:5"
+/size=slim /coordFont="Small Fonts:6"
+/size=small /coordFont="Small Fonts:7"
+/size=mediocre /coordFont="Small Fonts:7"
+/size=middling /coordFont="Small Fonts:7"
+/size=average /coordFont="Arial:7 b"
+/size=moderate /coordFont="Arial:7 b"
+/size=medium /coordFont="Arial:7 b"
+/size=bulky /coordFont="Arial:7 b"
+/size=large /coordFont="Arial:7 b"
+/size=big /coordFont="Arial:8 b"
+/size=huge /coordFont="Arial:8 b"
+/size=giant /coordFont="Arial:8 b"
+/size=colossal /coordFont="Arial:9 b"
+/size=titanic /coordFont="Arial:9 b"
+/size=tiny /tagsFont="Courier New:8"
+/size=teeny /tagsFont="Courier New:8"
+/size=dinky /tagsFont="Courier New:8"
+/size=petite /tagsFont="Courier New:8"
+/size=slim /tagsFont="Courier New:8"
+/size=small /tagsFont="Courier New:8"
+/size=mediocre /tagsFont="Courier New:8"
+/size=middling /tagsFont="Courier New:8"
+/size=average /tagsFont="Courier New:8"
+/size=moderate /tagsFont="Courier New:8"
+/size=medium /tagsFont="Courier New:8"
+/size=bulky /tagsFont="Courier New:8"
+/size=large /tagsFont="Courier New:8"
+/size=big /tagsFont="Courier New:8"
+/size=huge /tagsFont="Courier New:8"
+/size=giant /tagsFont="Courier New:8"
+/size=colossal /tagsFont="Courier New:8"
+/size=titanic /tagsFont="Courier New:8"
+/size=tiny /commentFont="Arial:9"
+/size=teeny /commentFont="Arial:9"
+/size=dinky /commentFont="Arial:9"
+/size=petite /commentFont="Arial:9"
+/size=slim /commentFont="Arial:9"
+/size=small /commentFont="Arial:9"
+/size=mediocre /commentFont="Arial:9"
+/size=middling /commentFont="Arial:9"
+/size=average /commentFont="Arial:9"
+/size=moderate /commentFont="Arial:9"
+/size=medium /commentFont="Arial:9"
+/size=bulky /commentFont="Arial:9"
+/size=large /commentFont="Arial:9"
+/size=big /commentFont="Arial:9"
+/size=huge /commentFont="Arial:9"
+/size=giant /commentFont="Arial:9"
+/size=colossal /commentFont="Arial:9"
+/size=titanic /commentFont="Arial:9"
+/size=tiny /icsFont="Courier New:8"
+/size=teeny /icsFont="Courier New:8"
+/size=dinky /icsFont="Courier New:8"
+/size=petite /icsFont="Courier New:8"
+/size=slim /icsFont="Courier New:8"
+/size=small /icsFont="Courier New:8"
+/size=mediocre /icsFont="Courier New:8"
+/size=middling /icsFont="Courier New:8"
+/size=average /icsFont="Courier New:8"
+/size=moderate /icsFont="Courier New:8"
+/size=medium /icsFont="Courier New:8"
+/size=bulky /icsFont="Courier New:8"
+/size=large /icsFont="Courier New:8"
+/size=big /icsFont="Courier New:8"
+/size=huge /icsFont="Courier New:8"
+/size=giant /icsFont="Courier New:8"
+/size=colossal /icsFont="Courier New:8"
+/size=titanic /icsFont="Courier New:8"
+/boardSize=giant
+/alwaysOnTop=false
+/autoCallFlag=false
+/autoComment=false
+/autoObserve=false
+/autoFlipView=true
+/autoRaiseBoard=true
+/alwaysPromoteToQueen=false
+/oldSaveStyle=false
+/quietPlay=false
+/getMoveList=true
+/testLegality=true
+/premove=true
+/premoveWhite=false
+/premoveWhiteText=""
+/premoveBlack=false
+/premoveBlackText=""
+/icsAlarm=true
+/icsAlarmTime=5000
+/animateMoving=true
+/animateSpeed=10
+/animateDragging=true
+/blindfold=false
+/highlightLastMove=true
+/highlightDragging=false
+/colorizeMessages=true
+/colorShout="#209000"
+/colorSShout="b #289808"
+/colorChannel1="#2020e0"
+/colorChannel="b #4040ff"
+/colorKibitz="b #ff00ff"
+/colorTell="b #ff0000"
+/colorChallenge="bi #ff0000"
+/colorRequest="bi #ff0000"
+/colorSeek="#980808"
+/colorNormal="#000000"
+/colorBackground=#ffffff
+/soundShout=""
+/soundSShout=""
+/soundChannel1=""
+/soundChannel=""
+/soundKibitz=""
+/soundTell=""
+/soundChallenge=""
+/soundRequest=""
+/soundSeek=""
+/soundMove=""
+/soundBell="$"
+/soundIcsWin=""
+/soundIcsLoss=""
+/soundIcsDraw=""
+/soundIcsUnfinished=""
+/soundIcsAlarm=""
+/comPortSettings=9600,7,Space,1,None
+/x=0
+/y=2
+/icsX=-2147483648
+/icsY=-2147483648
+/icsW=-2147483648
+/icsH=-2147483648
+/analysisX=-2147483648
+/analysisY=-2147483648
+/analysisW=-2147483648
+/analysisH=-2147483648
+/commentX=-2147483648
+/commentY=-2147483648
+/commentW=-2147483648
+/commentH=-2147483648
+/tagsX=-2147483648
+/tagsY=-2147483648
+/tagsW=-2147483648
+/tagsH=-2147483648
+/gameListX=-2147483648
+/gameListY=-2147483648
+/gameListW=-2147483648
+/gameListH=-2147483648
+/saveSettingsOnExit=true
+/icsMenu={-
+&Who,who,0,1
+Playe&rs,players,0,1
+&Games,games,0,1
+&Sought,sought,0,1
+|&Tell (name),tell,1,0
+M&essage (name),message,1,0
+-
+&Finger (name),finger,1,1
+&Vars (name),vars,1,1
+&Observe (name),observe,1,1
+&Match (name),match,1,1
+Pl&ay (name),play,1,1
+}
+/icsNames={chessclub.com /icsport=5000 /icshelper=timestamp
+freechess.org /icsport=5000 /icshelper=timeseal
+global.chessparlor.com /icsport=6000 /icshelper=timeseal
+chessanytime.com /icsport=5000
+chess.net /icsport=5000
+zics.org /icsport=5000
+jogo.cex.org.br /icsport=5000
+ajedrez.cec.uchile.cl /icsport=5000
+fly.cc.fer.hr /icsport=7890
+freechess.nl /icsport=5000 /icshelper=timeseal
+jeu.echecs.com /icsport=5000
+chess.unix-ag.uni-kl.de /icsport=5000 /icshelper=timeseal
+chess.mds.mdh.se /icsport=5000
+}
+/firstChessProgramNames={GNUChess
+"GNUChes5 xboard"
+}
+/secondChessProgramNames={GNUChess
+"GNUChes5 xboard"
+}
+/showButtonBar=true
+/firstScoreAbs=false
+/secondScoreAbs=false
+/pgnExtendedInfo=false
+/hideThinkingFromHuman=false
+/liteBackTextureFile=""
+/darkBackTextureFile=""
+/liteBackTextureMode=1
+/darkBackTextureMode=1
+/renderPiecesWithFont=""
+/fontPieceToCharTable=""
+/fontPieceBackColorWhite=#000000
+/fontPieceForeColorWhite=#000000
+/fontPieceBackColorBlack=#000000
+/fontPieceForeColorBlack=#000000
+/fontPieceSize=80
+/overrideLineGap=1
+/adjudicateLossThreshold=0
+/delayBeforeQuit=0
+/delayAfterQuit=0
+/pgnEventHeader="Computer Chess Game"
index fa51d89..1908a1a 100644 (file)
@@ -36,11 +36,7 @@ CAPTION "About WinBoard"
 FONT 8, "MS Sans Serif"\r
 BEGIN\r
     DEFPUSHBUTTON   "OK",IDOK,131,47,32,14,WS_GROUP\r
-#if __GNUC__\r
-    ICON            icon_white,-1,3,6,20,20,0\r
-#else\r
-    ICON            "icon_white",-1,3,6,20,20,0\r
-#endif\r
+    ICON            "icon_white",-1,3,6,20,20
     LTEXT           "Chessboard for Windows",400,25,15,121,8\r
     LTEXT           "Copyright 1991 Digital Equipment Corporation",201,6,34,\r
                     149,8\r
@@ -50,7 +46,7 @@ BEGIN
     LTEXT           "WinBoard 0.0.0",ABOUTBOX_Version,25,5,142,8\r
 END\r
 \r
-DLG_TimeControl DIALOG DISCARDABLE  6, 18, 147, 113\r
+DLG_TimeControl DIALOG DISCARDABLE  6, 18, 165, 114
 STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU\r
 CAPTION "Time Control"\r
 FONT 8, "MS Sans Serif"\r
@@ -61,15 +57,15 @@ BEGIN
                     BS_AUTORADIOBUTTON | WS_TABSTOP,6,42,107,10\r
     EDITTEXT        OPT_TCMoves,14,20,22,12,ES_AUTOHSCROLL | WS_GROUP\r
     LTEXT           "moves in",OPT_TCtext1,40,22,30,8,NOT WS_GROUP\r
-    EDITTEXT        OPT_TCTime,74,20,32,12,ES_AUTOHSCROLL\r
-    LTEXT           "minutes",OPT_TCtext2,111,22,26,8,NOT WS_GROUP\r
+    EDITTEXT        OPT_TCTime,74,20,50,12,ES_AUTOHSCROLL
+    LTEXT           "minutes",OPT_TCtext2,129,22,26,8,NOT WS_GROUP
     EDITTEXT        OPT_TCTime2,14,56,32,12,ES_AUTOHSCROLL | WS_GROUP\r
     LTEXT           "minutes initially,",405,51,57,73,8,NOT WS_GROUP\r
     LTEXT           "plus",406,19,74,15,8,NOT WS_GROUP\r
     EDITTEXT        OPT_TCInc,37,72,32,12,ES_AUTOHSCROLL\r
     LTEXT           "seconds per move",408,74,74,67,8,NOT WS_GROUP\r
-    PUSHBUTTON      "OK",IDOK,32,95,40,14,WS_GROUP\r
-    PUSHBUTTON      "Cancel",IDCANCEL,88,95,40,14\r
+    PUSHBUTTON      "OK",IDOK,34,95,40,14,WS_GROUP
+    PUSHBUTTON      "Cancel",IDCANCEL,90,95,40,14
 END\r
 \r
 DLG_LoadOptions DIALOG DISCARDABLE  10, 18, 144, 55\r
@@ -238,20 +234,16 @@ WBCONSOLE DIALOG DISCARDABLE  0, 0, 335, 133
 STYLE WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CAPTION | WS_SYSMENU | \r
     WS_THICKFRAME\r
 CAPTION "ICS Interaction"\r
-#if __GNUC__\r
-CLASS WBConsole\r
-#else\r
 CLASS "WBConsole"\r
-#endif\r
 FONT 8, "Courier New"\r
 BEGIN\r
     CONTROL         "",OPT_ConsoleText,"RICHEDIT",ES_MULTILINE | \r
                     ES_AUTOVSCROLL | ES_NOHIDESEL | ES_READONLY | ES_NUMBER | \r
                     WS_BORDER | WS_VSCROLL | WS_TABSTOP,0,0,335,119\r
-    CONTROL         "",OPT_ConsoleInput,"RICHEDIT",ES_AUTOHSCROLL | \r
-                    ES_AUTOVSCROLL | ES_MULTILINE | \r
-                    ES_NOHIDESEL | ES_NUMBER | WS_BORDER | \r
-                    WS_TABSTOP,0,120,335,13,WS_EX_TRANSPARENT\r
+    CONTROL         "",OPT_ConsoleInput,"RICHEDIT",ES_MULTILINE |
+                    ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_NOHIDESEL |
+                    ES_NUMBER | WS_BORDER | WS_TABSTOP,0,120,335,13,
+                    WS_EX_TRANSPARENT
 END\r
 \r
 DLG_Analysis DIALOG DISCARDABLE  0, 0, 294, 62\r
@@ -278,7 +270,7 @@ END
 DLG_Colorize DIALOGEX 0, 0, 183, 52\r
 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU\r
 CAPTION "ICS Interaction Colors"\r
-FONT 8, "MS Sans Serif"\r
+FONT 8, "MS Sans Serif", 0, 0, 0x1
 BEGIN\r
     PUSHBUTTON      "&Choose Color...",OPT_ChooseColor,15,29,51,14,WS_GROUP\r
     CONTROL         "&Bold",OPT_Bold,"Button",BS_AUTOCHECKBOX | WS_GROUP | \r
@@ -336,12 +328,7 @@ BEGIN
 END\r
 \r
 DLG_IndexNumber DIALOG DISCARDABLE  0, 0, 236, 18\r
-#if __GNUC__\r
-STYLE DS_3DLOOK | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS |\r
-       NOT WS_POPUP | NOT WS_BORDER | NOT WS_SYSMENU\r
-#else\r
 STYLE DS_3DLOOK | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS\r
-#endif\r
 FONT 8, "MS Sans Serif"\r
 BEGIN\r
     LTEXT           "Inde&x number:",IDC_STATIC,5,2,46,8\r
@@ -384,7 +371,7 @@ BEGIN
     LTEXT           "Event:",IDC_STATIC,19,9,26,9\r
 END\r
 \r
-DLG_GeneralOptions DIALOG DISCARDABLE  0, 0, 271, 135\r
+DLG_GeneralOptions DIALOG DISCARDABLE  0, 0, 271, 150
 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU\r
 CAPTION "General Options"\r
 FONT 8, "MS Sans Serif"\r
@@ -409,6 +396,8 @@ BEGIN
                     WS_TABSTOP,16,104,79,10\r
     CONTROL         "&Highlight Dragging",OPT_HighlightDragging,"Button",\r
                     BS_AUTOCHECKBOX | WS_TABSTOP,16,118,79,10\r
+    CONTROL         "Extended PGN Info",OPT_SaveExtPGN,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,16,132,79,10
     CONTROL         "Highlight Last &Move",OPT_HighlightLastMove,"Button",\r
                     BS_AUTOCHECKBOX | WS_TABSTOP,109,6,79,10\r
     CONTROL         "Periodic &Updates",OPT_PeriodicUpdates,"Button",\r
@@ -427,12 +416,14 @@ BEGIN
                     BS_AUTOCHECKBOX | WS_TABSTOP,109,104,79,10\r
     CONTROL         "Test &Legality",OPT_TestLegality,"Button",\r
                     BS_AUTOCHECKBOX | WS_TABSTOP,109,118,79,10\r
+    CONTROL         "Hide Thinking From Human",OPT_HideThinkFromHuman,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,109,132,102,10
 END\r
 \r
 DLG_IcsOptions DIALOGEX 0, 0, 318, 271\r
 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU\r
 CAPTION "ICS Options"\r
-FONT 8, "MS Sans Serif"\r
+FONT 8, "MS Sans Serif", 0, 0, 0x1
 BEGIN\r
     DEFPUSHBUTTON   "OK",IDOK,88,250,60,15\r
     PUSHBUTTON      "Cancel",IDCANCEL,168,250,60,15\r
@@ -638,7 +629,7 @@ BEGIN
         LEFTMARGIN, 7\r
         RIGHTMARGIN, 264\r
         TOPMARGIN, 7\r
-        BOTTOMMARGIN, 128\r
+        BOTTOMMARGIN, 143
     END\r
 \r
     DLG_IcsOptions, DIALOG\r
@@ -744,6 +735,10 @@ BEGIN
         MENUITEM SEPARATOR\r
         MENUITEM "Stop &Observing\tF10",        IDM_StopObserving\r
         MENUITEM "Stop E&xamining\tF11",        IDM_StopExamining\r
+        MENUITEM SEPARATOR
+        MENUITEM "Adjudicate to White",         IDM_UserAdjudication_White
+        MENUITEM "Adjudicate to Black",         IDM_UserAdjudication_Black
+        MENUITEM "Adjudicate Draw",             IDM_UserAdjudication_Draw
     END\r
     POPUP "&Step"\r
     BEGIN\r
@@ -902,11 +897,10 @@ BEGIN
     "1",            IDM_DirectCommand1,     VIRTKEY, ALT, NOINVERT\r
     "2",            IDM_DirectCommand2,     VIRTKEY, ALT, NOINVERT\r
     "C",            IDM_CopyGame,           VIRTKEY, ALT, NOINVERT\r
-    "C",            IDM_CopyPosition,       VIRTKEY, SHIFT, ALT, \r
-                                                    NOINVERT\r
+    "C",            IDM_CopyPosition,       VIRTKEY, SHIFT, ALT, NOINVERT
+    "V",            IDM_Paste,              VIRTKEY, CONTROL, NOINVERT
     "V",            IDM_PasteGame,          VIRTKEY, ALT, NOINVERT\r
-    "V",            IDM_PastePosition,      VIRTKEY, SHIFT, ALT, \r
-                                                    NOINVERT\r
+    "V",            IDM_PastePosition,      VIRTKEY, SHIFT, ALT, NOINVERT
     VK_DELETE,      IDM_RetractMove,        VIRTKEY, ALT, NOINVERT\r
     VK_DOWN,        IDM_ToEnd,              VIRTKEY, ALT, NOINVERT\r
     VK_END,         IDM_TruncateGame,       VIRTKEY, ALT, NOINVERT\r
@@ -1353,7 +1347,6 @@ SSHOUT                    WAVE    DISCARDABLE     "..\\sounds\\sshout.wav"
 TELL                   WAVE    DISCARDABLE     "..\\sounds\\tell.wav"\r
 UNFINISHED             WAVE    DISCARDABLE     "..\\sounds\\unfinished.wav"\r
 WIN                    WAVE    DISCARDABLE     "..\\sounds\\win.wav"\r
-\r
 #endif    // English (U.S.) resources\r
 /////////////////////////////////////////////////////////////////////////////\r
 \r
index 3308f2d..d568cee 100644 (file)
@@ -1,6 +1,6 @@
 /*\r
  * woptions.c -- Options dialog box routines for WinBoard\r
- * $Id$\r
+ * $Id: woptions.c,v 2.1 2003/10/27 19:21:02 mann Exp $
  *\r
  * Copyright 2000 Free Software Foundation, Inc.\r
  *\r
@@ -167,6 +167,8 @@ GeneralOptionsDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
     CHECK_BOX(OPT_ShowCoordinates, appData.showCoords);\r
     CHECK_BOX(OPT_ShowThinking, appData.showThinking);\r
     CHECK_BOX(OPT_TestLegality, appData.testLegality);\r
+    CHECK_BOX(OPT_HideThinkFromHuman, appData.hideThinkingFromHuman);
+    CHECK_BOX(OPT_SaveExtPGN, appData.saveExtendedInfoInPGN);
 \r
 #undef CHECK_BOX\r
 \r
@@ -208,6 +210,8 @@ GeneralOptionsDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
       appData.showCoords           = IS_CHECKED(OPT_ShowCoordinates);\r
       ShowThinkingEvent(             IS_CHECKED(OPT_ShowThinking));\r
       appData.testLegality         = IS_CHECKED(OPT_TestLegality);\r
+      appData.hideThinkingFromHuman= IS_CHECKED(OPT_HideThinkFromHuman);
+      appData.saveExtendedInfoInPGN= IS_CHECKED(OPT_SaveExtPGN);
 \r
 #undef IS_CHECKED\r
 \r