Merge branch 'master' into gtk
authorArun Persaud <arun@nubati.net>
Sun, 7 Feb 2010 00:15:15 +0000 (16:15 -0800)
committerArun Persaud <arun@nubati.net>
Sun, 7 Feb 2010 00:15:15 +0000 (16:15 -0800)
Conflicts:
Makefile.am
backend.c
configure.ac
xboard.c
xgamelist.c

1  2 
Makefile.am
backend.c
configure.ac
frontend.h
xboard.c
xgamelist.c
xoptions.c

diff --cc Makefile.am
@@@ -40,13 -35,13 +40,17 @@@ EXTRA_DIST = pixmaps bitmaps svg sound
  
  DISTCLEANFILES = stamp-h
  
- AM_CPPFLAGS=-DINFODIR='"$(infodir)"' @GTK_CFLAGS@
 -AM_CPPFLAGS=-DINFODIR='"$(infodir)"' @X_CFLAGS@  -DSYSCONFDIR='"$(sysconfdir)"'
++
++AM_CPPFLAGS=-DINFODIR='"$(infodir)"' @GTK_CFLAGS@  -DSYSCONFDIR='"$(sysconfdir)"'
++
  
  info_TEXINFOS =  xboard.texi
  xboard_TEXINFOS =  copyright.texi 
  man6_MANS = xboard.man
  
- sysconf_DATA=xboard.conf
++
+ dist_sysconf_DATA = xboard.conf
 +
  xboard.man: xboard.texi copyright.texi gpl.texinfo version.texi
        $(srcdir)/texi2man $(srcdir)/xboard.texi > xboard.man || (rm -f xboard.man ; false)
