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)
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;
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);
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;
}
}
}
+ 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;
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 */
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 &&
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])
--/*
++Xg/*
* xboard.c -- X front end for XBoard
*
* Copyright 1991 by Digital Equipment Corporation, Maynard,
{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},
{ "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 },
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;
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)
/*
* 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];
}
}
# 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;
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;
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
}
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
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);
+ }
+
+