diff --cc backend.c
+++ b/backend.c
@@@ -1092,94 -1095,71 +1095,97 @@@ InitBackEnd2(
  void
  InitBackEnd3 P((void))
  {
 -    GameMode initialMode;
 -    char buf[MSG_SIZ];
 -    int err;
 -
 -    InitChessProgram(&first, startedFromSetupPosition);
 -
 -
 -    if (appData.icsActive) {
 -#ifdef WIN32
 -        /* [DM] Make a console window if needed [HGM] merged ifs */
 -        ConsoleCreate(); 
 -#endif
 -      err = establish();
 -      if (err != 0) {
 -          if (*appData.icsCommPort != NULLCHAR) {
 -              sprintf(buf, _("Could not open comm port %s"),  
 -                      appData.icsCommPort);
 -          } else {
 -              snprintf(buf, sizeof(buf), _("Could not connect to host %s, port %s"),  
 -                      appData.icsHost, appData.icsPort);
 -          }
 -          DisplayFatalError(buf, err, 1);
 -          return;
 +  GameMode initialMode;
 +  char buf[MSG_SIZ];
 +  int err;
 +  
 +  InitChessProgram(&first, startedFromSetupPosition);
 +  
 +  
 +  if (appData.icsActive) 
 +    {
 +      err = establish();
 +      if (err != 0) 
 +      {
 +        if (*appData.icsCommPort != NULLCHAR) 
 +          {
 +            sprintf(buf, _("Could not open comm port %s"),
 +                    appData.icsCommPort);
 +          }
 +        else 
 +          {
 +            snprintf(buf, sizeof(buf), _("Could not connect to host %s, port %s"),
 +                     appData.icsHost, appData.icsPort);
 +          }
 +        DisplayFatalError(buf, err, 1);
 +        return;
        }
-       SetICSMode();
-       telnetISR =
-       AddInputSource(icsPR, FALSE, read_from_ics, &telnetISR);
-       fromUserISR =
-       AddInputSource(NoProc, FALSE, read_from_player, &fromUserISR);
++
+       SetICSMode();
+       telnetISR =
+         AddInputSource(icsPR, FALSE, read_from_ics, &telnetISR);
+       fromUserISR =
+         AddInputSource(NoProc, FALSE, read_from_player, &fromUserISR);
+       if(appData.keepAlive) // [HGM] alive: schedule sending of dummy 'date' command
+           ScheduleDelayedEvent(KeepAlive, appData.keepAlive*60*1000);
 -    } else if (appData.noChessProgram) {
 -      SetNCPMode();
 -    } else {
 -      SetGNUMode();
      }
 -
 -    if (*appData.cmailGameName != NULLCHAR) {
 -      SetCmailMode();
 -      OpenLoopback(&cmailPR);
 -      cmailISR =
 -        AddInputSource(cmailPR, FALSE, CmailSigHandlerCallBack, &cmailISR);
 +  else if (appData.noChessProgram) 
 +    {
 +      SetNCPMode();
 +    } 
 +  else 
 +    {
 +      SetGNUMode();
      }
 -    
 -    ThawUI();
 -    DisplayMessage("", "");
 -    if (StrCaseCmp(appData.initialMode, "") == 0) {
 +  
 +  if (*appData.cmailGameName != NULLCHAR) 
 +    {
 +      SetCmailMode();
 +      OpenLoopback(&cmailPR);
 +      cmailISR =
 +      AddInputSource(cmailPR, FALSE, CmailSigHandlerCallBack, &cmailISR);
 +    }
 +  
 +  ThawUI();
 +  DisplayMessage("", "");
 +  if (StrCaseCmp(appData.initialMode, "") == 0) 
 +    {
        initialMode = BeginningOfGame;
 -    } else if (StrCaseCmp(appData.initialMode, "TwoMachines") == 0) {
 +    } 
 +  else if (StrCaseCmp(appData.initialMode, "TwoMachines") == 0) 
 +    {
        initialMode = TwoMachinesPlay;
 -    } else if (StrCaseCmp(appData.initialMode, "AnalyzeFile") == 0) {
 -      initialMode = AnalyzeFile; 
 -    } else if (StrCaseCmp(appData.initialMode, "Analysis") == 0) {
 +    } 
 +  else if (StrCaseCmp(appData.initialMode, "AnalyzeFile") == 0) 
 +    {
 +      initialMode = AnalyzeFile;
 +    } 
 +  else if (StrCaseCmp(appData.initialMode, "Analysis") == 0) 
 +    {
        initialMode = AnalyzeMode;
 -    } else if (StrCaseCmp(appData.initialMode, "MachineWhite") == 0) {
 +    } 
 +  else if (StrCaseCmp(appData.initialMode, "MachineWhite") == 0) 
 +    {
        initialMode = MachinePlaysWhite;
 -    } else if (StrCaseCmp(appData.initialMode, "MachineBlack") == 0) {
 +    } 
 +  else if (StrCaseCmp(appData.initialMode, "MachineBlack") == 0) 
 +    {
        initialMode = MachinePlaysBlack;
 -    } else if (StrCaseCmp(appData.initialMode, "EditGame") == 0) {
 +    } 
 +  else if (StrCaseCmp(appData.initialMode, "EditGame") == 0) 
 +    {
        initialMode = EditGame;
 -    } else if (StrCaseCmp(appData.initialMode, "EditPosition") == 0) {
 +    } 
 +  else if (StrCaseCmp(appData.initialMode, "EditPosition") == 0) 
 +    {
        initialMode = EditPosition;
 -    } else if (StrCaseCmp(appData.initialMode, "Training") == 0) {
 +    } 
 +  else if (StrCaseCmp(appData.initialMode, "Training") == 0) 
 +    {
        initialMode = Training;
 -    } else {
 +    } 
 +  else 
 +    {
        sprintf(buf, _("Unknown initialMode %s"), appData.initialMode);
        DisplayFatalError(buf, 0, 2);
        return;
@@@ -5521,8 -5762,6 +5831,7 @@@ UserMoveTest(fromX, fromY, toX, toY, pr
           return WhiteDrop; /* Not needed to specify white or black yet */
      }
  
-     userOfferedDraw = FALSE;
 +
      /* [HGM] always test for legality, to get promotion info */
      moveType = LegalityTest(boards[currentMove], PosFlags(currentMove),
                                           fromY, fromX, toY, toX, promoChar);
@@@ -5654,110 -5876,102 +5963,114 @@@ FinishMove(moveType, fromX, fromY, toX
  
    MakeMove(fromX, fromY, toX, toY, promoChar); /*updates forwardMostMove*/
  
-   if (gameMode == BeginningOfGame)
 -  if(Adjudicate(NULL)) return 1; // [HGM] adjudicate: take care of automtic game end
 -  if (gameMode == BeginningOfGame) {
 -    if (appData.noChessProgram) {
 -      gameMode = EditGame;
 -      SetGameInfo();
 -    } else {
 -      char buf[MSG_SIZ];
 -      gameMode = MachinePlaysBlack;
 -      StartClocks();
 -      SetGameInfo();
 -      sprintf(buf, "%s vs. %s", gameInfo.white, gameInfo.black);
 -      DisplayTitle(buf);
 -      if (first.sendName) {
 -      sprintf(buf, "name %s\n", gameInfo.white);
 -      SendToProgram(buf, &first);
 -      }
 -      StartClocks();
++ if(Adjudicate(NULL)) return 1; // [HGM] adjudicate: take care of automtic game end
++
++if (gameMode == BeginningOfGame)
 +    {
 +      if (appData.noChessProgram)
 +      {
 +        gameMode = EditGame;
 +        SetGameInfo();
 +      }
 +      else
 +      {
 +        char buf[MSG_SIZ];
 +        gameMode = MachinePlaysBlack;
 +        StartClocks();
 +        SetGameInfo();
 +        sprintf(buf, "%s vs. %s", gameInfo.white, gameInfo.black);
 +        DisplayTitle(buf);
 +        if (first.sendName)
 +          {
 +            sprintf(buf, "name %s\n", gameInfo.white);
 +            SendToProgram(buf, &first);
 +          }
 +        StartClocks();
 +      }
 +      ModeHighlight();
++
      }
 -    ModeHighlight();
 -  }
  
    /* Relay move to ICS or chess engine */
-   if (appData.icsActive)
-     {
-       if (gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
-         gameMode == IcsExamining)
-       {
-         SendMoveToICS(moveType, fromX, fromY, toX, toY);
-         ics_user_moved = 1;
-       }
++
+   if (appData.icsActive) {
+     if (gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
+       gameMode == IcsExamining) {
+       if(userOfferedDraw && (signed char)boards[forwardMostMove][EP_STATUS] <= EP_DRAWS) {
+         SendToICS(ics_prefix); // [HGM] drawclaim: send caim and move on one line for FICS
+       SendToICS("draw ");
+         SendMoveToICS(moveType, fromX, fromY, toX, toY);
+       }
+       // also send plain move, in case ICS does not understand atomic claims
+       SendMoveToICS(moveType, fromX, fromY, toX, toY);
+       ics_user_moved = 1;
+     }
+   } else {
+     if (first.sendTime && (gameMode == BeginningOfGame ||
+                          gameMode == MachinePlaysWhite ||
+                          gameMode == MachinePlaysBlack)) {
+       SendTimeRemaining(&first, gameMode != MachinePlaysBlack);
+     }
+     if (gameMode != EditGame && gameMode != PlayFromGameFile) {
+        // [HGM] book: if program might be playing, let it use book
+       bookHit = SendMoveToBookUser(forwardMostMove-1, &first, FALSE);
+       first.maybeThinking = TRUE;
+     } else SendMoveToProgram(forwardMostMove-1, &first);
+     if (currentMove == cmailOldMove + 1) {
+       cmailMoveType[lastLoadGameNumber - 1] = CMAIL_MOVE;
      }
-   else
-     {
-       if (first.sendTime && (gameMode == BeginningOfGame ||
-                            gameMode == MachinePlaysWhite ||
-                            gameMode == MachinePlaysBlack))
-       {
-         SendTimeRemaining(&first, gameMode != MachinePlaysBlack);
-       }
-       if (gameMode != EditGame && gameMode != PlayFromGameFile)
-       {
-         // [HGM] book: if program might be playing, let it use book
-         bookHit = SendMoveToBookUser(forwardMostMove-1, &first, FALSE);
-         first.maybeThinking = TRUE;
-       }
-       else
-       SendMoveToProgram(forwardMostMove-1, &first);
-       if (currentMove == cmailOldMove + 1)
-       {
-         cmailMoveType[lastLoadGameNumber - 1] = CMAIL_MOVE;
-       }
 -  }
 +    }
  
    ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/
  
 -  switch (gameMode) {
 -  case EditGame:
 -    switch (MateTest(boards[currentMove], PosFlags(currentMove)) ) {
 -    case MT_NONE:
 -    case MT_CHECK:
 +  switch (gameMode) 
 +    {
 +    case EditGame:
 +      switch (MateTest(boards[currentMove], PosFlags(currentMove)) ) 
 +      {
 +      case MT_NONE:
 +      case MT_CHECK:
 +        break;
 +      case MT_CHECKMATE:
 +      case MT_STAINMATE:
 +        if (WhiteOnMove(currentMove)) {
 +          GameEnds(BlackWins, "Black mates", GE_PLAYER);
 +        } else {
 +          GameEnds(WhiteWins, "White mates", GE_PLAYER);
 +        }
 +        break;
 +      case MT_STALEMATE:
 +        GameEnds(GameIsDrawn, "Stalemate", GE_PLAYER);
 +        break;
 +      }
        break;
 -    case MT_CHECKMATE:
 -    case MT_STAINMATE:
 -      if (WhiteOnMove(currentMove)) {
 -      GameEnds(BlackWins, "Black mates", GE_PLAYER);
 -      } else {
 -      GameEnds(WhiteWins, "White mates", GE_PLAYER);
 -      }
 +      
 +    case MachinePlaysBlack:
 +    case MachinePlaysWhite:
 +      /* disable certain menu options while machine is thinking */
 +      SetMachineThinkingEnables();
        break;
 -    case MT_STALEMATE:
 -      GameEnds(GameIsDrawn, "Stalemate", GE_PLAYER);
 +      
 +    default:
        break;
      }
-   
 -    break;
 -    
 -  case MachinePlaysBlack:
 -  case MachinePlaysWhite:
 -    /* disable certain menu options while machine is thinking */
 -    SetMachineThinkingEnables();
 -    break;
 -
 -  default:
 -    break;
 -  }
 -
+   userOfferedDraw = FALSE; // [HGM] drawclaim: after move made, and tested for claimable draw
+       
 -  if(bookHit) { // [HGM] book: simulate book reply
 +  if(bookHit)
 +    { // [HGM] book: simulate book reply
-       static char bookMove[MSG_SIZ]; // a bit generous?
+       static char bookMove[MSG_SIZ]; // a bit generous?
 -      programStats.nodes = programStats.depth = programStats.time = 
 +
 +      programStats.nodes = programStats.depth = programStats.time =
        programStats.score = programStats.got_only_move = 0;
 -      sprintf(programStats.movelist, "%s (xbook)", bookHit);
 +      sprintf(programStats.movelist, "%s (xbook)", bookHit);
 +
 +      strcpy(bookMove, "move ");
 +      strcat(bookMove, bookHit);
 +      HandleMachineMove(bookMove, &first);
 +    }
  
 -      strcpy(bookMove, "move ");
 -      strcat(bookMove, bookHit);
 -      HandleMachineMove(bookMove, &first);
 -  }
    return 1;
  }
  
@@@ -6027,6 -6249,69 +6348,69 @@@ void LeftClick(ClickType clickType, in
      }
  }
  
+ int RightClick(ClickType action, int x, int y, int *fromX, int *fromY)
+ {   // front-end-free part taken out of PieceMenuPopup
+     int whichMenu; int xSqr, ySqr;
+     if(seekGraphUp) { // [HGM] seekgraph
+       if(action == Press)   SeekGraphClick(Press, x, y, 2); // 2 indicates right-click: no pop-down on miss
+       if(action == Release) SeekGraphClick(Release, x, y, 2); // and no challenge on hit
+       return -2;
+     }
+     xSqr = EventToSquare(x, BOARD_WIDTH);
+     ySqr = EventToSquare(y, BOARD_HEIGHT);
+     if (action == Release) UnLoadPV(); // [HGM] pv
+     if (action != Press) return -2; // return code to be ignored
+     switch (gameMode) {
+       case IcsExamining:
 -      if(xSqr < BOARD_LEFT || xSqr >= BOARD_RGHT) return -1;\r
++      if(xSqr < BOARD_LEFT || xSqr >= BOARD_RGHT) return -1;
+       case EditPosition:
 -      if (xSqr == BOARD_LEFT-1 || xSqr == BOARD_RGHT) return -1;\r
 -      if (xSqr < 0 || ySqr < 0) return -1;\r
++      if (xSqr == BOARD_LEFT-1 || xSqr == BOARD_RGHT) return -1;
++      if (xSqr < 0 || ySqr < 0) return -1;
+       whichMenu = 0; // edit-position menu
+       break;
+       case IcsObserving:
+       if(!appData.icsEngineAnalyze) return -1;
+       case IcsPlayingWhite:
+       case IcsPlayingBlack:
+       if(!appData.zippyPlay) goto noZip;
+       case AnalyzeMode:
+       case AnalyzeFile:
+       case MachinePlaysWhite:
+       case MachinePlaysBlack:
+       case TwoMachinesPlay: // [HGM] pv: use for showing PV
+       if (!appData.dropMenu) {
+         LoadPV(x, y);
+         return 2; // flag front-end to grab mouse events
+       }
+       if(gameMode == TwoMachinesPlay || gameMode == AnalyzeMode ||
+            gameMode == AnalyzeFile || gameMode == IcsObserving) return -1;
+       case EditGame:
+       noZip:
+       if (xSqr < 0 || ySqr < 0) return -1;
+       if (!appData.dropMenu || appData.testLegality &&
+           gameInfo.variant != VariantBughouse &&
+           gameInfo.variant != VariantCrazyhouse) return -1;
+       whichMenu = 1; // drop menu
+       break;
+       default:
+       return -1;
+     }
+     if (((*fromX = xSqr) < 0) ||
+       ((*fromY = ySqr) < 0)) {
+       *fromX = *fromY = -1;
+       return -1;
+     }
+     if (flipView)
+       *fromX = BOARD_WIDTH - 1 - *fromX;
+     else
+       *fromY = BOARD_HEIGHT - 1 - *fromY;
+     return whichMenu;
+ }
  void SendProgramStatsToFrontend( ChessProgramState * cps, ChessProgramStats * cpstats )
  {
  //    char * hint = lastHint;
      SetProgramStats( &stats );
  }
  
+ int
+ Adjudicate(ChessProgramState *cps)
+ {     // [HGM] some adjudications useful with buggy engines
+       // [HGM] adjudicate: made into separate routine, which now can be called after every move
+       //       In any case it determnes if the game is a claimable draw (filling in EP_STATUS).
+       //       Actually ending the game is now based on the additional internal condition canAdjudicate.
+       //       Only when the game is ended, and the opponent is a computer, this opponent gets the move relayed.
+       int k, count = 0; static int bare = 1;
+       ChessProgramState *engineOpponent = (gameMode == TwoMachinesPlay ? cps->other : (cps ? NULL : &first));
+       Boolean canAdjudicate = !appData.icsActive;
+       // most tests only when we understand the game, i.e. legality-checking on, and (for the time being) no piece drops
+       if(gameInfo.holdingsSize == 0 || gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat) {
+           if( appData.testLegality )
+           {   /* [HGM] Some more adjudications for obstinate engines */
+               int NrWN=0, NrBN=0, NrWB=0, NrBB=0, NrWR=0, NrBR=0,
+                     NrWQ=0, NrBQ=0, NrW=0, NrK=0, bishopsColor = 0,
+                     NrPieces=0, NrPawns=0, PawnAdvance=0, i, j;
+               static int moveCount = 6;
+               ChessMove result;
+               char *reason = NULL;
++
+                 /* Count what is on board. */
+               for(i=0; i<BOARD_HEIGHT; i++) for(j=BOARD_LEFT; j<BOARD_RGHT; j++)
+               {   ChessSquare p = boards[forwardMostMove][i][j];
+                   int m=i;
+                   switch((int) p)
+                   {   /* count B,N,R and other of each side */
+                         case WhiteKing:
+                         case BlackKing:
+                            NrK++; break; // [HGM] atomic: count Kings
+                         case WhiteKnight:
+                              NrWN++; break;
+                         case WhiteBishop:
+                         case WhiteFerz:    // [HGM] shatranj: kludge to mke it work in shatranj
+                              bishopsColor |= 1 << ((i^j)&1);
+                              NrWB++; break;
+                         case BlackKnight:
+                              NrBN++; break;
+                         case BlackBishop:
+                         case BlackFerz:    // [HGM] shatranj: kludge to mke it work in shatranj
+                              bishopsColor |= 1 << ((i^j)&1);
+                              NrBB++; break;
+                         case WhiteRook:
+                              NrWR++; break;
+                         case BlackRook:
+                              NrBR++; break;
+                         case WhiteQueen:
+                              NrWQ++; break;
+                         case BlackQueen:
+                              NrBQ++; break;
+                         case EmptySquare: 
+                              break;
+                         case BlackPawn:
+                              m = 7-i;
+                         case WhitePawn:
+                              PawnAdvance += m; NrPawns++;
+                     }
+                     NrPieces += (p != EmptySquare);
+                     NrW += ((int)p < (int)BlackPawn);
+                   if(gameInfo.variant == VariantXiangqi && 
+                     (p == WhiteFerz || p == WhiteAlfil || p == BlackFerz || p == BlackAlfil)) {
+                       NrPieces--; // [HGM] XQ: do not count purely defensive pieces
+                         NrW -= ((int)p < (int)BlackPawn);
+                   }
+                 }
+               /* Some material-based adjudications that have to be made before stalemate test */
+               if(gameInfo.variant == VariantAtomic && NrK < 2) {
+                   // [HGM] atomic: stm must have lost his King on previous move, as destroying own K is illegal
+                    boards[forwardMostMove][EP_STATUS] = EP_CHECKMATE; // make claimable as if stm is checkmated
+                    if(canAdjudicate && appData.checkMates) {
+                        if(engineOpponent)
+                          SendMoveToProgram(forwardMostMove-1, engineOpponent); // make sure opponent gets move
+                          ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/
+                          GameEnds( WhiteOnMove(forwardMostMove) ? BlackWins : WhiteWins, 
+                                                       "Xboard adjudication: King destroyed", GE_XBOARD );
+                          return 1;
+                    }
+               }
+               /* Bare King in Shatranj (loses) or Losers (wins) */
+                 if( NrW == 1 || NrPieces - NrW == 1) {
+                   if( gameInfo.variant == VariantLosers) { // [HGM] losers: bare King wins (stm must have it first)
+                    boards[forwardMostMove][EP_STATUS] = EP_WINS;  // mark as win, so it becomes claimable
+                    if(canAdjudicate && appData.checkMates) {
+                        if(engineOpponent)
+                          SendMoveToProgram(forwardMostMove-1, engineOpponent); // make sure opponent gets to see move
+                          ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/
+                          GameEnds( WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins, 
+                                                       "Xboard adjudication: Bare king", GE_XBOARD );
+                          return 1;
+                    }
+                 } else
+                   if( gameInfo.variant == VariantShatranj && --bare < 0)
+                   {    /* bare King */
+                       boards[forwardMostMove][EP_STATUS] = EP_WINS; // make claimable as win for stm
+                       if(canAdjudicate && appData.checkMates) {
+                           /* but only adjudicate if adjudication enabled */
+                           if(engineOpponent)
+                             SendMoveToProgram(forwardMostMove-1, engineOpponent); // make sure opponent gets move
+                           ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/
+                           GameEnds( NrW > 1 ? WhiteWins : NrPieces - NrW > 1 ? BlackWins : GameIsDrawn, 
+                                                       "Xboard adjudication: Bare king", GE_XBOARD );
+                           return 1;
+                       }
+                 }
+                 } else bare = 1;
+             // don't wait for engine to announce game end if we can judge ourselves
+             switch (MateTest(boards[forwardMostMove], PosFlags(forwardMostMove)) ) {
+             case MT_CHECK:
+               if(gameInfo.variant == Variant3Check) { // [HGM] 3check: when in check, test if 3rd time
+                   int i, checkCnt = 0;    // (should really be done by making nr of checks part of game state)
+                   for(i=forwardMostMove-2; i>=backwardMostMove; i-=2) {
+                       if(MateTest(boards[i], PosFlags(i)) == MT_CHECK)
+                           checkCnt++;
+                       if(checkCnt >= 2) {
+                           reason = "Xboard adjudication: 3rd check";
+                           boards[forwardMostMove][EP_STATUS] = EP_CHECKMATE;
+                           break;
+                       }
+                   }
+               }
+             case MT_NONE:
+             default:
+               break;
+             case MT_STALEMATE:
+             case MT_STAINMATE:
+               reason = "Xboard adjudication: Stalemate";
+               if((signed char)boards[forwardMostMove][EP_STATUS] != EP_CHECKMATE) { // [HGM] don't touch win through baring or K-capt
+                   boards[forwardMostMove][EP_STATUS] = EP_STALEMATE;   // default result for stalemate is draw
+                   if(gameInfo.variant == VariantLosers  || gameInfo.variant == VariantGiveaway) // [HGM] losers:
+                       boards[forwardMostMove][EP_STATUS] = EP_WINS;    // in these variants stalemated is always a win
+                   else if(gameInfo.variant == VariantSuicide) // in suicide it depends
+                       boards[forwardMostMove][EP_STATUS] = NrW == NrPieces-NrW ? EP_STALEMATE :
+                                                  ((NrW < NrPieces-NrW) != WhiteOnMove(forwardMostMove) ?
+                                                                       EP_CHECKMATE : EP_WINS);
+                   else if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantXiangqi)
+                       boards[forwardMostMove][EP_STATUS] = EP_CHECKMATE; // and in these variants being stalemated loses
+               }
+               break;
+             case MT_CHECKMATE:
+               reason = "Xboard adjudication: Checkmate";
+               boards[forwardMostMove][EP_STATUS] = (gameInfo.variant == VariantLosers ? EP_WINS : EP_CHECKMATE);
+               break;
+           }
+               switch(i = (signed char)boards[forwardMostMove][EP_STATUS]) {
+                   case EP_STALEMATE:
+                       result = GameIsDrawn; break;
+                   case EP_CHECKMATE:
+                       result = WhiteOnMove(forwardMostMove) ? BlackWins : WhiteWins; break;
+                   case EP_WINS:
+                       result = WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins; break;
+                   default:
+                       result = (ChessMove) 0;
+               }
+                 if(canAdjudicate && appData.checkMates && result) { // [HGM] mates: adjudicate finished games if requested
+                   if(engineOpponent)
+                     SendMoveToProgram(forwardMostMove-1, engineOpponent); /* make sure opponent gets to see move */
+                   ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/
+                   GameEnds( result, reason, GE_XBOARD );
+                   return 1;
+               }
+                 /* Next absolutely insufficient mating material. */
+                 if( NrPieces == 2 || gameInfo.variant != VariantXiangqi && 
+                                    gameInfo.variant != VariantShatranj && // [HGM] baring will remain possible
+                       (NrPieces == 3 && NrWN+NrBN+NrWB+NrBB == 1 ||
+                        NrPieces == NrBB+NrWB+2 && bishopsColor != 3)) // [HGM] all Bishops (Ferz!) same color
+                 {    /* KBK, KNK, KK of KBKB with like Bishops */
+                      /* always flag draws, for judging claims */
+                      boards[forwardMostMove][EP_STATUS] = EP_INSUF_DRAW;
+                      if(canAdjudicate && appData.materialDraws) {
+                          /* but only adjudicate them if adjudication enabled */
+                        if(engineOpponent) {
+                          SendToProgram("force\n", engineOpponent); // suppress reply
+                          SendMoveToProgram(forwardMostMove-1, engineOpponent); /* make sure opponent gets to see last move */
+                        }
+                          ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/
+                          GameEnds( GameIsDrawn, "Xboard adjudication: Insufficient mating material", GE_XBOARD );
+                          return 1;
+                      }
+                 }
+                 /* Then some trivial draws (only adjudicate, cannot be claimed) */
+                 if(NrPieces == 4 && 
+                    (   NrWR == 1 && NrBR == 1 /* KRKR */
+                    || NrWQ==1 && NrBQ==1     /* KQKQ */
+                    || NrWN==2 || NrBN==2     /* KNNK */
+                    || NrWN+NrWB == 1 && NrBN+NrBB == 1 /* KBKN, KBKB, KNKN */
+                   ) ) {
+                      if(canAdjudicate && --moveCount < 0 && appData.trivialDraws)
+                      {    /* if the first 3 moves do not show a tactical win, declare draw */
+                         if(engineOpponent) {
+                           SendToProgram("force\n", engineOpponent); // suppress reply
+                           SendMoveToProgram(forwardMostMove-1, engineOpponent); /* make sure opponent gets to see move */
+                         }
+                           ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/
+                           GameEnds( GameIsDrawn, "Xboard adjudication: Trivial draw", GE_XBOARD );
+                           return 1;
+                      }
+                 } else moveCount = 6;
+           }
+       }
+         
+       if (appData.debugMode) { int i;
+           fprintf(debugFP, "repeat test fmm=%d bmm=%d ep=%d, reps=%d\n",
+                   forwardMostMove, backwardMostMove, boards[backwardMostMove][EP_STATUS],
+                   appData.drawRepeats);
+           for( i=forwardMostMove; i>=backwardMostMove; i-- )
+             fprintf(debugFP, "%d ep=%d\n", i, (signed char)boards[i][EP_STATUS]);
+           
+       }
+       // Repetition draws and 50-move rule can be applied independently of legality testing
+                 /* Check for rep-draws */
+                 count = 0;
+                 for(k = forwardMostMove-2;
+                     k>=backwardMostMove && k>=forwardMostMove-100 &&
+                         (signed char)boards[k][EP_STATUS] < EP_UNKNOWN &&
+                         (signed char)boards[k+2][EP_STATUS] <= EP_NONE && (signed char)boards[k+1][EP_STATUS] <= EP_NONE;
+                     k-=2)
+                 {   int rights=0;
+                     if(CompareBoards(boards[k], boards[forwardMostMove])) {
+                         /* compare castling rights */
+                         if( boards[forwardMostMove][CASTLING][2] != boards[k][CASTLING][2] &&
+                              (boards[k][CASTLING][0] != NoRights || boards[k][CASTLING][1] != NoRights) )
+                                 rights++; /* King lost rights, while rook still had them */
+                         if( boards[forwardMostMove][CASTLING][2] != NoRights ) { /* king has rights */
+                             if( boards[forwardMostMove][CASTLING][0] != boards[k][CASTLING][0] ||
+                                 boards[forwardMostMove][CASTLING][1] != boards[k][CASTLING][1] )
+                                    rights++; /* but at least one rook lost them */
+                         }
+                         if( boards[forwardMostMove][CASTLING][5] != boards[k][CASTLING][5] &&
+                              (boards[k][CASTLING][3] != NoRights || boards[k][CASTLING][4] != NoRights) )
+                                 rights++; 
+                         if( boards[forwardMostMove][CASTLING][5] != NoRights ) {
+                             if( boards[forwardMostMove][CASTLING][3] != boards[k][CASTLING][3] ||
+                                 boards[forwardMostMove][CASTLING][4] != boards[k][CASTLING][4] )
+                                    rights++;
+                         }
+                         if( canAdjudicate && rights == 0 && ++count > appData.drawRepeats-2
+                             && appData.drawRepeats > 1) {
+                              /* adjudicate after user-specified nr of repeats */
+                            if(engineOpponent) {
+                              SendToProgram("force\n", engineOpponent); // suppress reply
+                              SendMoveToProgram(forwardMostMove-1, engineOpponent); /* make sure opponent gets to see move */
+                            }
+                              ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/
+                            if(gameInfo.variant == VariantXiangqi && appData.testLegality) { 
+                               // [HGM] xiangqi: check for forbidden perpetuals
+                               int m, ourPerpetual = 1, hisPerpetual = 1;
+                               for(m=forwardMostMove; m>k; m-=2) {
+                                   if(MateTest(boards[m], PosFlags(m)) != MT_CHECK)
+                                       ourPerpetual = 0; // the current mover did not always check
+                                   if(MateTest(boards[m-1], PosFlags(m-1)) != MT_CHECK)
+                                       hisPerpetual = 0; // the opponent did not always check
+                               }
+                               if(appData.debugMode) fprintf(debugFP, "XQ perpetual test, our=%d, his=%d\n",
+                                                                       ourPerpetual, hisPerpetual);
+                               if(ourPerpetual && !hisPerpetual) { // we are actively checking him: forfeit
+                                   GameEnds( WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins, 
+                                          "Xboard adjudication: perpetual checking", GE_XBOARD );
+                                   return 1;
+                               }
+                               if(hisPerpetual && !ourPerpetual)   // he is checking us, but did not repeat yet
+                                   break; // (or we would have caught him before). Abort repetition-checking loop.
+                               // Now check for perpetual chases
+                               if(!ourPerpetual && !hisPerpetual) { // no perpetual check, test for chase
+                                   hisPerpetual = PerpetualChase(k, forwardMostMove);
+                                   ourPerpetual = PerpetualChase(k+1, forwardMostMove);
+                                   if(ourPerpetual && !hisPerpetual) { // we are actively chasing him: forfeit
+                                       GameEnds( WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins, 
+                                                     "Xboard adjudication: perpetual chasing", GE_XBOARD );
+                                       return 1;
+                                   }
+                                   if(hisPerpetual && !ourPerpetual)   // he is chasing us, but did not repeat yet
+                                       break; // Abort repetition-checking loop.
+                               }
+                               // if neither of us is checking or chasing all the time, or both are, it is draw
+                            }
+                              GameEnds( GameIsDrawn, "Xboard adjudication: repetition draw", GE_XBOARD );
+                              return 1;
+                         }
+                         if( rights == 0 && count > 1 ) /* occurred 2 or more times before */
+                              boards[forwardMostMove][EP_STATUS] = EP_REP_DRAW;
+                     }
+                 }
+                 /* Now we test for 50-move draws. Determine ply count */
+                 count = forwardMostMove;
+                 /* look for last irreversble move */
+                 while( (signed char)boards[count][EP_STATUS] <= EP_NONE && count > backwardMostMove )
+                     count--;
+                 /* if we hit starting position, add initial plies */
+                 if( count == backwardMostMove )
+                     count -= initialRulePlies;
+                 count = forwardMostMove - count; 
+                 if( count >= 100)
+                          boards[forwardMostMove][EP_STATUS] = EP_RULE_DRAW;
+                          /* this is used to judge if draw claims are legal */
+                 if(canAdjudicate && appData.ruleMoves > 0 && count >= 2*appData.ruleMoves) {
+                        if(engineOpponent) {
+                          SendToProgram("force\n", engineOpponent); // suppress reply
+                          SendMoveToProgram(forwardMostMove-1, engineOpponent); /* make sure opponent gets to see move */
+                        }
+                          ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/
+                          GameEnds( GameIsDrawn, "Xboard adjudication: 50-move rule", GE_XBOARD );
+                          return 1;
+                 }
+                 /* if draw offer is pending, treat it as a draw claim
+                  * when draw condition present, to allow engines a way to
+                  * claim draws before making their move to avoid a race
+                  * condition occurring after their move
+                  */
+               if((gameMode == TwoMachinesPlay ? second.offeredDraw : userOfferedDraw) || first.offeredDraw ) {
+                          char *p = NULL;
+                          if((signed char)boards[forwardMostMove][EP_STATUS] == EP_RULE_DRAW)
+                              p = "Draw claim: 50-move rule";
+                          if((signed char)boards[forwardMostMove][EP_STATUS] == EP_REP_DRAW)
+                              p = "Draw claim: 3-fold repetition";
+                          if((signed char)boards[forwardMostMove][EP_STATUS] == EP_INSUF_DRAW)
+                              p = "Draw claim: insufficient mating material";
+                          if( p != NULL && canAdjudicate) {
+                            if(engineOpponent) {
+                              SendToProgram("force\n", engineOpponent); // suppress reply
+                              SendMoveToProgram(forwardMostMove-1, engineOpponent); /* make sure opponent gets to see move */
+                            }
+                              ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/
+                              GameEnds( GameIsDrawn, p, GE_XBOARD );
+                              return 1;
+                          }
+                 }
+               if( canAdjudicate && appData.adjudicateDrawMoves > 0 && forwardMostMove > (2*appData.adjudicateDrawMoves) ) {
+                   if(engineOpponent) {
+                     SendToProgram("force\n", engineOpponent); // suppress reply
+                     SendMoveToProgram(forwardMostMove-1, engineOpponent); /* make sure opponent gets to see move */
+                   }
+                   ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/
+                   GameEnds( GameIsDrawn, "Xboard adjudication: long game", GE_XBOARD );
+                   return 1;
+               }
+       return 0;
+ }
  char *SendMoveToBookUser(int moveNr, ChessProgramState *cps, int initial)
  {   // [HGM] book: this routine intercepts moves to simulate book replies
      char *bookHit = NULL;
@@@ -6233,453 -6872,130 +6972,534 @@@ FakeBookMove: // [HGM] book: we jump he
            if (gameMode == TwoMachinesPlay) {
              GameEnds(machineWhite ? BlackWins : WhiteWins,
                         buf1, GE_XBOARD);
++<<<<<<< HEAD
 +          }
 +          return;
 +      }
 +
 +        /* [HGM] Apparently legal, but so far only tested with EP_UNKOWN */
 +        /* So we have to redo legality test with true e.p. status here,  */
 +        /* to make sure an illegal e.p. capture does not slip through,   */
 +        /* to cause a forfeit on a justified illegal-move complaint      */
 +        /* of the opponent.                                              */
 +        if( gameMode==TwoMachinesPlay && appData.testLegality
 +            && fromY != DROP_RANK /* [HGM] temporary; should still add legality test for drops */
 +                                                              ) {
 +           ChessMove moveType;
 +           moveType = LegalityTest(boards[forwardMostMove], PosFlags(forwardMostMove),
 +                             fromY, fromX, toY, toX, promoChar);
 +          if (appData.debugMode) {
 +                int i;
 +                for(i=0; i< nrCastlingRights; i++) fprintf(debugFP, "(%d,%d) ",
 +                    boards[forwardMostMove][CASTLING][i], castlingRank[i]);
 +                fprintf(debugFP, "castling rights\n");
 +          }
 +            if(moveType == IllegalMove) {
 +                sprintf(buf1, "Xboard: Forfeit due to illegal move: %s (%c%c%c%c)%c",
 +                        machineMove, fromX+AAA, fromY+ONE, toX+AAA, toY+ONE, 0);
 +                GameEnds(machineWhite ? BlackWins : WhiteWins,
 +                           buf1, GE_XBOARD);
 +              return;
 +           } else if(gameInfo.variant != VariantFischeRandom && gameInfo.variant != VariantCapaRandom)
 +           /* [HGM] Kludge to handle engines that send FRC-style castling
 +              when they shouldn't (like TSCP-Gothic) */
 +           switch(moveType) {
 +             case WhiteASideCastleFR:
 +             case BlackASideCastleFR:
 +               toX+=2;
 +               currentMoveString[2]++;
 +               break;
 +             case WhiteHSideCastleFR:
 +             case BlackHSideCastleFR:
 +               toX--;
 +               currentMoveString[2]--;
 +               break;
 +           default: ; // nothing to do, but suppresses warning of pedantic compilers
 +           }
 +        }
 +      hintRequested = FALSE;
 +      lastHint[0] = NULLCHAR;
 +      bookRequested = FALSE;
 +      /* Program may be pondering now */
 +      cps->maybeThinking = TRUE;
 +      if (cps->sendTime == 2) cps->sendTime = 1;
 +      if (cps->offeredDraw) cps->offeredDraw--;
 +
 +#if ZIPPY
 +      if ((gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack) &&
 +          first.initDone) {
 +        SendMoveToICS(moveType, fromX, fromY, toX, toY);
 +        ics_user_moved = 1;
 +        if(appData.autoKibitz && !appData.icsEngineAnalyze ) { /* [HGM] kibitz: send most-recent PV info to ICS */
 +              char buf[3*MSG_SIZ];
 +
 +              sprintf(buf, "kibitz !!! %+.2f/%d (%.2f sec, %u nodes, %.0f knps) PV=%s\n",
 +                      programStats.score / 100.,
 +                      programStats.depth,
 +                      programStats.time / 100.,
 +                      (unsigned int)programStats.nodes,
 +                      (unsigned int)programStats.nodes / (10*abs(programStats.time) + 1.),
 +                      programStats.movelist);
 +              SendToICS(buf);
 +if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.nodes, programStats.nodes);
 +        }
 +      }
 +#endif
 +      /* currentMoveString is set as a side-effect of ParseOneMove */
 +      strcpy(machineMove, currentMoveString);
 +      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;
 +        pvInfoList[ forwardMostMove ].time =  programStats.time; // [HGM] PGNtime: take time from engine stats
 +        ClearProgramStats();
 +        thinkOutput[0] = NULLCHAR;
 +        hiddenThinkOutputState = 0;
 +
 +      MakeMove(fromX, fromY, toX, toY, promoChar);/*updates forwardMostMove*/
 +
 +        /* [AS] Adjudicate game if needed (note: remember that 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 ) {
 +              ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/
 +
 +                GameEnds( WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins,
 +                    "Xboard adjudication",
 +                    GE_XBOARD );
 +
 +                return;
 +            }
 +        }
 +
 +      if( gameMode == TwoMachinesPlay ) {
 +        // [HGM] some adjudications useful with buggy engines
 +            int k, count = 0; static int bare = 1;
 +        if(gameInfo.holdingsSize == 0 || gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat) {
 +
 +
 +          if( appData.testLegality )
 +          {   /* [HGM] Some more adjudications for obstinate engines */
 +              int NrWN=0, NrBN=0, NrWB=0, NrBB=0, NrWR=0, NrBR=0,
 +                    NrWQ=0, NrBQ=0, NrW=0, NrK=0, bishopsColor = 0,
 +                    NrPieces=0, NrPawns=0, PawnAdvance=0, i, j;
 +              static int moveCount = 6;
 +              ChessMove result;
 +              char *reason = NULL;
 +
 +                /* Count what is on board. */
 +              for(i=0; i<BOARD_HEIGHT; i++) for(j=BOARD_LEFT; j<BOARD_RGHT; j++)
 +              {   ChessSquare p = boards[forwardMostMove][i][j];
 +                  int m=i;
 +
 +                  switch((int) p)
 +                  {   /* count B,N,R and other of each side */
 +                        case WhiteKing:
 +                        case BlackKing:
 +                           NrK++; break; // [HGM] atomic: count Kings
 +                        case WhiteKnight:
 +                             NrWN++; break;
 +                        case WhiteBishop:
 +                        case WhiteFerz:    // [HGM] shatranj: kludge to mke it work in shatranj
 +                             bishopsColor |= 1 << ((i^j)&1);
 +                             NrWB++; break;
 +                        case BlackKnight:
 +                             NrBN++; break;
 +                        case BlackBishop:
 +                        case BlackFerz:    // [HGM] shatranj: kludge to mke it work in shatranj
 +                             bishopsColor |= 1 << ((i^j)&1);
 +                             NrBB++; break;
 +                        case WhiteRook:
 +                             NrWR++; break;
 +                        case BlackRook:
 +                             NrBR++; break;
 +                        case WhiteQueen:
 +                             NrWQ++; break;
 +                        case BlackQueen:
 +                             NrBQ++; break;
 +                        case EmptySquare:
 +                             break;
 +                        case BlackPawn:
 +                             m = 7-i;
 +                        case WhitePawn:
 +                             PawnAdvance += m; NrPawns++;
 +                    }
 +                    NrPieces += (p != EmptySquare);
 +                    NrW += ((int)p < (int)BlackPawn);
 +                  if(gameInfo.variant == VariantXiangqi &&
 +                    (p == WhiteFerz || p == WhiteAlfil || p == BlackFerz || p == BlackAlfil)) {
 +                      NrPieces--; // [HGM] XQ: do not count purely defensive pieces
 +                        NrW -= ((int)p < (int)BlackPawn);
 +                  }
 +                }
 +
 +              /* Some material-based adjudications that have to be made before stalemate test */
 +              if(gameInfo.variant == VariantAtomic && NrK < 2) {
 +                  // [HGM] atomic: stm must have lost his King on previous move, as destroying own K is illegal
 +                   boards[forwardMostMove][EP_STATUS] = EP_CHECKMATE; // make claimable as if stm is checkmated
 +                   if(appData.checkMates) {
 +                       SendMoveToProgram(forwardMostMove-1, cps->other); // make sure opponent gets move
 +                         ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/
 +                         GameEnds( WhiteOnMove(forwardMostMove) ? BlackWins : WhiteWins,
 +                                                      "Xboard adjudication: King destroyed", GE_XBOARD );
 +                         return;
 +                   }
 +              }
 +
 +              /* Bare King in Shatranj (loses) or Losers (wins) */
 +                if( NrW == 1 || NrPieces - NrW == 1) {
 +                  if( gameInfo.variant == VariantLosers) { // [HGM] losers: bare King wins (stm must have it first)
 +                   boards[forwardMostMove][EP_STATUS] = EP_WINS;  // mark as win, so it becomes claimable
 +                   if(appData.checkMates) {
 +                       SendMoveToProgram(forwardMostMove-1, cps->other); // make sure opponent gets to see move
 +                         ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/
 +                         GameEnds( WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins,
 +                                                      "Xboard adjudication: Bare king", GE_XBOARD );
 +                         return;
 +                   }
 +                } else
 +                  if( gameInfo.variant == VariantShatranj && --bare < 0)
 +                  {    /* bare King */
 +                      boards[forwardMostMove][EP_STATUS] = EP_WINS; // make claimable as win for stm
 +                      if(appData.checkMates) {
 +                          /* but only adjudicate if adjudication enabled */
 +                          SendMoveToProgram(forwardMostMove-1, cps->other); // make sure opponent gets move
 +                          ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/
 +                          GameEnds( NrW > 1 ? WhiteWins : NrPieces - NrW > 1 ? BlackWins : GameIsDrawn,
 +                                                      "Xboard adjudication: Bare king", GE_XBOARD );
 +                          return;
 +                      }
 +                }
 +                } else bare = 1;
 +
 +
 +            // don't wait for engine to announce game end if we can judge ourselves
 +            switch (MateTest(boards[forwardMostMove], PosFlags(forwardMostMove)) ) {
 +            case MT_CHECK:
 +              if(gameInfo.variant == Variant3Check) { // [HGM] 3check: when in check, test if 3rd time
 +                  int i, checkCnt = 0;    // (should really be done by making nr of checks part of game state)
 +                  for(i=forwardMostMove-2; i>=backwardMostMove; i-=2) {
 +                      if(MateTest(boards[i], PosFlags(i)) == MT_CHECK)
 +                          checkCnt++;
 +                      if(checkCnt >= 2) {
 +                          reason = "Xboard adjudication: 3rd check";
 +                          boards[forwardMostMove][EP_STATUS] = EP_CHECKMATE;
 +                          break;
 +                      }
 +                  }
 +              }
 +            case MT_NONE:
 +            default:
 +              break;
 +            case MT_STALEMATE:
 +            case MT_STAINMATE:
 +              reason = "Xboard adjudication: Stalemate";
 +              if((signed char)boards[forwardMostMove][EP_STATUS] != EP_CHECKMATE) { // [HGM] don't touch win through baring or K-capt
 +                  boards[forwardMostMove][EP_STATUS] = EP_STALEMATE;   // default result for stalemate is draw
 +                  if(gameInfo.variant == VariantLosers  || gameInfo.variant == VariantGiveaway) // [HGM] losers:
 +                      boards[forwardMostMove][EP_STATUS] = EP_WINS;    // in these variants stalemated is always a win
 +                  else if(gameInfo.variant == VariantSuicide) // in suicide it depends
 +                      boards[forwardMostMove][EP_STATUS] = NrW == NrPieces-NrW ? EP_STALEMATE :
 +                                                 ((NrW < NrPieces-NrW) != WhiteOnMove(forwardMostMove) ?
 +                                                                      EP_CHECKMATE : EP_WINS);
 +                  else if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantXiangqi)
 +                      boards[forwardMostMove][EP_STATUS] = EP_CHECKMATE; // and in these variants being stalemated loses
 +              }
 +              break;
 +            case MT_CHECKMATE:
 +              reason = "Xboard adjudication: Checkmate";
 +              boards[forwardMostMove][EP_STATUS] = (gameInfo.variant == VariantLosers ? EP_WINS : EP_CHECKMATE);
 +              break;
++=======
++>>>>>>> master
            }
+           return;
+       }
  
++<<<<<<< HEAD
 +              switch(i = (signed char)boards[forwardMostMove][EP_STATUS]) {
 +                  case EP_STALEMATE:
 +                      result = GameIsDrawn; break;
 +                  case EP_CHECKMATE:
 +                      result = WhiteOnMove(forwardMostMove) ? BlackWins : WhiteWins; break;
 +                  case EP_WINS:
 +                      result = WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins; break;
 +                  default:
 +                      result = (ChessMove) 0;
 +              }
 +                if(appData.checkMates && result) { // [HGM] mates: adjudicate finished games if requested
 +                  SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see move */
 +                  ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/
 +                  GameEnds( result, reason, GE_XBOARD );
 +                  return;
 +              }
 +
 +                /* Next absolutely insufficient mating material. */
 +                if( NrPieces == 2 || gameInfo.variant != VariantXiangqi &&
 +                                   gameInfo.variant != VariantShatranj && // [HGM] baring will remain possible
 +                      (NrPieces == 3 && NrWN+NrBN+NrWB+NrBB == 1 ||
 +                       NrPieces == NrBB+NrWB+2 && bishopsColor != 3)) // [HGM] all Bishops (Ferz!) same color
 +                {    /* KBK, KNK, KK of KBKB with like Bishops */
++=======
+         /* [HGM] Apparently legal, but so far only tested with EP_UNKOWN */
+         /* So we have to redo legality test with true e.p. status here,  */
+         /* to make sure an illegal e.p. capture does not slip through,   */
+         /* to cause a forfeit on a justified illegal-move complaint      */
+         /* of the opponent.                                              */
+         if( gameMode==TwoMachinesPlay && appData.testLegality
+             && fromY != DROP_RANK /* [HGM] temporary; should still add legality test for drops */
+                                                               ) {
+            ChessMove moveType;
+            moveType = LegalityTest(boards[forwardMostMove], PosFlags(forwardMostMove),
+                              fromY, fromX, toY, toX, promoChar);
+           if (appData.debugMode) {
+                 int i;
+                 for(i=0; i< nrCastlingRights; i++) fprintf(debugFP, "(%d,%d) ",
+                     boards[forwardMostMove][CASTLING][i], castlingRank[i]);
+                 fprintf(debugFP, "castling rights\n");
+           }
+             if(moveType == IllegalMove) {
+                 sprintf(buf1, "Xboard: Forfeit due to illegal move: %s (%c%c%c%c)%c",
+                         machineMove, fromX+AAA, fromY+ONE, toX+AAA, toY+ONE, 0);
+                 GameEnds(machineWhite ? BlackWins : WhiteWins,
+                            buf1, GE_XBOARD);
+               return;
+            } else if(gameInfo.variant != VariantFischeRandom && gameInfo.variant != VariantCapaRandom)
+            /* [HGM] Kludge to handle engines that send FRC-style castling
+               when they shouldn't (like TSCP-Gothic) */
+            switch(moveType) {
+              case WhiteASideCastleFR:
+              case BlackASideCastleFR:
+                toX+=2;
+                currentMoveString[2]++;
+                break;
+              case WhiteHSideCastleFR:
+              case BlackHSideCastleFR:
+                toX--;
+                currentMoveString[2]--;
+                break;
+            default: ; // nothing to do, but suppresses warning of pedantic compilers
+            }
+         }
+       hintRequested = FALSE;
+       lastHint[0] = NULLCHAR;
+       bookRequested = FALSE;
+       /* Program may be pondering now */
+       cps->maybeThinking = TRUE;
+       if (cps->sendTime == 2) cps->sendTime = 1;
+       if (cps->offeredDraw) cps->offeredDraw--;
++>>>>>>> master
  
-                      /* always flag draws, for judging claims */
-                      boards[forwardMostMove][EP_STATUS] = EP_INSUF_DRAW;
+       /* currentMoveString is set as a side-effect of ParseOneMove */
+       strcpy(machineMove, currentMoveString);
+       strcat(machineMove, "\n");
+       strcpy(moveList[forwardMostMove], machineMove);
  
-                      if(appData.materialDraws) {
-                          /* but only adjudicate them if adjudication enabled */
-                        SendToProgram("force\n", cps->other); // suppress reply
-                        SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see last move */
-                          ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/
-                          GameEnds( GameIsDrawn, "Xboard adjudication: Insufficient mating material", GE_XBOARD );
-                          return;
-                      }
-                 }
+       MakeMove(fromX, fromY, toX, toY, promoChar);/*updates forwardMostMove*/
  
++<<<<<<< HEAD
 +                /* Then some trivial draws (only adjudicate, cannot be claimed) */
 +                if(NrPieces == 4 &&
 +                   (   NrWR == 1 && NrBR == 1 /* KRKR */
 +                   || NrWQ==1 && NrBQ==1     /* KQKQ */
 +                   || NrWN==2 || NrBN==2     /* KNNK */
 +                   || NrWN+NrWB == 1 && NrBN+NrBB == 1 /* KBKN, KBKB, KNKN */
 +                  ) ) {
 +                     if(--moveCount < 0 && appData.trivialDraws)
 +                     {    /* if the first 3 moves do not show a tactical win, declare draw */
 +                        SendToProgram("force\n", cps->other); // suppress reply
 +                        SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see move */
 +                          ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/
 +                          GameEnds( GameIsDrawn, "Xboard adjudication: Trivial draw", GE_XBOARD );
 +                          return;
 +                     }
 +                } else moveCount = 6;
 +          }
 +        }
 +        
 +        if (appData.debugMode) { int i;
 +          fprintf(debugFP, "repeat test fmm=%d bmm=%d ep=%d, reps=%d\n",
 +                  forwardMostMove, backwardMostMove, boards[backwardMostMove][EP_STATUS],
 +                  appData.drawRepeats);
 +          for( i=forwardMostMove; i>=backwardMostMove; i-- )
 +            fprintf(debugFP, "%d ep=%d\n", i, (signed char)boards[i][EP_STATUS]);
 +          
 +        }
 +
 +                /* Check for rep-draws */
 +                count = 0;
 +                for(k = forwardMostMove-2;
 +                    k>=backwardMostMove && k>=forwardMostMove-100 &&
 +                        (signed char)boards[k][EP_STATUS] < EP_UNKNOWN &&
 +                        (signed char)boards[k+2][EP_STATUS] <= EP_NONE && (signed char)boards[k+1][EP_STATUS] <= EP_NONE;
 +                    k-=2)
 +                {   int rights=0;
 +                    if(CompareBoards(boards[k], boards[forwardMostMove])) {
 +                        /* compare castling rights */
 +                        if( boards[forwardMostMove][CASTLING][2] != boards[k][CASTLING][2] &&
 +                             (boards[k][CASTLING][0] != NoRights || boards[k][CASTLING][1] != NoRights) )
 +                                rights++; /* King lost rights, while rook still had them */
 +                        if( boards[forwardMostMove][CASTLING][2] != NoRights ) { /* king has rights */
 +                            if( boards[forwardMostMove][CASTLING][0] != boards[k][CASTLING][0] ||
 +                                boards[forwardMostMove][CASTLING][1] != boards[k][CASTLING][1] )
 +                                   rights++; /* but at least one rook lost them */
 +                        }
 +                        if( boards[forwardMostMove][CASTLING][5] != boards[k][CASTLING][5] &&
 +                             (boards[k][CASTLING][3] != NoRights || boards[k][CASTLING][4] != NoRights) )
 +                                rights++; 
 +                        if( boards[forwardMostMove][CASTLING][5] != NoRights ) {
 +                            if( boards[forwardMostMove][CASTLING][3] != boards[k][CASTLING][3] ||
 +                                boards[forwardMostMove][CASTLING][4] != boards[k][CASTLING][4] )
 +                                   rights++;
 +                        }
 +                        if( rights == 0 && ++count > appData.drawRepeats-2
 +                            && appData.drawRepeats > 1) {
 +                             /* adjudicate after user-specified nr of repeats */
 +                           SendToProgram("force\n", cps->other); // suppress reply
 +                           SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see move */
 +                             ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/
 +                           if(gameInfo.variant == VariantXiangqi && appData.testLegality) {
 +                              // [HGM] xiangqi: check for forbidden perpetuals
 +                              int m, ourPerpetual = 1, hisPerpetual = 1;
 +                              for(m=forwardMostMove; m>k; m-=2) {
 +                                  if(MateTest(boards[m], PosFlags(m)) != MT_CHECK)
 +                                      ourPerpetual = 0; // the current mover did not always check
 +                                  if(MateTest(boards[m-1], PosFlags(m-1)) != MT_CHECK)
 +                                      hisPerpetual = 0; // the opponent did not always check
 +                              }
 +                              if(appData.debugMode) fprintf(debugFP, "XQ perpetual test, our=%d, his=%d\n",
 +                                                                      ourPerpetual, hisPerpetual);
 +                              if(ourPerpetual && !hisPerpetual) { // we are actively checking him: forfeit
 +                                  GameEnds( WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins,
 +                                         "Xboard adjudication: perpetual checking", GE_XBOARD );
 +                                  return;
 +                              }
 +                              if(hisPerpetual && !ourPerpetual)   // he is checking us, but did not repeat yet
 +                                  break; // (or we would have caught him before). Abort repetition-checking loop.
 +                              // Now check for perpetual chases
 +                              if(!ourPerpetual && !hisPerpetual) { // no perpetual check, test for chase
 +                                  hisPerpetual = PerpetualChase(k, forwardMostMove);
 +                                  ourPerpetual = PerpetualChase(k+1, forwardMostMove);
 +                                  if(ourPerpetual && !hisPerpetual) { // we are actively chasing him: forfeit
 +                                      GameEnds( WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins,
 +                                                    "Xboard adjudication: perpetual chasing", GE_XBOARD );
 +                                      return;
 +                                  }
 +                                  if(hisPerpetual && !ourPerpetual)   // he is chasing us, but did not repeat yet
 +                                      break; // Abort repetition-checking loop.
 +                              }
 +                              // if neither of us is checking or chasing all the time, or both are, it is draw
 +                           }
 +                             GameEnds( GameIsDrawn, "Xboard adjudication: repetition draw", GE_XBOARD );
 +                             return;
 +                        }
 +                        if( rights == 0 && count > 1 ) /* occurred 2 or more times before */
 +                             boards[forwardMostMove][EP_STATUS] = EP_REP_DRAW;
 +                    }
 +                }
 +
 +                /* Now we test for 50-move draws. Determine ply count */
 +                count = forwardMostMove;
 +                /* look for last irreversble move */
 +                while( (signed char)boards[count][EP_STATUS] <= EP_NONE && count > backwardMostMove )
 +                    count--;
 +                /* if we hit starting position, add initial plies */
 +                if( count == backwardMostMove )
 +                    count -= initialRulePlies;
 +                count = forwardMostMove - count;
 +                if( count >= 100)
 +                         boards[forwardMostMove][EP_STATUS] = EP_RULE_DRAW;
 +                         /* this is used to judge if draw claims are legal */
 +                if(appData.ruleMoves > 0 && count >= 2*appData.ruleMoves) {
 +                       SendToProgram("force\n", cps->other); // suppress reply
 +                       SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see move */
 +                         ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/
 +                         GameEnds( GameIsDrawn, "Xboard adjudication: 50-move rule", GE_XBOARD );
 +                         return;
++=======
+         /* [AS] Adjudicate game if needed (note: remember that 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 */
++>>>>>>> master
                  }
  
-                 /* if draw offer is pending, treat it as a draw claim
-                  * when draw condition present, to allow engines a way to
-                  * claim draws before making their move to avoid a race
-                  * condition occurring after their move
-                  */
-                 if( cps->other->offeredDraw || cps->offeredDraw ) {
-                          char *p = NULL;
-                          if((signed char)boards[forwardMostMove][EP_STATUS] == EP_RULE_DRAW)
-                              p = "Draw claim: 50-move rule";
-                          if((signed char)boards[forwardMostMove][EP_STATUS] == EP_REP_DRAW)
-                              p = "Draw claim: 3-fold repetition";
-                          if((signed char)boards[forwardMostMove][EP_STATUS] == EP_INSUF_DRAW)
-                              p = "Draw claim: insufficient mating material";
-                          if( p != NULL ) {
-                            SendToProgram("force\n", cps->other); // suppress reply
-                            SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see move */
-                              GameEnds( GameIsDrawn, p, GE_XBOARD );
-                              ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/
-                              return;
-                          }
+                 if( score > adjudicateLossThreshold ) {
+                     break;
                  }
  
+                 count++;
+             }
  
-               if( appData.adjudicateDrawMoves > 0 && forwardMostMove > (2*appData.adjudicateDrawMoves) ) {
-                   SendToProgram("force\n", cps->other); // suppress reply
-                   SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see move */
-                   ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/
+             if( count >= adjudicateLossPlies ) {
+               ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/
  
-                   GameEnds( GameIsDrawn, "Xboard adjudication: long game", GE_XBOARD );
+                 GameEnds( WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins, 
+                     "Xboard adjudication", 
+                     GE_XBOARD );
  
-                   return;
-               }
+                 return;
+             }
          }
  
+       if(Adjudicate(cps)) return; // [HGM] adjudicate: for all automatic game ends
+ #if ZIPPY
+       if ((gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack) &&
+           first.initDone) {
+         if(cps->offeredDraw && (signed char)boards[forwardMostMove][EP_STATUS] <= EP_DRAWS) {
+               SendToICS(ics_prefix); // [HGM] drawclaim: send caim and move on one line for FICS
+               SendToICS("draw ");
+               SendMoveToICS(moveType, fromX, fromY, toX, toY);
+         }
+         SendMoveToICS(moveType, fromX, fromY, toX, toY);
+         ics_user_moved = 1;
+         if(appData.autoKibitz && !appData.icsEngineAnalyze ) { /* [HGM] kibitz: send most-recent PV info to ICS */
+               char buf[3*MSG_SIZ];
+               sprintf(buf, "kibitz !!! %+.2f/%d (%.2f sec, %u nodes, %.0f knps) PV=%s\n",
+                       programStats.score / 100.,
+                       programStats.depth,
+                       programStats.time / 100.,
+                       (unsigned int)programStats.nodes,
+                       (unsigned int)programStats.nodes / (10*abs(programStats.time) + 1.),
+                       programStats.movelist);
+               SendToICS(buf);
+ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.nodes, programStats.nodes);
+         }
+       }
+ #endif
+         /* [AS] Save move info and clear stats for next move */
+         pvInfoList[ forwardMostMove-1 ].score = programStats.score;
+         pvInfoList[ forwardMostMove-1 ].depth = programStats.depth;
+         pvInfoList[ forwardMostMove-1 ].time =  programStats.time; // [HGM] PGNtime: take time from engine stats
+         ClearProgramStats();
+         thinkOutput[0] = NULLCHAR;
+         hiddenThinkOutputState = 0;
        bookHit = NULL;
        if (gameMode == TwoMachinesPlay) {
              /* [HGM] relaying draw offers moved to after reception of move */
@@@ -11892,9 -12169,10 +12712,10 @@@ DrawEvent(
           your clock.  Currently ICS doesn't let you do that;
           instead, you immediately punch your clock after making
           a move, but you can offer a draw at any time. */
 -      
 +
          SendToICS(ics_prefix);
        SendToICS("draw\n");
+         userOfferedDraw = TRUE; // [HGM] drawclaim: also set flag in ICS play
      } else if (cmailMsgLoaded) {
        if (currentMove == cmailOldMove &&
            commentList[cmailOldMove] != NULL &&
diff --cc configure.ac
@@@ -28,7 -28,7 +28,8 @@@ dnl| to regenerate configure.  Then sub
  dnl| the standard version of xboard.
  
  dnl| define second argument as VERSION.PATCHLEVEL. e.g. 4.4.0j
 -AC_INIT([xboard],[master-20100118],[bug-xboard@gnu.org])
 +AC_INIT([xboard],[gtk-20100118],[bug-xboard@gnu.org])
++
  AM_INIT_AUTOMAKE
  
  AC_CONFIG_HEADERS([config.h])
diff --cc frontend.h
Simple merge
diff --cc xboard.c
+++ b/xboard.c
@@@ -1,4 -1,4 +1,4 @@@
--/*
++Xg/*
   * xboard.c -- X front end for XBoard
   *
   * Copyright 1991 by Digital Equipment Corporation, Maynard,
@@@ -662,35 -666,36 +664,36 @@@ MenuItem optionsMenu[] = 
      {N_("Engine #1 Settings ..."), FirstSettingsProc},
      {N_("Engine #2 Settings ..."), SecondSettingsProc},
      {N_("Time Control ..."), TimeControlProc},
+     {N_("Game List ..."), GameListOptionsPopUp},
      {"----", NothingProc},
 -    {N_("Always Queen"), AlwaysQueenProc},
 -    {N_("Animate Dragging"), AnimateDraggingProc},
 -    {N_("Animate Moving"), AnimateMovingProc},
 -    {N_("Auto Comment"), AutocommProc},
 -    {N_("Auto Flag"), AutoflagProc},
 -    {N_("Auto Flip View"), AutoflipProc},
 -    {N_("Auto Observe"), AutobsProc},
 -    {N_("Auto Raise Board"), AutoraiseProc},
 -    {N_("Auto Save"), AutosaveProc},
 -    {N_("Blindfold"), BlindfoldProc},
 -    {N_("Flash Moves"), FlashMovesProc},
 -    {N_("Get Move List"), GetMoveListProc},
 -#if HIGHDRAG
 -    {N_("Highlight Dragging"), HighlightDraggingProc},
 -#endif
 -    {N_("Highlight Last Move"), HighlightLastMoveProc},
 -    {N_("Move Sound"), MoveSoundProc},
 -    {N_("ICS Alarm"), IcsAlarmProc},
 -    {N_("Old Save Style"), OldSaveStyleProc},
 -    {N_("Periodic Updates"), PeriodicUpdatesProc},
 -    {N_("Ponder Next Move"), PonderNextMoveProc},
 -    {N_("Popup Exit Message"), PopupExitMessageProc},
 -    {N_("Popup Move Errors"), PopupMoveErrorsProc},
 -    {N_("Premove"), PremoveProc},
 -    {N_("Quiet Play"), QuietPlayProc},
 -    {N_("Show Coords"), ShowCoordsProc},
 -    {N_("Hide Thinking"), HideThinkingProc},
 -    {N_("Test Legality"), TestLegalityProc},
 +    //    {N_("Always Queen"), AlwaysQueenProc},
 +    //    {N_("Animate Dragging"), AnimateDraggingProc},
 +    //    {N_("Animate Moving"), AnimateMovingProc},
 +    //    {N_("Auto Comment"), AutocommProc},
 +    //    {N_("Auto Flag"), AutoflagProc},
 +    //    {N_("Auto Flip View"), AutoflipProc},
 +    //    {N_("Auto Observe"), AutobsProc},
 +    //    {N_("Auto Raise Board"), AutoraiseProc},
 +    //    {N_("Auto Save"), AutosaveProc},
 +    //    {N_("Blindfold"), BlindfoldProc},
 +    //    {N_("Flash Moves"), FlashMovesProc},
 + //    {N_("Get Move List"), GetMoveListProc},
 +    //#if HIGHDRAG
 +    //    {N_("Highlight Dragging"), HighlightDraggingProc},
 +    //#endif
 +    //    {N_("Highlight Last Move"), HighlightLastMoveProc},
 +    //    {N_("Move Sound"), MoveSoundProc},
 +    //    {N_("ICS Alarm"), IcsAlarmProc},
 +    //    {N_("Old Save Style"), OldSaveStyleProc},
 +    //    {N_("Periodic Updates"), PeriodicUpdatesProc},
 +    //    {N_("Ponder Next Move"), PonderNextMoveProc},
 +    //    {N_("Popup Exit Message"), PopupExitMessageProc},
 +    //    {N_("Popup Move Errors"), PopupMoveErrorsProc},
 +    //    {N_("Premove"), PremoveProc},
 +    //    {N_("Quiet Play"), QuietPlayProc},
 +    //    {N_("Hide Thinking"), HideThinkingProc},
 +    //    {N_("Test Legality"), TestLegalityProc},
 +    //    {N_("Show Coords"), ShowCoordsProc},
      {"----", NothingProc},
      {N_("Save Settings Now"), SaveSettingsProc},
      {N_("Save Settings on Exit"), SaveOnExitProc},
@@@ -781,14 -844,21 +784,23 @@@ XtActionsRec boardActions[] = 
      { "AskQuestionProc", AskQuestionProc },
      { "AskQuestionReplyAction", AskQuestionReplyAction },
      { "PieceMenuPopup", PieceMenuPopup },
 -    { "WhiteClock", WhiteClock },
 -    { "BlackClock", BlackClock },
 +    //    { "WhiteClock", WhiteClock },
 +    //    { "BlackClock", BlackClock },
      { "Iconify", Iconify },
 -    { "ResetProc", ResetProc },
 -    { "LoadGameProc", LoadGameProc },
 -    { "LoadNextGameProc", LoadNextGameProc },
 -    { "LoadPrevGameProc", LoadPrevGameProc },
      { "LoadSelectedProc", LoadSelectedProc },
++<<<<<<< HEAD
 +    //    { "LoadPositionProc", LoadPositionProc },
 +    //    { "LoadNextPositionProc", LoadNextPositionProc },
 +    //    { "LoadPrevPositionProc", LoadPrevPositionProc },
 +    //    { "ReloadPositionProc", ReloadPositionProc },
++=======
+     { "SetFilterProc", SetFilterProc },
+     { "ReloadGameProc", ReloadGameProc },
+     { "LoadPositionProc", LoadPositionProc },
+     { "LoadNextPositionProc", LoadNextPositionProc },
+     { "LoadPrevPositionProc", LoadPrevPositionProc },
+     { "ReloadPositionProc", ReloadPositionProc },
++>>>>>>> master
      { "CopyPositionProc", CopyPositionProc },
      { "PastePositionProc", PastePositionProc },
      { "CopyGameProc", CopyGameProc },
      { "TagsPopDown", (XtActionProc) TagsPopDown },
      { "ErrorPopDown", (XtActionProc) ErrorPopDown },
      { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
 -    { "FileNamePopDown", (XtActionProc) FileNamePopDown },
 +    //    { "FileNamePopDown", (XtActionProc) FileNamePopDown },
      { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
      { "GameListPopDown", (XtActionProc) GameListPopDown },
+     { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
      { "PromotionPopDown", (XtActionProc) PromotionPopDown },
 -    { "HistoryPopDown", (XtActionProc) HistoryPopDown },
 +    //    { "HistoryPopDown", (XtActionProc) HistoryPopDown },
      { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
      { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
      { "ShufflePopDown", (XtActionProc) ShufflePopDown },
@@@ -1871,6 -2458,35 +1907,20 @@@ main(argc, argv
      if (appData.animate || appData.animateDragging)
        CreateAnimVars();
  
 -    XtAugmentTranslations(formWidget,
 -                        XtParseTranslationTable(globalTranslations));
 -    XtAugmentTranslations(boardWidget,
 -                        XtParseTranslationTable(boardTranslations));
 -    XtAugmentTranslations(whiteTimerWidget,
 -                        XtParseTranslationTable(whiteTranslations));
 -    XtAugmentTranslations(blackTimerWidget,
 -                        XtParseTranslationTable(blackTranslations));
 -
 -    /* Why is the following needed on some versions of X instead
 -     * of a translation? */
 -    XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
 -                    (XtEventHandler) EventProc, NULL);
 -    /* end why */
 -
+     /* [AS] Restore layout */
+     if( wpMoveHistory.visible ) {
+       HistoryPopUp();
+     }
+     if( wpEvalGraph.visible ) 
+       {
+       EvalGraphPopUp();
+       };
+     
+     if( wpEngineOutput.visible ) {
+       EngineOutputPopUp();
+     }
      InitBackEnd2();
  
      if (errorExitStatus == -1) {
  SetHighlights(fromX, fromY, toX, toY)
       int fromX, fromY, toX, toY;
  {
 -    if (hi1X != fromX || hi1Y != fromY) {
 -      if (hi1X >= 0 && hi1Y >= 0) {
 -          drawHighlight(hi1X, hi1Y, lineGC);
 -      }
 -    } // [HGM] first erase both, then draw new!
 -    if (hi2X != toX || hi2Y != toY) {
 -      if (hi2X >= 0 && hi2Y >= 0) {
 -          drawHighlight(hi2X, hi2Y, lineGC);
 -      }
 -    }
 -    if (hi1X != fromX || hi1Y != fromY) {
 -      if (fromX >= 0 && fromY >= 0) {
 -          drawHighlight(fromX, fromY, highlineGC);
 -      }
 -    }
 -    if (hi2X != toX || hi2Y != toY) {
 -      if (toX >= 0 && toY >= 0) {
 -          drawHighlight(toX, toY, highlineGC);
 -      }
 -    }
 +    if (hi1X != fromX || hi1Y != fromY)
 +      {
 +      if (hi1X >= 0 && hi1Y >= 0)
 +        {
 +          drawHighlight(hi1X, hi1Y, LINE_TYPE_NORMAL);
 +        }
-       if (fromX >= 0 && fromY >= 0)
-         {
-           drawHighlight(fromX, fromY, LINE_TYPE_HIGHLIGHT);
-         }
 +      }
 +    if (hi2X != toX || hi2Y != toY)
 +      {
 +      if (hi2X >= 0 && hi2Y >= 0)
 +        {
 +          drawHighlight(hi2X, hi2Y, LINE_TYPE_NORMAL);
 +        }
++      }
++    if (hi1X != fromX || hi1Y != fromY)
++      {
++      if (fromX >= 0 && fromY >= 0)
++        {
++          drawHighlight(fromX, fromY, LINE_TYPE_HIGHLIGHT);
++        }
++    if (hi2X != toX || hi2Y != toY)
++      {    
 +      if (toX >= 0 && toY >= 0)
 +        {
 +          drawHighlight(toX, toY, LINE_TYPE_HIGHLIGHT);
 +        }
 +      }
      hi1X = fromX;
      hi1Y = fromY;
      hi2X = toX;
@@@ -2760,158 -4119,125 +2779,171 @@@ void DrawSquare(row, column, piece, do_
  
      square_color = SquareColor(row, column);
  
 -    if ( // [HGM] holdings: blank out area between board and holdings
 -                 column == BOARD_LEFT-1 ||  column == BOARD_RGHT
 -              || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
 -                || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
 -                      BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
 -
 -                      // [HGM] print piece counts next to holdings
 -                      string[1] = NULLCHAR;
 -                      if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
 -                          string[0] = '0' + piece;
 -                          XTextExtents(countFontStruct, string, 1, &direction,
 -                               &font_ascent, &font_descent, &overall);
 -                          if (appData.monoMode) {
 -                              XDrawImageString(xDisplay, xBoardWindow, countGC,
 -                                               x + squareSize - overall.width - 2,
 -                                               y + font_ascent + 1, string, 1);
 -                          } else {
 -                              XDrawString(xDisplay, xBoardWindow, countGC,
 -                                          x + squareSize - overall.width - 2,
 -                                          y + font_ascent + 1, string, 1);
 -                          }
 -                      }
 -                      if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
 -                          string[0] = '0' + piece;
 -                          XTextExtents(countFontStruct, string, 1, &direction,
 -                                       &font_ascent, &font_descent, &overall);
 -                          if (appData.monoMode) {
 -                              XDrawImageString(xDisplay, xBoardWindow, countGC,
 -                                               x + 2, y + font_ascent + 1, string, 1);
 -                          } else {
 -                              XDrawString(xDisplay, xBoardWindow, countGC,
 -                                          x + 2, y + font_ascent + 1, string, 1);
 -                          }
 -                      }
 -    } else {
 -          if (piece == EmptySquare || appData.blindfold) {
 -                      BlankSquare(x, y, square_color, piece, xBoardWindow);
 -          } else {
 -                      drawfunc = ChooseDrawFunc();
 -                      if (do_flash && appData.flashCount > 0) {
 -                          for (i=0; i<appData.flashCount; ++i) {
 -
 -                                      drawfunc(piece, square_color, x, y, xBoardWindow);
 -                                      XSync(xDisplay, False);
 -                                      do_flash_delay(flash_delay);
 -
 -                                      BlankSquare(x, y, square_color, piece, xBoardWindow);
 -                                      XSync(xDisplay, False);
 -                                      do_flash_delay(flash_delay);
 -                          }
 -                      }
 -                      drawfunc(piece, square_color, x, y, xBoardWindow);
 -      }
 -      }
 +    // [HGM] holdings: blank out area between board and holdings
 +    if ( column == BOARD_LEFT-1 ||  column == BOARD_RGHT
 +       || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
 +       || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) )
 +      {
 +      BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
  
 -    string[1] = NULLCHAR;
 -    if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
 -              && column >= BOARD_LEFT && column < BOARD_RGHT) {
 -      string[0] = 'a' + column - BOARD_LEFT;
 -      XTextExtents(coordFontStruct, string, 1, &direction,
 -                   &font_ascent, &font_descent, &overall);
 -      if (appData.monoMode) {
 -          XDrawImageString(xDisplay, xBoardWindow, coordGC,
 -                           x + squareSize - overall.width - 2,
 -                           y + squareSize - font_descent - 1, string, 1);
 -      } else {
 -          XDrawString(xDisplay, xBoardWindow, coordGC,
 -                      x + squareSize - overall.width - 2,
 -                      y + squareSize - font_descent - 1, string, 1);
 -      }
 -    }
 -    if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
 -      string[0] = ONE + row;
 -      XTextExtents(coordFontStruct, string, 1, &direction,
 -                   &font_ascent, &font_descent, &overall);
 -      if (appData.monoMode) {
 -          XDrawImageString(xDisplay, xBoardWindow, coordGC,
 -                           x + 2, y + font_ascent + 1, string, 1);
 -      } else {
 -          XDrawString(xDisplay, xBoardWindow, coordGC,
 -                      x + 2, y + font_ascent + 1, string, 1);
 -      }
 -    }
 -    if(marker[row][column]) {
 -      XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC, 
 -              x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
 -    }
 -}
 +      // [HGM] print piece counts next to holdings
 +      string[1] = NULLCHAR;
 +      if(piece > 1)
 +        {
 +          cairo_text_extents_t extents;
 +          cairo_t *cr;
 +          int  xpos, ypos;
 +
 +          /* get a cairo_t */
 +          cr = gdk_cairo_create (GDK_WINDOW(GUI_Board->window));
 +
 +          string[0] = '0' + piece;
 +
 +          /* TODO this has to go into the font-selection */
 +          cairo_select_font_face (cr, "Sans",
 +                                  CAIRO_FONT_SLANT_NORMAL,
 +                                  CAIRO_FONT_WEIGHT_NORMAL);
++          //TODO
++//    switch (event->type) {
++//      case Expose:
++//    if (event->xexpose.count > 0) return;  /* no clipping is done */
++//    XDrawPosition(widget, True, NULL);
++//    break;
++//      case MotionNotify:
++//        if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
++//      default:
++//    return;
++//    }
++//}
++/* end why */
  
 +          cairo_set_font_size (cr, 12.0);
 +          cairo_text_extents (cr, string, &extents);
  
 -/* Why is this needed on some versions of X? */
 -void EventProc(widget, unused, event)
 -     Widget widget;
 -     caddr_t unused;
 -     XEvent *event;
 -{
 -    if (!XtIsRealized(widget))
 -      return;
 +          if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) )
 +            {
 +              xpos= x + squareSize - extents.width - 2;
 +              ypos= y + extents.y_bearing + 1;
 +            }
 +          if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1)
 +            {
 +              xpos= x + 2;
 +              ypos = y + extents.y_bearing + 1;
 +            }
  
 -    switch (event->type) {
 -      case Expose:
 -      if (event->xexpose.count > 0) return;  /* no clipping is done */
 -      XDrawPosition(widget, True, NULL);
 -      break;
 -      case MotionNotify:
 -        if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;\r
 -      default:
 -      return;
 -    }
 -}
 -/* end why */
 +          /* TODO mono mode? */
 +          cairo_move_to (cr, xpos, ypos);
 +          cairo_text_path (cr, string);
 +          cairo_set_source_rgb (cr, 1.0, 1.0, 1);
 +          cairo_fill_preserve (cr);
 +          cairo_set_source_rgb (cr, 0, 0, 0);
 +          cairo_set_line_width (cr, 0.1);
 +          cairo_stroke (cr);
 +
 +          /* free memory */
 +          cairo_destroy (cr);
 +        }
 +      }
 +    else
 +      {
 +      /* square on the board */
 +      if (piece == EmptySquare || appData.blindfold)
 +        {
 +          BlankSquare(x, y, square_color, piece, xBoardWindow);
 +        }
 +      else
 +        {
 +          if (do_flash && appData.flashCount > 0)
 +            {
 +              for (i=0; i<appData.flashCount; ++i)
 +                {
  
 -void DrawPosition(fullRedraw, board)
 -     /*Boolean*/int fullRedraw;
 -     Board board;
 -{
 -    XDrawPosition(boardWidget, fullRedraw, board);
 +                  DrawPiece(piece, square_color, x, y, xBoardWindow);
 +                  do_flash_delay(flash_delay);
 +
 +                  BlankSquare(x, y, square_color, piece, xBoardWindow);
 +                  do_flash_delay(flash_delay);
 +                }
 +            }
 +          DrawPiece(piece, square_color, x, y, xBoardWindow);
 +        }
 +      }
 +
 +    /* show coordinates if necessary */
 +    if(appData.showCoords)
 +      {
 +      cairo_text_extents_t extents;
 +      cairo_t *cr;
 +      int  xpos, ypos;
 +
 +      /* TODO this has to go into the font-selection */
 +      cairo_select_font_face (cr, "Sans",
 +                              CAIRO_FONT_SLANT_NORMAL,
 +                              CAIRO_FONT_WEIGHT_NORMAL);
 +      cairo_set_font_size (cr, 12.0);
 +
 +      string[1] = NULLCHAR;
 +
 +      /* get a cairo_t */
 +      cr = gdk_cairo_create (GDK_WINDOW(GUI_Board->window));
 +
 +      if (row == (flipView ? BOARD_HEIGHT-1 : 0) &&
 +          column >= BOARD_LEFT && column < BOARD_RGHT)
 +        {
 +          string[0] = 'a' + column - BOARD_LEFT;
 +          cairo_text_extents (cr, string, &extents);
 +
 +          xpos = x + squareSize - extents.width - 2;
 +          ypos = y + squareSize - extents.height - extents.y_bearing - 1;
 +
 +          if (appData.monoMode)
 +            { /*TODO*/
 +            }
 +          else
 +            {
 +            }
 +
 +          cairo_move_to (cr, xpos, ypos);
 +          cairo_text_path (cr, string);
 +          cairo_set_source_rgb (cr, 0.0, 0.0, 0);
 +          cairo_fill_preserve (cr);
 +          cairo_set_source_rgb (cr, 0, 1.0, 0);
 +          cairo_set_line_width (cr, 0.1);
 +          cairo_stroke (cr);
 +        }
 +      if ( column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT))
 +        {
 +
 +          string[0] = ONE + row;
 +          cairo_text_extents (cr, string, &extents);
 +
 +          xpos = x + 2;
 +          ypos = y + extents.height + 1;
 +
 +          if (appData.monoMode)
 +            { /*TODO*/
 +            }
 +          else
 +            {
 +            }
 +
 +          cairo_move_to (cr, xpos, ypos);
 +          cairo_text_path (cr, string);
 +          cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
 +          cairo_fill_preserve (cr);
 +          cairo_set_source_rgb (cr, 0, 0, 1.0);
 +          cairo_set_line_width (cr, 0.1);
 +          cairo_stroke (cr);
 +
 +        }
 +      /* free memory */
 +      cairo_destroy (cr);
 +      }
 +
 +    return;
  }
  
 +
  /* Returns 1 if there are "too many" differences between b1 and b2
     (i.e. more than 1 move was made) */
  static int too_many_diffs(b1, b2)
@@@ -2984,46 -4340,48 +3046,48 @@@ static int damage[BOARD_RANKS][BOARD_FI
  /*
   * event handler for redrawing the board
   */
 -void XDrawPosition(w, repaint, board)
 -     Widget w;
 +void DrawPosition( repaint, board)
       /*Boolean*/int repaint;
 -     Board board;
 +              Board board;
  {
 -    int i, j, do_flash;
 -    static int lastFlipView = 0;
 -    static int lastBoardValid = 0;
 -    static Board lastBoard;
 -    Arg args[16];
 -    int rrow, rcol;
 +  int i, j, do_flash;
 +  static int lastFlipView = 0;
 +  static int lastBoardValid = 0;
 +  static Board lastBoard;
 +  int rrow, rcol;
  
+     if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
 -    if (board == NULL) {
 -      if (!lastBoardValid) return;
 -      board = lastBoard;
 -    }
 -    if (!lastBoardValid || lastFlipView != flipView) {
 -      XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
 -      XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
 -                  args, 1);
 -    }
 -
 -    /*
 -     * It would be simpler to clear the window with XClearWindow()
 -     * but this causes a very distracting flicker.
 -     */
 +  if (board == NULL) {
 +    if (!lastBoardValid) return;
 +    board = lastBoard;
 +  }
 +  if (!lastBoardValid || lastFlipView != flipView) {
 +    //    XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
 +    // XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
 +    //        args, 1);
 +  }
  
 -    if (!repaint && lastBoardValid && lastFlipView == flipView) {
 +  /*
 +   * It would be simpler to clear the window with XClearWindow()
 +   * but this causes a very distracting flicker.
 +   */
  
 -      /* If too much changes (begin observing new game, etc.), don't
 -         do flashing */
 -      do_flash = too_many_diffs(board, lastBoard) ? 0 : 1;
 +  if (!repaint && lastBoardValid && lastFlipView == flipView)
 +    {
 +      /* If too much changes (begin observing new game, etc.), don't
 +       do flashing */
 +      do_flash = too_many_diffs(board, lastBoard) ? 0 : 1;
  
 -      /* Special check for castling so we don't flash both the king
 -         and the rook (just flash the king). */
 -      if (do_flash) {
 -          if (check_castle_draw(board, lastBoard, &rrow, &rcol)) {
 -              /* Draw rook with NO flashing. King will be drawn flashing later */
 -              DrawSquare(rrow, rcol, board[rrow][rcol], 0);
 -              lastBoard[rrow][rcol] = board[rrow][rcol];
 +      /* Special check for castling so we don't flash both the king
 +       and the rook (just flash the king). */
 +      if (do_flash)
 +      {
 +        if (check_castle_draw(board, lastBoard, &rrow, &rcol))
 +          {
 +            /* Draw rook with NO flashing. King will be drawn flashing later */
 +            DrawSquare(rrow, rcol, board[rrow][rcol], 0);
 +            lastBoard[rrow][rcol] = board[rrow][rcol];
            }
        }
  
diff --cc xgamelist.c
@@@ -91,11 -90,11 +91,13 @@@ extern char *getenv()
  # define N_(s)  s
  #endif
  
 +extern GtkWidget               *GUI_GameList;
 +extern GtkListStore            *LIST_GameList;
  
+ void SetFocus P((Widget w, XtPointer data, XEvent *event, Boolean *b));
+ extern Widget formWidget, shellWidget, boardWidget, menuBarWidget, gameListShell;
 -extern Display *xDisplay;
 +
- extern Widget formWidget, boardWidget, menuBarWidget, gameListShell;
  extern int squareSize;
  extern Pixmap xMarkPixmap;
  extern char *layoutName;
@@@ -125,9 -137,236 +140,45 @@@ GameListCreate(name, callback, client_d
       XtCallbackProc callback;
       XtPointer client_data;
  {
 -    Arg args[16];
 -    Widget shell, form, viewport, listwidg, layout, label;
 -    Widget b_load, b_loadprev, b_loadnext, b_close, b_filter;
 -    Dimension fw_width;
 -    int j;
 -    GameListClosure *glc = (GameListClosure *) client_data;
 -
 -    j = 0;
 -    XtSetArg(args[j], XtNwidth, &fw_width);  j++;
 -    XtGetValues(formWidget, args, j);
 -
 -    j = 0;
 -    XtSetArg(args[j], XtNresizable, True);  j++;
 -    XtSetArg(args[j], XtNallowShellResize, True);  j++;
 -#if TOPLEVEL
 -    shell = gameListShell =
 -      XtCreatePopupShell(name, topLevelShellWidgetClass,
 -                       shellWidget, args, j);
 -#else
 -    shell = gameListShell =
 -      XtCreatePopupShell(name, transientShellWidgetClass,
 -                       shellWidget, args, j);
 -#endif
 -    layout =
 -      XtCreateManagedWidget(layoutName, formWidgetClass, shell,
 -                          layoutArgs, XtNumber(layoutArgs));
 -    j = 0;
 -    XtSetArg(args[j], XtNborderWidth, 0); j++;
 -    form =
 -      XtCreateManagedWidget("form", formWidgetClass, layout, args, j);
 -
 -    j = 0;
 -    XtSetArg(args[j], XtNtop, XtChainTop);  j++;
 -    XtSetArg(args[j], XtNbottom, XtChainBottom);  j++;
 -    XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
 -    XtSetArg(args[j], XtNright, XtChainRight);  j++;
 -    XtSetArg(args[j], XtNresizable, False);  j++;
 -    XtSetArg(args[j], XtNwidth, fw_width);  j++;
 -    XtSetArg(args[j], XtNallowVert, True); j++;
 -    viewport =
 -      XtCreateManagedWidget("viewport", viewportWidgetClass, form, args, j);
 -
 -    j = 0;
 -    XtSetArg(args[j], XtNlist, glc->strings);  j++;
 -    XtSetArg(args[j], XtNdefaultColumns, 1);  j++;
 -    XtSetArg(args[j], XtNforceColumns, True);  j++;
 -    XtSetArg(args[j], XtNverticalList, True);  j++;
 -    listwidg = 
 -      XtCreateManagedWidget("list", listWidgetClass, viewport, args, j);
 -    XawListHighlight(listwidg, 0);
 -    XtAugmentTranslations(listwidg,
 -                        XtParseTranslationTable(gameListTranslations));
 -
 -    j = 0;
 -    XtSetArg(args[j], XtNfromVert, viewport);  j++;
 -    XtSetArg(args[j], XtNtop, XtChainBottom); j++;
 -    XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
 -    XtSetArg(args[j], XtNleft, XtChainLeft); j++;
 -    XtSetArg(args[j], XtNright, XtChainLeft); j++;
 -    b_load =
 -      XtCreateManagedWidget(_("load"), commandWidgetClass, form, args, j);
 -    XtAddCallback(b_load, XtNcallback, callback, client_data);
 -
 -    j = 0;
 -    XtSetArg(args[j], XtNfromVert, viewport);  j++;
 -    XtSetArg(args[j], XtNfromHoriz, b_load);  j++;
 -    XtSetArg(args[j], XtNtop, XtChainBottom); j++;
 -    XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
 -    XtSetArg(args[j], XtNleft, XtChainLeft); j++;
 -    XtSetArg(args[j], XtNright, XtChainLeft); j++;
 -    b_loadprev =
 -      XtCreateManagedWidget(_("prev"), commandWidgetClass, form, args, j);
 -    XtAddCallback(b_loadprev, XtNcallback, callback, client_data);
 -
 -    j = 0;
 -    XtSetArg(args[j], XtNfromVert, viewport);  j++;
 -    XtSetArg(args[j], XtNfromHoriz, b_loadprev);  j++;
 -    XtSetArg(args[j], XtNtop, XtChainBottom); j++;
 -    XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
 -    XtSetArg(args[j], XtNleft, XtChainLeft); j++;
 -    XtSetArg(args[j], XtNright, XtChainLeft); j++;
 -    b_loadnext =
 -      XtCreateManagedWidget(_("next"), commandWidgetClass, form, args, j);
 -    XtAddCallback(b_loadnext, XtNcallback, callback, client_data);
 -
 -    j = 0;
 -    XtSetArg(args[j], XtNfromVert, viewport);  j++;
 -    XtSetArg(args[j], XtNfromHoriz, b_loadnext);  j++;
 -    XtSetArg(args[j], XtNtop, XtChainBottom); j++;
 -    XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
 -    XtSetArg(args[j], XtNleft, XtChainLeft); j++;
 -    XtSetArg(args[j], XtNright, XtChainLeft); j++;
 -    b_close =
 -      XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
 -    XtAddCallback(b_close, XtNcallback, callback, client_data);
 -
 -    j = 0;
 -    XtSetArg(args[j], XtNfromVert, viewport);  j++;
 -    XtSetArg(args[j], XtNfromHoriz, b_close);  j++;
 -    XtSetArg(args[j], XtNtop, XtChainBottom); j++;
 -    XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
 -    XtSetArg(args[j], XtNleft, XtChainLeft); j++;
 -    XtSetArg(args[j], XtNright, XtChainLeft); j++;
 -    XtSetArg(args[j], XtNborderWidth, 0); j++;
 -    label =
 -      XtCreateManagedWidget(_("Filter:"), labelWidgetClass, form, args, j);
 -
 -    j = 0;
 -    XtSetArg(args[j], XtNfromVert, viewport);  j++;
 -    XtSetArg(args[j], XtNfromHoriz, label);  j++;
 -    XtSetArg(args[j], XtNtop, XtChainBottom); j++;
 -    XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
 -    XtSetArg(args[j], XtNleft, XtChainLeft); j++;
 -    XtSetArg(args[j], XtNright, XtChainRight); j++;
 -    XtSetArg(args[j], XtNwidth, fw_width - 225 - squareSize); j++;
 -    XtSetArg(args[j], XtNstring, filterString);  j++;
 -    XtSetArg(args[j], XtNdisplayCaret, False);  j++;
 -    XtSetArg(args[j], XtNresizable, True);  j++;
 -//    XtSetArg(args[j], XtNwidth, bw_width);  j++; /*force wider than buttons*/
 -    /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
 -    XtSetArg(args[j], XtNeditType, XawtextEdit);  j++;
 -    XtSetArg(args[j], XtNuseStringInPlace, False);  j++;
 -    filterText =
 -      XtCreateManagedWidget(_("filtertext"), asciiTextWidgetClass, form, args, j);
 -    XtAddEventHandler(filterText, ButtonPressMask, False, SetFocus, (XtPointer) shell);
 -    XtOverrideTranslations(filterText,
 -                        XtParseTranslationTable(filterTranslations));
 -
 -    j = 0;
 -    XtSetArg(args[j], XtNfromVert, viewport);  j++;
 -    XtSetArg(args[j], XtNfromHoriz, filterText);  j++;
 -    XtSetArg(args[j], XtNtop, XtChainBottom); j++;
 -    XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
 -    XtSetArg(args[j], XtNleft, XtChainRight); j++;
 -    XtSetArg(args[j], XtNright, XtChainRight); j++;
 -    b_filter =
 -      XtCreateManagedWidget(_("apply"), commandWidgetClass, form, args, j);
 -    XtAddCallback(b_filter, XtNcallback, callback, client_data);
 -
 -
 -    if(wpGameList.width > 0) {
 -      glc->x = wpGameList.x;
 -      glc->y = wpGameList.y;
 -      glc->w = wpGameList.width;
 -      glc->h = wpGameList.height;
 -    }
 -
 -    if (glc->x == -1) {
 -      Position y1;
 -      Dimension h1;
 -      int xx, yy;
 -      Window junk;
 -
 -      j = 0;
 -      XtSetArg(args[j], XtNheight, &h1); j++;
 -      XtSetArg(args[j], XtNy, &y1); j++;
 -      XtGetValues(boardWidget, args, j);
 -      glc->w = fw_width * 3/4;
 -      glc->h = squareSize * 3;
 -
 -      XSync(xDisplay, False);
 -#ifdef NOTDEF
 -      /* This code seems to tickle an X bug if it is executed too soon
 -         after xboard starts up.  The coordinates get transformed as if
 -         the main window was positioned at (0, 0).
 -      */
 -      XtTranslateCoords(shellWidget, (fw_width - glc->w) / 2,
 -                        y1 + (h1 - glc->h + appData.borderYoffset) / 2,
 -                        &glc->x, &glc->y);
 -#else /*!NOTDEF*/
 -        XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
 -                            RootWindowOfScreen(XtScreen(shellWidget)),
 -                            (fw_width - glc->w) / 2,
 -                            y1 + (h1 - glc->h + appData.borderYoffset) / 2,
 -                            &xx, &yy, &junk);
 -      glc->x = xx;
 -      glc->y = yy;
 -#endif /*!NOTDEF*/
 -      if (glc->y < 0) glc->y = 0; /*avoid positioning top offscreen*/
 -    }
 -    j = 0;
 -    XtSetArg(args[j], XtNheight, glc->h);  j++;
 -    XtSetArg(args[j], XtNwidth, glc->w);  j++;
 -    XtSetArg(args[j], XtNx, glc->x - appData.borderXoffset);  j++;
 -    XtSetArg(args[j], XtNy, glc->y - appData.borderYoffset);  j++;
 -    XtSetValues(shell, args, j);
 -
 -    XtRealizeWidget(shell);
 -    CatchDeleteWindow(shell, "GameListPopDown");
 -    XtSetKeyboardFocus(shell, listwidg);
 -
 -    return shell;
 +  return;
  }
  
+ static int
+ GameListPrepare()
+ {   // [HGM] filter: put in separate routine, to make callable from call-back
+     int nstrings;
+     ListGame *lg;
+     char **st, *line;
+     nstrings = ((ListGame *) gameList.tailPred)->number;
+     glc->strings = (char **) malloc((nstrings + 1) * sizeof(char *));
+     st = glc->strings;
+     lg = (ListGame *) gameList.head;
+     listLength = 0;
+     while (nstrings--) {
+       line = GameListLine(lg->number, &lg->gameInfo);
+       if(filterString[0] == NULLCHAR || SearchPattern( line, filterString ) ) {
+           *st++ = line; // [HGM] filter: make adding line conditional
+           listLength++;
+       }
+       lg = (ListGame *) lg->node.succ;
+      }
+     *st = NULL;
+     return listLength;
+ }
+ static void
+ GameListReplace()
+ {   // [HGM] filter: put in separate routine, to make callable from call-back
+     Arg args[16];
+     int j;
+     Widget listwidg;
+       listwidg = XtNameToWidget(glc->shell, "*form.viewport.list");
+       XawListChange(listwidg, glc->strings, 0, 0, True);
+       XawListHighlight(listwidg, 0);
+ }
  void
  GameListCallback(w, client_data, call_data)
       Widget w;
@@@ -186,39 -433,49 +245,38 @@@ GameListPopUp(fp, filename
       FILE *fp;
       char *filename;
  {
 -    Arg args[16];
 -    int j, nstrings;
 -    Widget listwidg;
 -    ListGame *lg;
 -    char **st;
 -
 -    if (glc == NULL) {
 -      glc = (GameListClosure *) calloc(1, sizeof(GameListClosure));
 -      glc->x = glc->y = -1;
 -    }
 -
 -    if (glc->strings != NULL) {
 -      st = glc->strings;
 -      while (*st) {
 -          free(*st++);
 -      }
 -      free(glc->strings);
 +  GtkTreeIter iter;
 +  int  i=0,nstrings;
 +  ListGame *lg;
 +  
 +  /* first clear everything, do we need this? */
 +  gtk_list_store_clear(LIST_GameList);
 +
 +  /* fill list with information */
 +  lg = (ListGame *) gameList.head;
 +  nstrings = ((ListGame *) gameList.tailPred)->number;
 +  while (nstrings--) 
 +    {
 +      gtk_list_store_append (LIST_GameList, &iter);
 +      gtk_list_store_set (LIST_GameList, &iter,
 +                        0, StrSave(filename),
 +                        1, GameListLine(lg->number, &lg->gameInfo),
 +                        2, fp,
 +                        -1);
 +      lg = (ListGame *) lg->node.succ;
      }
  
 -    GameListPrepare(); // [HGM] filter: code put in separate routine
 -
 -    glc->fp = fp;
 -
 -    if (glc->filename != NULL) free(glc->filename);
 -    glc->filename = StrSave(filename);
 +  /* show widget */
 +  gtk_widget_show (GUI_GameList);
  
 +//    XtPopup(glc->shell, XtGrabNone);
 +//    glc->up = True;
 +//    j = 0;
 +//    XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
 +//    XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Game List"),
 +//            args, j);
  
 -    if (glc->shell == NULL) {
 -      glc->shell = GameListCreate(filename, GameListCallback, glc); 
 -    } else {
 -        GameListReplace(); // [HGM] filter: code put in separate routine
 -      j = 0;
 -      XtSetArg(args[j], XtNiconName, (XtArgVal) filename);  j++;
 -      XtSetArg(args[j], XtNtitle, (XtArgVal) filename);  j++;
 -      XtSetValues(glc->shell, args, j);
 -    }
 -
 -    XtPopup(glc->shell, XtGrabNone);
 -    glc->up = True;
 -    j = 0;
 -    XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
 -    XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Game List"),
 -              args, j);
 +  return;
  }
  
  void
@@@ -280,12 -554,52 +347,35 @@@ LoadSelectedProc(w, event, prms, nprms
  }
  
  void
+ SetFilterProc(w, event, prms, nprms)
+      Widget w;
+      XEvent *event;
+      String *prms;
+      Cardinal *nprms;
+ {
+       Arg args[16];
+         String name;
+       Widget list;
+         int j = 0;
+         XtSetArg(args[j], XtNstring, &name);  j++;
+       XtGetValues(filterText, args, j);
+         strcpy(filterString, name);
+         if(GameListPrepare()) GameListReplace(); // crashes on empty list...
+       list = XtNameToWidget(glc->shell, "*form.viewport.list");
+       XawListHighlight(list, 0);
+         j = 0;
+       XtSetArg(args[j], XtNdisplayCaret, False); j++;
+       XtSetValues(filterText, args, j);
+       XtSetKeyboardFocus(glc->shell, list);
+ }
+ void
  GameListPopDown()
  {
 -    Arg args[16];
 -    int j;
 +  /* hides the history window */
  
 -    if (glc == NULL) return;
 -    j = 0;
 -    XtSetArg(args[j], XtNx, &glc->x); j++;
 -    XtSetArg(args[j], XtNy, &glc->y); j++;
 -    XtSetArg(args[j], XtNheight, &glc->h); j++;
 -    XtSetArg(args[j], XtNwidth, &glc->w); j++;
 -    XtGetValues(glc->shell, args, j);
 -    wpGameList.x = glc->x - 4;
 -    wpGameList.y = glc->y - 23;
 -    wpGameList.width = glc->w;
 -    wpGameList.height = glc->h;
 -    XtPopdown(glc->shell);
 -    XtSetKeyboardFocus(shellWidget, formWidget);
 -    glc->up = False;
 -    j = 0;
 -    XtSetArg(args[j], XtNleftBitmap, None); j++;
 -    XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Game List"),
 -              args, j);
 +  gtk_widget_hide (GUI_GameList);
 +  return;
  }
  
  void
@@@ -301,7 -618,218 +394,220 @@@ GameListHighlight(index
  Boolean
  GameListIsUp()
  {
 -    return glc && glc->up;
 +  /* return status of history window */
 +  
 +  return gtk_widget_get_visible (GUI_GameList);
  }
+ //--------------------------------- Game-List options dialog ------------------------------------------
+ Widget gameListOptShell, listwidg;
+ char *strings[20];
+ int stringPtr;
+ void GLT_ClearList()
+ {
+     strings[0] = NULL;
+     stringPtr = 0;
+ }
+ void GLT_AddToList(char *name)
+ {
+     strings[stringPtr++] = name;
+     strings[stringPtr] = NULL;
+ }
+ Boolean GLT_GetFromList(int index, char *name)
+ {
+     strcpy(name, strings[index]);
+ }
+ void GLT_DeSelectList()
+ {
+     XawListChange(listwidg, strings, 0, 0, True);
+     XawListHighlight(listwidg, 0);
+ }
+ void
+ GameListOptionsPopDown()
+ {
+     Arg args[16];
+     int j;
+     if (gameListOptShell == NULL) return;
+     XtPopdown(gameListOptShell);
+     XtDestroyWidget(gameListOptShell);
+     gameListOptShell = 0;
+     XtSetKeyboardFocus(shellWidget, formWidget);
+ }
+ void
+ GameListOptionsCallback(w, client_data, call_data)
+      Widget w;
+      XtPointer client_data, call_data;
+ {
+     String name;
+     Arg args[16];
+     int j;
+     Widget listwidg;
+     XawListReturnStruct *rs;
+     int index;
+     char *p;
+     j = 0;
+     XtSetArg(args[j], XtNlabel, &name);  j++;
+     XtGetValues(w, args, j);
+     if (strcmp(name, _("OK")) == 0) {
+       GLT_ParseList();
+       appData.gameListTags = strdup(lpUserGLT);
+       GameListOptionsPopDown();
+       return;
+     } else
+     if (strcmp(name, _("cancel")) == 0) {
+       GameListOptionsPopDown();
+       return;
+     }
+     listwidg = XtNameToWidget(gameListOptShell, "*form.list");
+     rs = XawListShowCurrent(listwidg);
+     index = rs->list_index;
+     if (index < 0) {
+       DisplayError(_("No tag selected"), 0);
+       return;
+     }
+     p = strings[index];
+     if (strcmp(name, _("down")) == 0) {
+         if(index >= strlen(GLT_ALL_TAGS)) return;
+       strings[index] = strings[index+1];
+       strings[++index] = p;
+     } else
+     if (strcmp(name, _("up")) == 0) {
+         if(index == 0) return;
+       strings[index] = strings[index-1];
+       strings[--index] = p;
+     } else
+     if (strcmp(name, _("factory")) == 0) {
+       strcpy(lpUserGLT, GLT_DEFAULT_TAGS);
+       GLT_TagsToList(lpUserGLT);
+       index = 0;
+     }
+     XawListHighlight(listwidg, index);
+ }
+ Widget
+ GameListOptionsCreate()
+ {
+     Arg args[16];
+     Widget shell, form, viewport, layout;
+     Widget b_load, b_loadprev, b_loadnext, b_close, b_cancel;
+     Dimension fw_width;
+     XtPointer client_data = NULL;
+     int j;
+     j = 0;
+     XtSetArg(args[j], XtNwidth, &fw_width);  j++;
+     XtGetValues(formWidget, args, j);
+     j = 0;
+     XtSetArg(args[j], XtNresizable, True);  j++;
+     XtSetArg(args[j], XtNallowShellResize, True);  j++;
+     shell = gameListOptShell =
+       XtCreatePopupShell("Game-list options", transientShellWidgetClass,
+                        shellWidget, args, j);
+     layout =
+       XtCreateManagedWidget(layoutName, formWidgetClass, shell,
+                           layoutArgs, XtNumber(layoutArgs));
+     j = 0;
+     XtSetArg(args[j], XtNborderWidth, 0); j++;
+     form =
+       XtCreateManagedWidget("form", formWidgetClass, layout, args, j);
+     j = 0;
+     XtSetArg(args[j], XtNdefaultColumns, 1);  j++;
+     XtSetArg(args[j], XtNforceColumns, True);  j++;
+     XtSetArg(args[j], XtNverticalList, True);  j++;
+     listwidg = viewport =
+       XtCreateManagedWidget("list", listWidgetClass, form, args, j);
+     XawListHighlight(listwidg, 0);
+ //    XtAugmentTranslations(listwidg,
+ //                      XtParseTranslationTable(gameListOptTranslations));
+     j = 0;
+     XtSetArg(args[j], XtNfromVert, viewport);  j++;
+     XtSetArg(args[j], XtNtop, XtChainBottom); j++;
+     XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
+     XtSetArg(args[j], XtNleft, XtChainLeft); j++;
+     XtSetArg(args[j], XtNright, XtChainLeft); j++;
+     b_load =
+       XtCreateManagedWidget(_("factory"), commandWidgetClass, form, args, j);
+     XtAddCallback(b_load, XtNcallback, GameListOptionsCallback, client_data);
+     j = 0;
+     XtSetArg(args[j], XtNfromVert, viewport);  j++;
+     XtSetArg(args[j], XtNfromHoriz, b_load);  j++;
+     XtSetArg(args[j], XtNtop, XtChainBottom); j++;
+     XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
+     XtSetArg(args[j], XtNleft, XtChainLeft); j++;
+     XtSetArg(args[j], XtNright, XtChainLeft); j++;
+     b_loadprev =
+       XtCreateManagedWidget(_("up"), commandWidgetClass, form, args, j);
+     XtAddCallback(b_loadprev, XtNcallback, GameListOptionsCallback, client_data);
+     j = 0;
+     XtSetArg(args[j], XtNfromVert, viewport);  j++;
+     XtSetArg(args[j], XtNfromHoriz, b_loadprev);  j++;
+     XtSetArg(args[j], XtNtop, XtChainBottom); j++;
+     XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
+     XtSetArg(args[j], XtNleft, XtChainLeft); j++;
+     XtSetArg(args[j], XtNright, XtChainLeft); j++;
+     b_loadnext =
+       XtCreateManagedWidget(_("down"), commandWidgetClass, form, args, j);
+     XtAddCallback(b_loadnext, XtNcallback, GameListOptionsCallback, client_data);
+     j = 0;
+     XtSetArg(args[j], XtNfromVert, viewport);  j++;
+     XtSetArg(args[j], XtNfromHoriz, b_loadnext);  j++;
+     XtSetArg(args[j], XtNtop, XtChainBottom); j++;
+     XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
+     XtSetArg(args[j], XtNleft, XtChainLeft); j++;
+     XtSetArg(args[j], XtNright, XtChainLeft); j++;
+     b_cancel =
+       XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
+     XtAddCallback(b_cancel, XtNcallback, GameListOptionsCallback, client_data);
+     j = 0;
+     XtSetArg(args[j], XtNfromVert, viewport);  j++;
+     XtSetArg(args[j], XtNfromHoriz, b_cancel);  j++;
+     XtSetArg(args[j], XtNtop, XtChainBottom); j++;
+     XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
+     XtSetArg(args[j], XtNleft, XtChainLeft); j++;
+     XtSetArg(args[j], XtNright, XtChainLeft); j++;
+     b_close =
+       XtCreateManagedWidget(_("OK"), commandWidgetClass, form, args, j);
+     XtAddCallback(b_close, XtNcallback, GameListOptionsCallback, client_data);
+     strcpy(lpUserGLT, appData.gameListTags);
+     GLT_TagsToList(lpUserGLT);
+     XtRealizeWidget(shell);
+     CatchDeleteWindow(shell, "GameListOptionsPopDown");
+     return shell;
+ }
+ void
+ GameListOptionsPopUp(Widget w, XEvent *event, String *prms, Cardinal *nprms)
+ {
+     Arg args[16];
+     int j, nstrings;
+     Widget listwidg;
+     if (gameListOptShell == NULL) {
+       gameListOptShell = GameListOptionsCreate(); 
+     }
+     XtPopup(gameListOptShell, XtGrabNone);
+ }
diff --cc xoptions.c
Simple merge