X-Git-Url: http://winboard.nl/cgi-bin?p=xboard.git;a=blobdiff_plain;f=xboard.c;h=0e8b132d0e9d7b9c9f4f07632fd5af69c1379f6f;hp=36987280a8c0522ecda17115c1fcc42ca5ae680f;hb=d016fb202fe45795e630e22ba516e754cf694ea6;hpb=912ff451e7a648f6aa3ba7d2a10df2a1dc2cace5 diff --git a/xboard.c b/xboard.c index 3698728..0e8b132 100644 --- a/xboard.c +++ b/xboard.c @@ -1,9 +1,11 @@ /* * xboard.c -- X front end for XBoard - * $Id$ * - * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts. - * Enhancements Copyright 1992-2001 Free Software Foundation, Inc. + * Copyright 1991 by Digital Equipment Corporation, Maynard, + * Massachusetts. + * + * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006, + * 2007, 2008, 2009 Free Software Foundation, Inc. * * The following terms apply to Digital Equipment Corporation's copyright * interest in XBoard: @@ -27,26 +29,25 @@ * SOFTWARE. * ------------------------------------------------------------------------ * - * The following terms apply to the enhanced version of XBoard distributed - * by the Free Software Foundation: + * The following terms apply to the enhanced version of XBoard + * distributed by the Free Software Foundation: * ------------------------------------------------------------------------ - * This program is free software; you can redistribute it and/or modify + * + * GNU XBoard is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU XBoard is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * ------------------------------------------------------------------------ + * along with this program. If not, see http://www.gnu.org/licenses/. * * - * See the file ChangeLog for a revision history. - */ + *------------------------------------------------------------------------ + ** See the file ChangeLog for a revision history. */ #include "config.h" @@ -169,6 +170,9 @@ extern char *getenv(); #include #endif +// [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are. +#include "common.h" + #if HAVE_LIBXPM #include #include "pixmaps/pixmaps.h" @@ -182,7 +186,6 @@ extern char *getenv(); #include "bitmaps/icon_black.bm" #include "bitmaps/checkmark.bm" -#include "common.h" #include "frontend.h" #include "backend.h" #include "moves.h" @@ -193,6 +196,14 @@ extern char *getenv(); #include "xedittags.h" #include "gettext.h" +// must be moved to xengineoutput.h + +void EngineOutputProc P((Widget w, XEvent *event, + String *prms, Cardinal *nprms)); + +void EngineOutputPopDown(); + + #ifdef __EMX__ #ifndef HAVE_USLEEP #define HAVE_USLEEP @@ -249,7 +260,7 @@ void BlackClock P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); void DrawPositionProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); -void XDrawPosition P((Widget w, /*Boolean*/int repaint, +void XDrawPosition P((Widget w, /*Boolean*/int repaint, Board board)); void CommentPopUp P((char *title, char *label)); void CommentPopDown P((void)); @@ -335,6 +346,9 @@ void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); +void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); +void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); +void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); void StopObservingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); @@ -392,6 +406,8 @@ void ShowCoordsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); void ShowThinkingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); +void HideThinkingProc P((Widget w, XEvent *event, String *prms, + Cardinal *nprms)); void TestLegalityProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); @@ -416,7 +432,20 @@ static void DragPieceMove P((int x, int y)); static void DragPieceEnd P((int x, int y)); static void DrawDragPiece P((void)); char *ModeToWidgetName P((GameMode mode)); - +void EngineOutputUpdate( FrontEndProgramStats * stats ); +void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); +void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); +void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); +void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); +void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); +void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); +void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); +void ShufflePopDown P(()); +void EnginePopDown P(()); +void UciPopDown P(()); +void TimeControlPopDown P(()); +void NewVariantPopDown P(()); +void SettingsPopDown P(()); /* * XBoard depends on Xt R4 or higher */ @@ -427,30 +456,33 @@ Display *xDisplay; Window xBoardWindow; Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor, jailSquareColor, highlightSquareColor, premoveHighlightColor; +Pixel lowTimeWarningColor; GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC, bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC, - wjPieceGC, bjPieceGC, prelineGC; + wjPieceGC, bjPieceGC, prelineGC, countGC; Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap; -Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget, - whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16], +Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget, + whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16], commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu, menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell, ICSInputShell, fileNameShell, askQuestionShell; XSegment gridSegments[(BOARD_SIZE + 1) * 2]; XSegment jailGridSegments[(BOARD_SIZE + 3) * 2]; -Font clockFontID, coordFontID; -XFontStruct *clockFontStruct, *coordFontStruct; +Font clockFontID, coordFontID, countFontID; +XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct; XtAppContext appContext; char *layoutName; char *oldICSInteractionTitle; FileProc fileProc; char *fileOpenMode; +char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion Position commentX = -1, commentY = -1; Dimension commentW, commentH; int squareSize, smallLayout = 0, tinyLayout = 0, + marginW, marginH, // [HGM] for run-time resizing fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False, ICSInputBoxUp = False, askQuestionUp = False, filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1, @@ -462,17 +494,20 @@ char *chessDir, *programName, *programVersion, #define SOLID 0 #define OUTLINE 1 -Pixmap pieceBitmap[2][6]; -Pixmap xpmPieceBitmap[4][6]; /* LL, LD, DL, DD */ +Pixmap pieceBitmap[2][(int)BlackPawn]; +Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */ +Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/ +Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */ Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare; int useImages, useImageSqs; -XImage *ximPieceBitmap[4][6]; /* LL, LD, DL, DD */ -Pixmap ximMaskPm[6]; /* clipmasks, used for XIM pieces */ +XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */ +Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */ +Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */ XImage *ximLightSquare, *ximDarkSquare; XImage *xim_Cross; -#define pieceToSolid(piece) &pieceBitmap[SOLID][((int)(piece)) % 6] -#define pieceToOutline(piece) &pieceBitmap[OUTLINE][((int)(piece)) % 6] +#define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn] +#define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn] #define White(piece) ((int)(piece) < (int)BlackPawn) @@ -508,7 +543,9 @@ static Pixmap xpmMask[BlackKing + 1]; SizeDefaults sizeDefaults[] = SIZE_DEFAULTS; MenuItem fileMenu[] = { - {N_("Reset Game"), ResetProc}, + {N_("New Game"), ResetProc}, + {N_("New Shuffle Game ..."), ShuffleMenuProc}, + {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet {"----", NothingProc}, {N_("Load Game"), LoadGameProc}, {N_("Load Next Game"), LoadNextGameProc}, @@ -546,8 +583,11 @@ MenuItem modeMenu[] = { {N_("Edit Position"), EditPositionProc}, {N_("Training"), TrainingProc}, {"----", NothingProc}, + {N_("Show Engine Output"), EngineOutputProc}, + {N_("Show Evaluation Graph"), NothingProc}, // [HGM] evalgr: not functional yet {N_("Show Game List"), ShowGameListProc}, - {N_("Show Move List"), HistoryShowProc}, + {"Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code + {"----", NothingProc}, {N_("Edit Tags"), EditTagsProc}, {N_("Edit Comment"), EditCommentProc}, {N_("ICS Input Box"), IcsInputBoxProc}, @@ -559,15 +599,19 @@ MenuItem actionMenu[] = { {N_("Accept"), AcceptProc}, {N_("Decline"), DeclineProc}, {N_("Rematch"), RematchProc}, - {"----", NothingProc}, + {"----", NothingProc}, {N_("Call Flag"), CallFlagProc}, {N_("Draw"), DrawProc}, {N_("Adjourn"), AdjournProc}, {N_("Abort"), AbortProc}, {N_("Resign"), ResignProc}, - {"----", NothingProc}, + {"----", NothingProc}, {N_("Stop Observing"), StopObservingProc}, {N_("Stop Examining"), StopExaminingProc}, + {"----", NothingProc}, + {N_("Adjudicate to White"), AdjuWhiteProc}, + {N_("Adjudicate to Black"), AdjuBlackProc}, + {N_("Adjudicate Draw"), AdjuDrawProc}, {NULL, NULL} }; @@ -578,13 +622,21 @@ MenuItem stepMenu[] = { {N_("Forward to End"), ToEndProc}, {N_("Revert"), RevertProc}, {N_("Truncate Game"), TruncateGameProc}, - {"----", NothingProc}, + {"----", NothingProc}, {N_("Move Now"), MoveNowProc}, {N_("Retract Move"), RetractMoveProc}, {NULL, NULL} -}; +}; MenuItem optionsMenu[] = { + {N_("Flip View"), FlipViewProc}, + {"----", NothingProc}, + {N_("Adjudications ..."), EngineMenuProc}, + {N_("General Settings ..."), UciMenuProc}, + {N_("Engine #1 Settings ..."), FirstSettingsProc}, + {N_("Engine #2 Settings ..."), SecondSettingsProc}, + {N_("Time Control ..."), TimeControlProc}, + {"----", NothingProc}, {N_("Always Queen"), AlwaysQueenProc}, {N_("Animate Dragging"), AnimateDraggingProc}, {N_("Animate Moving"), AnimateMovingProc}, @@ -596,7 +648,6 @@ MenuItem optionsMenu[] = { {N_("Auto Save"), AutosaveProc}, {N_("Blindfold"), BlindfoldProc}, {N_("Flash Moves"), FlashMovesProc}, - {N_("Flip View"), FlipViewProc}, {N_("Get Move List"), GetMoveListProc}, #if HIGHDRAG {N_("Highlight Dragging"), HighlightDraggingProc}, @@ -605,14 +656,14 @@ MenuItem optionsMenu[] = { {N_("Move Sound"), MoveSoundProc}, {N_("ICS Alarm"), IcsAlarmProc}, {N_("Old Save Style"), OldSaveStyleProc}, - {N_("Periodic Updates"), PeriodicUpdatesProc}, + {N_("Periodic Updates"), PeriodicUpdatesProc}, {N_("Ponder Next Move"), PonderNextMoveProc}, - {N_("Popup Exit Message"), PopupExitMessageProc}, - {N_("Popup Move Errors"), PopupMoveErrorsProc}, + {N_("Popup Exit Message"), PopupExitMessageProc}, + {N_("Popup Move Errors"), PopupMoveErrorsProc}, {N_("Premove"), PremoveProc}, {N_("Quiet Play"), QuietPlayProc}, {N_("Show Coords"), ShowCoordsProc}, - {N_("Show Thinking"), ShowThinkingProc}, + {N_("Hide Thinking"), HideThinkingProc}, {N_("Test Legality"), TestLegalityProc}, {NULL, NULL} }; @@ -638,8 +689,6 @@ Menu menuBar[] = { {NULL, NULL} }; - -/* Label on pause button */ #define PAUSE_BUTTON N_("P") MenuItem buttonBar[] = { {"<<", ToStartProc}, @@ -650,21 +699,27 @@ MenuItem buttonBar[] = { {NULL, NULL} }; -#define PIECE_MENU_SIZE 11 +#define PIECE_MENU_SIZE 18 String pieceMenuStrings[2][PIECE_MENU_SIZE] = { { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), - N_("Queen"), N_("King"), "----", N_("Empty square"), N_("Clear board") }, + N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"), + N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"), + N_("Empty square"), N_("Clear board") }, { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), - N_("Queen"), N_("King"), "----", N_("Empty square"), N_("Clear board") }, - }; + N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"), + N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"), + N_("Empty square"), N_("Clear board") } +}; /* must be in same order as PieceMenuStrings! */ ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = { { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop, - WhiteRook, WhiteQueen, WhiteKing, - (ChessSquare) 0, EmptySquare, ClearBoard }, + WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil, + WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0, + PromotePiece, DemotePiece, EmptySquare, ClearBoard }, { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop, - BlackRook, BlackQueen, BlackKing, - (ChessSquare) 0, EmptySquare, ClearBoard }, + BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil, + BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0, + PromotePiece, DemotePiece, EmptySquare, ClearBoard }, }; #define DROP_MENU_SIZE 6 @@ -743,7 +798,7 @@ XtResource clientResources[] = { BLACK_PIECE_COLOR }, { "lightSquareColor", "lightSquareColor", XtRString, sizeof(String), XtOffset(AppDataPtr, lightSquareColor), - XtRString, LIGHT_SQUARE_COLOR }, + XtRString, LIGHT_SQUARE_COLOR }, { "darkSquareColor", "darkSquareColor", XtRString, sizeof(String), XtOffset(AppDataPtr, darkSquareColor), XtRString, DARK_SQUARE_COLOR }, @@ -786,9 +841,9 @@ XtResource clientResources[] = { { "secondHost", "secondHost", XtRString, sizeof(String), XtOffset(AppDataPtr, secondHost), XtRString, SECOND_HOST }, { "firstDirectory", "firstDirectory", XtRString, sizeof(String), - XtOffset(AppDataPtr, firstDirectory), XtRString, "" }, + XtOffset(AppDataPtr, firstDirectory), XtRString, "." }, { "secondDirectory", "secondDirectory", XtRString, sizeof(String), - XtOffset(AppDataPtr, secondDirectory), XtRString, "" }, + XtOffset(AppDataPtr, secondDirectory), XtRString, "." }, { "bitmapDirectory", "bitmapDirectory", XtRString, sizeof(String), XtOffset(AppDataPtr, bitmapDirectory), XtRString, "" }, @@ -891,7 +946,7 @@ XtResource clientResources[] = { XtOffset(AppDataPtr, searchTime), XtRString, (XtPointer) "" }, { "searchDepth", "searchDepth", XtRInt, sizeof(int), - XtOffset(AppDataPtr, searchDepth), XtRImmediate, + XtOffset(AppDataPtr, searchDepth), XtRImmediate, (XtPointer) 0 }, { "showCoords", "showCoords", XtRBoolean, sizeof(Boolean), XtOffset(AppDataPtr, showCoords), XtRImmediate, @@ -901,7 +956,7 @@ XtResource clientResources[] = { (XtPointer) 0 }, { "showThinking", "showThinking", XtRBoolean, sizeof(Boolean), XtOffset(AppDataPtr, showThinking), XtRImmediate, - (XtPointer) False }, + (XtPointer) True }, { "ponderNextMove", "ponderNextMove", XtRBoolean, sizeof(Boolean), XtOffset(AppDataPtr, ponderNextMove), XtRImmediate, (XtPointer) True }, @@ -967,7 +1022,7 @@ XtResource clientResources[] = { { "localLineEditing", "localLineEditing", XtRBoolean, sizeof(Boolean), XtOffset(AppDataPtr, localLineEditing), XtRImmediate, (XtPointer) True }, /* not implemented, must be True */ -#ifdef ZIPPY +#if ZIPPY { "zippyTalk", "zippyTalk", XtRBoolean, sizeof(Boolean), XtOffset(AppDataPtr, zippyTalk), XtRImmediate, (XtPointer) ZIPPY_TALK }, @@ -1014,6 +1069,9 @@ XtResource clientResources[] = { { "zippyReplayTimeout", "zippyReplayTimeout", XtRInt, sizeof(int), XtOffset(AppDataPtr, zippyReplayTimeout), XtRImmediate, (XtPointer) ZIPPY_REPLAY_TIMEOUT }, + { "zippyShortGame", "zippyShortGame", XtRInt, sizeof(int), + XtOffset(AppDataPtr, zippyShortGame), XtRImmediate, + (XtPointer) 0 }, #endif { "flashCount", "flashCount", XtRInt, sizeof(int), XtOffset(AppDataPtr, flashCount), XtRImmediate, @@ -1029,7 +1087,7 @@ XtResource clientResources[] = { (XtPointer) MS_LOGIN_DELAY }, { "colorizeMessages", "colorizeMessages", XtRBoolean, sizeof(Boolean), XtOffset(AppDataPtr, colorize), - XtRImmediate, (XtPointer) False }, + XtRImmediate, (XtPointer) False }, { "colorShout", "colorShout", XtRString, sizeof(String), XtOffset(AppDataPtr, colorShout), XtRString, COLOR_SHOUT }, @@ -1059,7 +1117,7 @@ XtResource clientResources[] = { XtRString, COLOR_SEEK }, { "colorNormal", "colorNormal", XtRString, sizeof(String), XtOffset(AppDataPtr, colorNormal), - XtRString, COLOR_NORMAL }, + XtRString, COLOR_NORMAL }, { "soundProgram", "soundProgram", XtRString, sizeof(String), XtOffset(AppDataPtr, soundProgram), XtRString, "play" }, @@ -1147,10 +1205,205 @@ XtResource clientResources[] = { { "showButtonBar", "showButtonBar", XtRBoolean, sizeof(Boolean), XtOffset(AppDataPtr, showButtonBar), XtRImmediate, (XtPointer) True }, - /* icsEngineAnalyze */ - {"icsEngineAnalyze", "icsEngineAnalyze", XtRBoolean, - sizeof(Boolean), XtOffset(AppDataPtr, icsEngineAnalyze), - XtRImmediate, (XtPointer) False }, + { "lowTimeWarningColor", "lowTimeWarningColor", XtRString, + sizeof(String), XtOffset(AppDataPtr, lowTimeWarningColor), + XtRString, COLOR_LOWTIMEWARNING }, + { "lowTimeWarning", "lowTimeWarning", XtRBoolean, + sizeof(Boolean), XtOffset(AppDataPtr, lowTimeWarning), + XtRImmediate, (XtPointer) False }, + {"icsEngineAnalyze", "icsEngineAnalyze", XtRBoolean, /* [DM] icsEngineAnalyze */ + sizeof(Boolean), XtOffset(AppDataPtr, icsEngineAnalyze), + XtRImmediate, (XtPointer) False }, + { "firstScoreAbs", "firstScoreAbs", XtRBoolean, + sizeof(Boolean), XtOffset(AppDataPtr, firstScoreIsAbsolute), + XtRImmediate, (XtPointer) False }, + { "secondScoreAbs", "secondScoreAbs", XtRBoolean, + sizeof(Boolean), XtOffset(AppDataPtr, secondScoreIsAbsolute), + XtRImmediate, (XtPointer) False }, + { "pgnExtendedInfo", "pgnExtendedInfo", XtRBoolean, + sizeof(Boolean), XtOffset(AppDataPtr, saveExtendedInfoInPGN), + XtRImmediate, (XtPointer) False }, + { "hideThinkingFromHuman", "hideThinkingFromHuman", XtRBoolean, + sizeof(Boolean), XtOffset(AppDataPtr, hideThinkingFromHuman), + XtRImmediate, (XtPointer) True }, + { "adjudicateLossThreshold", "adjudicateLossThreshold", XtRInt, + sizeof(int), XtOffset(AppDataPtr, adjudicateLossThreshold), + XtRImmediate, (XtPointer) 0}, + { "adjudicateDrawMoves", "adjudicateDrawMoves", XtRInt, + sizeof(int), XtOffset(AppDataPtr, adjudicateDrawMoves), + XtRImmediate, (XtPointer) 0}, + { "pgnEventHeader", "pgnEventHeader", XtRString, + sizeof(String), XtOffset(AppDataPtr, pgnEventHeader), + XtRImmediate, (XtPointer) "Computer Chess Game" }, + { "defaultFrcPosition", "defaultFrcPositon", XtRInt, + sizeof(int), XtOffset(AppDataPtr, defaultFrcPosition), + XtRImmediate, (XtPointer) -1}, + { "gameListTags", "gameListTags", XtRString, + sizeof(String), XtOffset(AppDataPtr, gameListTags), + XtRImmediate, (XtPointer) GLT_DEFAULT_TAGS }, + + // [HGM] 4.3.xx options + { "boardWidth", "boardWidth", XtRInt, + sizeof(int), XtOffset(AppDataPtr, NrFiles), + XtRImmediate, (XtPointer) -1}, + { "boardHeight", "boardHeight", XtRInt, + sizeof(int), XtOffset(AppDataPtr, NrRanks), + XtRImmediate, (XtPointer) -1}, + { "matchPause", "matchPause", XtRInt, + sizeof(int), XtOffset(AppDataPtr, matchPause), + XtRImmediate, (XtPointer) 10000}, + { "holdingsSize", "holdingsSize", XtRInt, + sizeof(int), XtOffset(AppDataPtr, holdingsSize), + XtRImmediate, (XtPointer) -1}, + { "flipBlack", "flipBlack", XtRBoolean, + sizeof(Boolean), XtOffset(AppDataPtr, upsideDown), + XtRImmediate, (XtPointer) False}, + { "allWhite", "allWhite", XtRBoolean, + sizeof(Boolean), XtOffset(AppDataPtr, allWhite), + XtRImmediate, (XtPointer) False}, + { "pieceToCharTable", "pieceToCharTable", XtRString, + sizeof(String), XtOffset(AppDataPtr, pieceToCharTable), + XtRImmediate, (XtPointer) 0}, + { "alphaRank", "alphaRank", XtRBoolean, + sizeof(Boolean), XtOffset(AppDataPtr, alphaRank), + XtRImmediate, (XtPointer) False}, + { "testClaims", "testClaims", XtRBoolean, + sizeof(Boolean), XtOffset(AppDataPtr, testClaims), + XtRImmediate, (XtPointer) True}, + { "checkMates", "checkMates", XtRBoolean, + sizeof(Boolean), XtOffset(AppDataPtr, checkMates), + XtRImmediate, (XtPointer) True}, + { "materialDraws", "materialDraws", XtRBoolean, + sizeof(Boolean), XtOffset(AppDataPtr, materialDraws), + XtRImmediate, (XtPointer) True}, + { "trivialDraws", "trivialDraws", XtRBoolean, + sizeof(Boolean), XtOffset(AppDataPtr, trivialDraws), + XtRImmediate, (XtPointer) False}, + { "ruleMoves", "ruleMoves", XtRInt, + sizeof(int), XtOffset(AppDataPtr, ruleMoves), + XtRImmediate, (XtPointer) 51}, + { "repeatsToDraw", "repeatsToDraw", XtRInt, + sizeof(int), XtOffset(AppDataPtr, drawRepeats), + XtRImmediate, (XtPointer) 6}, + { "engineDebugOutput", "engineDebugOutput", XtRInt, + sizeof(int), XtOffset(AppDataPtr, engineComments), + XtRImmediate, (XtPointer) 1}, + { "userName", "userName", XtRString, + sizeof(int), XtOffset(AppDataPtr, userName), + XtRImmediate, (XtPointer) 0}, + { "autoKibitz", "autoKibitz", XtRBoolean, + sizeof(Boolean), XtOffset(AppDataPtr, autoKibitz), + XtRImmediate, (XtPointer) False}, + { "firstTimeOdds", "firstTimeOdds", XtRInt, + sizeof(int), XtOffset(AppDataPtr, firstTimeOdds), + XtRImmediate, (XtPointer) 1}, + { "secondTimeOdds", "secondTimeOdds", XtRInt, + sizeof(int), XtOffset(AppDataPtr, secondTimeOdds), + XtRImmediate, (XtPointer) 1}, + { "timeOddsMode", "timeOddsMode", XtRInt, + sizeof(int), XtOffset(AppDataPtr, timeOddsMode), + XtRImmediate, (XtPointer) 0}, + { "firstAccumulateTC", "firstAccumulateTC", XtRInt, + sizeof(int), XtOffset(AppDataPtr, firstAccumulateTC), + XtRImmediate, (XtPointer) 1}, + { "secondAccumulateTC", "secondAccumulateTC", XtRInt, + sizeof(int), XtOffset(AppDataPtr, secondAccumulateTC), + XtRImmediate, (XtPointer) 1}, + { "firstNPS", "firstNPS", XtRInt, + sizeof(int), XtOffset(AppDataPtr, firstNPS), + XtRImmediate, (XtPointer) -1}, + { "secondNPS", "secondNPS", XtRInt, + sizeof(int), XtOffset(AppDataPtr, secondNPS), + XtRImmediate, (XtPointer) -1}, + { "serverMoves", "serverMoves", XtRString, + sizeof(String), XtOffset(AppDataPtr, serverMovesName), + XtRImmediate, (XtPointer) 0}, + { "serverPause", "serverPause", XtRInt, + sizeof(int), XtOffset(AppDataPtr, serverPause), + XtRImmediate, (XtPointer) 0}, + { "suppressLoadMoves", "suppressLoadMoves", XtRBoolean, + sizeof(Boolean), XtOffset(AppDataPtr, suppressLoadMoves), + XtRImmediate, (XtPointer) False}, + { "userName", "userName", XtRString, + sizeof(String), XtOffset(AppDataPtr, userName), + XtRImmediate, (XtPointer) 0}, + { "egtFormats", "egtFormats", XtRString, + sizeof(String), XtOffset(AppDataPtr, egtFormats), + XtRImmediate, (XtPointer) 0}, + { "rewindIndex", "rewindIndex", XtRInt, + sizeof(int), XtOffset(AppDataPtr, rewindIndex), + XtRImmediate, (XtPointer) 0}, + { "sameColorGames", "sameColorGames", XtRInt, + sizeof(int), XtOffset(AppDataPtr, sameColorGames), + XtRImmediate, (XtPointer) 0}, + { "smpCores", "smpCores", XtRInt, + sizeof(int), XtOffset(AppDataPtr, smpCores), + XtRImmediate, (XtPointer) 1}, + { "niceEngines", "niceEngines", XtRInt, + sizeof(int), XtOffset(AppDataPtr, niceEngines), + XtRImmediate, (XtPointer) 0}, + { "nameOfDebugFile", "nameOfDebugFile", XtRString, + sizeof(String), XtOffset(AppDataPtr, nameOfDebugFile), + XtRImmediate, (XtPointer) "xboard.debug"}, + { "engineDebugOutput", "engineDebugOutput", XtRInt, + sizeof(int), XtOffset(AppDataPtr, engineComments), + XtRImmediate, (XtPointer) 1}, + { "noGUI", "noGUI", XtRBoolean, + sizeof(Boolean), XtOffset(AppDataPtr, noGUI), + XtRImmediate, (XtPointer) 0}, + { "firstOptions", "firstOptions", XtRString, + sizeof(String), XtOffset(AppDataPtr, firstOptions), + XtRImmediate, (XtPointer) "" }, + { "secondOptions", "secondOptions", XtRString, + sizeof(String), XtOffset(AppDataPtr, secondOptions), + XtRImmediate, (XtPointer) "" }, + { "firstNeedsNoncompliantFEN", "firstNeedsNoncompliantFEN", XtRString, + sizeof(String), XtOffset(AppDataPtr, fenOverride1), + XtRImmediate, (XtPointer) 0 }, + { "secondNeedsNoncompliantFEN", "secondNeedsNoncompliantFEN", XtRString, + sizeof(String), XtOffset(AppDataPtr, fenOverride2), + XtRImmediate, (XtPointer) 0 }, + + // [HGM] Winboard_x UCI options + { "firstIsUCI", "firstIsUCI", XtRBoolean, + sizeof(Boolean), XtOffset(AppDataPtr, firstIsUCI), + XtRImmediate, (XtPointer) False}, + { "secondIsUCI", "secondIsUCI", XtRBoolean, + sizeof(Boolean), XtOffset(AppDataPtr, secondIsUCI), + XtRImmediate, (XtPointer) False}, + { "firstHasOwnBookUCI", "firstHasOwnBookUCI", XtRBoolean, + sizeof(Boolean), XtOffset(AppDataPtr, firstHasOwnBookUCI), + XtRImmediate, (XtPointer) True}, + { "secondHasOwnBookUCI", "secondHasOwnBookUCI", XtRBoolean, + sizeof(Boolean), XtOffset(AppDataPtr, secondHasOwnBookUCI), + XtRImmediate, (XtPointer) True}, + { "usePolyglotBook", "usePolyglotBook", XtRBoolean, + sizeof(Boolean), XtOffset(AppDataPtr, usePolyglotBook), + XtRImmediate, (XtPointer) False}, + { "defaultHashSize", "defaultHashSize", XtRInt, + sizeof(int), XtOffset(AppDataPtr, defaultHashSize), + XtRImmediate, (XtPointer) 64}, + { "defaultCacheSizeEGTB", "defaultCacheSizeEGTB", XtRInt, + sizeof(int), XtOffset(AppDataPtr, defaultCacheSizeEGTB), + XtRImmediate, (XtPointer) 4}, + { "polyglotDir", "polyglotDir", XtRString, + sizeof(String), XtOffset(AppDataPtr, polyglotDir), + XtRImmediate, (XtPointer) "." }, + { "polyglotBook", "polyglotBook", XtRString, + sizeof(String), XtOffset(AppDataPtr, polyglotBook), + XtRImmediate, (XtPointer) "" }, + { "defaultPathEGTB", "defaultPathEGTB", XtRString, + sizeof(String), XtOffset(AppDataPtr, defaultPathEGTB), + XtRImmediate, (XtPointer) "/usr/local/share/egtb"}, + { "delayBeforeQuit", "delayBeforeQuit", XtRInt, + sizeof(int), XtOffset(AppDataPtr, delayBeforeQuit), + XtRImmediate, (XtPointer) 0}, + { "delayAfterQuit", "delayAfterQuit", XtRInt, + sizeof(int), XtOffset(AppDataPtr, delayAfterQuit), + XtRImmediate, (XtPointer) 0}, + { "keepAlive", "keepAlive", XtRInt, + sizeof(int), XtOffset(AppDataPtr, keepAlive), + XtRImmediate, (XtPointer) 0}, }; XrmOptionDescRec shellOptions[] = { @@ -1373,6 +1626,7 @@ XrmOptionDescRec shellOptions[] = { { "-zippyVariants", "zippyVariants", XrmoptionSepArg, NULL }, { "-zippyMaxGames", "zippyMaxGames", XrmoptionSepArg, NULL }, { "-zippyReplayTimeout", "zippyReplayTimeout", XrmoptionSepArg, NULL }, + { "-zippyShortGame", "zippyShortGame", XrmoptionSepArg, NULL }, #endif { "-flashCount", "flashCount", XrmoptionSepArg, NULL }, { "-flash", "flashCount", XrmoptionNoArg, "3" }, @@ -1441,6 +1695,83 @@ XrmOptionDescRec shellOptions[] = { { "-showButtonBar", "showButtonBar", XrmoptionSepArg, NULL }, { "-buttons", "showButtonBar", XrmoptionNoArg, "True" }, { "-xbuttons", "showButtonBar", XrmoptionNoArg, "False" }, + { "-lowTimeWarningColor", "lowTimeWarningColor", XrmoptionSepArg, NULL }, + { "-lowTimeWarning", "lowTimeWarning", XrmoptionSepArg, NULL }, + /* [AS,HR] New features */ + { "-firstScoreAbs", "firstScoreAbs", XrmoptionSepArg, NULL }, + { "-secondScoreAbs", "secondScoreAbs", XrmoptionSepArg, NULL }, + { "-pgnExtendedInfo", "pgnExtendedInfo", XrmoptionSepArg, NULL }, + { "-hideThinkingFromHuman", "hideThinkingFromHuman", XrmoptionSepArg, NULL }, + { "-adjudicateLossThreshold", "adjudicateLossThreshold", XrmoptionSepArg, NULL }, + { "-adjudicateDrawMoves", "adjudicateDrawMoves", XrmoptionSepArg, NULL }, + { "-pgnEventHeader", "pgnEventHeader", XrmoptionSepArg, NULL }, + { "-firstIsUCI", "firstIsUCI", XrmoptionSepArg, NULL }, + { "-secondIsUCI", "secondIsUCI", XrmoptionSepArg, NULL }, + { "-fUCI", "firstIsUCI", XrmoptionNoArg, "True" }, + { "-sUCI", "secondIsUCI", XrmoptionNoArg, "True" }, + { "-firstHasOwnBookUCI", "firstHasOwnBookUCI", XrmoptionSepArg, NULL }, + { "-secondHasOwnBookUCI", "secondHasOwnBookUCI", XrmoptionSepArg, NULL }, + { "-fNoOwnBookUCI", "firstHasOwnBookUCI", XrmoptionNoArg, "False" }, + { "-sNoOwnBookUCI", "secondHasOwnBookUCI", XrmoptionNoArg, "False" }, + { "-firstXBook", "firstHasOwnBookUCI", XrmoptionNoArg, "False" }, + { "-secondXBook", "secondHasOwnBookUCI", XrmoptionNoArg, "False" }, + { "-polyglotDir", "polyglotDir", XrmoptionSepArg, NULL }, + { "-usePolyglotBook", "usePolyglotBook", XrmoptionSepArg, NULL }, + { "-polyglotBook", "polyglotBook", XrmoptionSepArg, NULL }, + { "-defaultHashSize", "defaultHashSize", XrmoptionSepArg, NULL }, + { "-defaultCacheSizeEGTB", "defaultCacheSizeEGTB", XrmoptionSepArg, NULL }, + { "-defaultPathEGTB", "defaultPathEGTB", XrmoptionSepArg, NULL }, + { "-defaultFrcPosition", "defaultFrcPosition", XrmoptionSepArg, NULL }, + { "-gameListTags", "gameListTags", XrmoptionSepArg, NULL }, + // [HGM] I am sure AS added many more options, but we have to fish them out, from the list in winboard.c + + /* [HGM,HR] User-selectable board size */ + { "-boardWidth", "boardWidth", XrmoptionSepArg, NULL }, + { "-boardHeight", "boardHeight", XrmoptionSepArg, NULL }, + { "-matchPause", "matchPause", XrmoptionSepArg, NULL }, + + /* [HGM] new arguments of 4.3.xx. All except first three are back-end options, which should work immediately */ + { "-holdingsSize", "holdingsSize", XrmoptionSepArg, NULL }, // requires extensive front-end changes to work + { "-flipBlack", "flipBlack", XrmoptionSepArg, NULL }, // requires front-end changes to work + { "-allWhite", "allWhite", XrmoptionSepArg, NULL }, // requires front-end changes to work + { "-pieceToCharTable", "pieceToCharTable", XrmoptionSepArg, NULL }, + { "-alphaRank", "alphaRank", XrmoptionSepArg, NULL }, + { "-testClaims", "testClaims", XrmoptionSepArg, NULL }, + { "-checkMates", "checkMates", XrmoptionSepArg, NULL }, + { "-materialDraws", "materialDraws", XrmoptionSepArg, NULL }, + { "-trivialDraws", "trivialDraws", XrmoptionSepArg, NULL }, + { "-ruleMoves", "ruleMoves", XrmoptionSepArg, NULL }, + { "-repeatsToDraw", "repeatsToDraw", XrmoptionSepArg, NULL }, + { "-engineDebugOutput", "engineDebugOutput", XrmoptionSepArg, NULL }, + { "-userName", "userName", XrmoptionSepArg, NULL }, + { "-autoKibitz", "autoKibitz", XrmoptionNoArg, "True" }, + { "-firstTimeOdds", "firstTimeOdds", XrmoptionSepArg, NULL }, + { "-secondTimeOdds", "secondTimeOdds", XrmoptionSepArg, NULL }, + { "-timeOddsMode", "timeOddsMode", XrmoptionSepArg, NULL }, + { "-firstAccumulateTC", "firstAccumulateTC", XrmoptionSepArg, NULL }, + { "-secondAccumulateTC", "secondAccumulateTC", XrmoptionSepArg, NULL }, + { "-firstNPS", "firstNPS", XrmoptionSepArg, NULL }, + { "-secondNPS", "secondNPS", XrmoptionSepArg, NULL }, + { "-serverMoves", "serverMoves", XrmoptionSepArg, NULL }, + { "-serverPause", "serverPause", XrmoptionSepArg, NULL }, + { "-suppressLoadMoves", "suppressLoadMoves", XrmoptionSepArg, NULL }, + { "-egtFormats", "egtFormats", XrmoptionSepArg, NULL }, + { "-userName", "userName", XrmoptionSepArg, NULL }, + { "-smpCores", "smpCores", XrmoptionSepArg, NULL }, + { "-sameColorGames", "sameColorGames", XrmoptionSepArg, NULL }, + { "-rewindIndex", "rewindIndex", XrmoptionSepArg, NULL }, + { "-niceEngines", "niceEngines", XrmoptionSepArg, NULL }, + { "-delayBeforeQuit", "delayBeforeQuit", XrmoptionSepArg, NULL }, + { "-delayAfterQuit", "delayAfterQuit", XrmoptionSepArg, NULL }, + { "-nameOfDebugFile", "nameOfDebugFile", XrmoptionSepArg, NULL }, + { "-debugFile", "nameOfDebugFile", XrmoptionSepArg, NULL }, + { "-engineDebugOutput", "engineDebugOutput", XrmoptionSepArg, NULL }, + { "-noGUI", "noGUI", XrmoptionNoArg, "True" }, + { "-firstOptions", "firstOptions", XrmoptionSepArg, NULL }, + { "-secondOptions", "secondOptions", XrmoptionSepArg, NULL }, + { "-firstNeedsNoncompliantFEN", "firstNeedsNoncompliantFEN", XrmoptionSepArg, NULL }, + { "-secondNeedsNoncompliantFEN", "secondNeedsNoncompliantFEN", XrmoptionSepArg, NULL }, + { "-keepAlive", "keepAlive", XrmoptionSepArg, NULL }, }; @@ -1483,6 +1814,7 @@ XtActionsRec boardActions[] = { { "EditGameProc", EditGameProc }, { "EditPositionProc", EditPositionProc }, { "TrainingProc", EditPositionProc }, + { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window { "ShowGameListProc", ShowGameListProc }, { "ShowMoveListProc", HistoryShowProc}, { "EditTagsProc", EditCommentProc }, @@ -1498,6 +1830,9 @@ XtActionsRec boardActions[] = { { "AdjournProc", AdjournProc }, { "AbortProc", AbortProc }, { "ResignProc", ResignProc }, + { "AdjuWhiteProc", AdjuWhiteProc }, + { "AdjuBlackProc", AdjuBlackProc }, + { "AdjuDrawProc", AdjuDrawProc }, { "EnterKeyProc", EnterKeyProc }, { "StopObservingProc", StopObservingProc }, { "StopExaminingProc", StopExaminingProc }, @@ -1528,14 +1863,15 @@ XtActionsRec boardActions[] = { { "IcsAlarmProc", IcsAlarmProc }, { "MoveSoundProc", MoveSoundProc }, { "OldSaveStyleProc", OldSaveStyleProc }, - { "PeriodicUpdatesProc", PeriodicUpdatesProc }, + { "PeriodicUpdatesProc", PeriodicUpdatesProc }, { "PonderNextMoveProc", PonderNextMoveProc }, - { "PopupExitMessageProc", PopupExitMessageProc }, - { "PopupMoveErrorsProc", PopupMoveErrorsProc }, + { "PopupExitMessageProc", PopupExitMessageProc }, + { "PopupMoveErrorsProc", PopupMoveErrorsProc }, { "PremoveProc", PremoveProc }, { "QuietPlayProc", QuietPlayProc }, { "ShowCoordsProc", ShowCoordsProc }, { "ShowThinkingProc", ShowThinkingProc }, + { "HideThinkingProc", HideThinkingProc }, { "TestLegalityProc", TestLegalityProc }, { "InfoProc", InfoProc }, { "ManProc", ManProc }, @@ -1556,8 +1892,15 @@ XtActionsRec boardActions[] = { { "GameListPopDown", (XtActionProc) GameListPopDown }, { "PromotionPopDown", (XtActionProc) PromotionPopDown }, { "HistoryPopDown", (XtActionProc) HistoryPopDown }, + { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown }, + { "ShufflePopDown", (XtActionProc) ShufflePopDown }, + { "EnginePopDown", (XtActionProc) EnginePopDown }, + { "UciPopDown", (XtActionProc) UciPopDown }, + { "TimeControlPopDown", (XtActionProc) TimeControlPopDown }, + { "NewVariantPopDown", (XtActionProc) NewVariantPopDown }, + { "SettingsPopDown", (XtActionProc) SettingsPopDown }, }; - + char globalTranslations[] = ":R: ResignProc() \n \ :r: ResetProc() \n \ @@ -1596,10 +1939,10 @@ char boardTranslations[] = PieceMenuPopup(menuW) \n \ Any: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \ PieceMenuPopup(menuB) \n"; - + char whiteTranslations[] = ": WhiteClock()\n"; char blackTranslations[] = ": BlackClock()\n"; - + char ICSInputTranslations[] = "Return: EnterKeyProc() \n"; @@ -1609,7 +1952,7 @@ String xboardResources[] = { "*errorpopup*translations: #override\\n Return: ErrorPopDown()", NULL }; - + /* Max possible square size */ #define MAXSQSIZE 256 @@ -1627,14 +1970,14 @@ xpm_getsize(name, len, ext) { char *p, *d; char buf[10]; - + if (len < 4) return 0; if ((p=strchr(name, '.')) == NULL || StrCaseCmp(p+1, ext) != 0) return 0; - + p = name + 3; d = buf; @@ -1660,15 +2003,15 @@ xpm_getavail(dirname, ext) if (appData.debugMode) fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext); - + dir = opendir(dirname); if (!dir) { - fprintf(stderr, _("%s: Can't access XPM directory %s\n"), + fprintf(stderr, _("%s: Can't access XPM directory %s\n"), programName, dirname); exit(1); } - + while ((ent=readdir(dir)) != NULL) { i = xpm_getsize(ent->d_name, NAMLEN(ent), ext); if (i > 0 && i < MAXSQSIZE) @@ -1705,12 +2048,12 @@ xpm_closest_to(dirname, size, ext) int sm_diff = MAXSQSIZE; int sm_index = 0; int diff; - + xpm_getavail(dirname, ext); if (appData.debugMode) xpm_print_avail(stderr, ext); - + for (i=1; i 99) /* watch bounds on buf */ return -1; @@ -1785,10 +2128,10 @@ parse_color(str, which) if (*p == ',') { return -1; /* Use default for empty field */ } - + if (which == 2 || isdigit(*p)) return atoi(p); - + while (*p && isalpha(*p)) *(d++) = *(p++); @@ -1831,7 +2174,7 @@ CatchDeleteWindow(Widget w, String procname) { char buf[MSG_SIZ]; XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1); - sprintf(buf, "WM_PROTOCOLS: %s() \n", procname); + snprintf(buf, sizeof(buf), "WM_PROTOCOLS: %s() \n", procname); XtAugmentTranslations(w, XtParseTranslationTable(buf)); } @@ -1845,6 +2188,155 @@ BoardToTop() XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */ } +#ifdef IDSIZES + // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined +#else +#define BoardSize int +void InitDrawingSizes(BoardSize boardSize, int flags) +{ // [HGM] resize is functional now, but for board format changes only (nr of ranks, files) + Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr; + Arg args[16]; + XtGeometryResult gres; + int i; + + if(!formWidget) return; + + /* + * Enable shell resizing. + */ + shellArgs[0].value = (XtArgVal) &w; + shellArgs[1].value = (XtArgVal) &h; + XtGetValues(shellWidget, shellArgs, 2); + + shellArgs[4].value = 2*w; shellArgs[2].value = 10; + shellArgs[5].value = 2*h; shellArgs[3].value = 10; + XtSetValues(shellWidget, &shellArgs[2], 4); + + XtSetArg(args[0], XtNdefaultDistance, &sep); + XtGetValues(formWidget, args, 1); + + boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap); + boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap); + CreateGrid(); + + XtSetArg(args[0], XtNwidth, boardWidth); + XtSetArg(args[1], XtNheight, boardHeight); + XtSetValues(boardWidget, args, 2); + + timerWidth = (boardWidth - sep) / 2; + XtSetArg(args[0], XtNwidth, timerWidth); + XtSetValues(whiteTimerWidget, args, 1); + XtSetValues(blackTimerWidget, args, 1); + + XawFormDoLayout(formWidget, False); + + if (appData.titleInWindow) { + i = 0; + XtSetArg(args[i], XtNborderWidth, &bor); i++; + XtSetArg(args[i], XtNheight, &h); i++; + XtGetValues(titleWidget, args, i); + if (smallLayout) { + w = boardWidth - 2*bor; + } else { + XtSetArg(args[0], XtNwidth, &w); + XtGetValues(menuBarWidget, args, 1); + w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE + } + + gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr); + if (gres != XtGeometryYes && appData.debugMode) { + fprintf(stderr, + _("%s: titleWidget geometry error %d %d %d %d %d\n"), + programName, gres, w, h, wr, hr); + } + } + + XawFormDoLayout(formWidget, True); + + /* + * Inhibit shell resizing. + */ + shellArgs[0].value = w = (XtArgVal) boardWidth + marginW; + shellArgs[1].value = h = (XtArgVal) boardHeight + marginH; + shellArgs[4].value = shellArgs[2].value = w; + shellArgs[5].value = shellArgs[3].value = h; + XtSetValues(shellWidget, &shellArgs[0], 6); + + // [HGM] pieces: tailor piece bitmaps to needs of specific variant + // (only for xpm) + if(useImages) { + for(i=0; i<4; i++) { + int p; + for(p=0; p<=(int)WhiteKing; p++) + xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults + if(gameInfo.variant == VariantShogi) { + xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1]; + xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2]; + xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3]; + xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4]; + xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance]; + } +#ifdef GOTHIC + if(gameInfo.variant == VariantGothic) { + xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver]; + } +#endif +#if !HAVE_LIBXPM + // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used! + for(p=0; p<=(int)WhiteKing; p++) + ximMaskPm[p] = ximMaskPm2[p]; // defaults + if(gameInfo.variant == VariantShogi) { + ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1]; + ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2]; + ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3]; + ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4]; + ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance]; + } +#ifdef GOTHIC + if(gameInfo.variant == VariantGothic) { + ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver]; + } +#endif +#endif + } + } else { + for(i=0; i<2; i++) { + int p; + for(p=0; p<=(int)WhiteKing; p++) + pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults + if(gameInfo.variant == VariantShogi) { + pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1]; + pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2]; + pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3]; + pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4]; + pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance]; + } +#ifdef GOTHIC + if(gameInfo.variant == VariantGothic) { + pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver]; + } +#endif + } + } +#if HAVE_LIBXPM + CreateAnimVars(); +#endif +} +#endif + +void EscapeExpand(char *p, char *q) +{ // [HGM] initstring: routine to shape up string arguments + while(*p++ = *q++) if(p[-1] == '\\') + switch(*q++) { + case 'n': p[-1] = '\n'; break; + case 'r': p[-1] = '\r'; break; + case 't': p[-1] = '\t'; break; + case '\\': p[-1] = '\\'; break; + case 0: *p = 0; return; + default: p[-1] = q[-1]; break; + } +} + int main(argc, argv) int argc; @@ -1853,17 +2345,60 @@ main(argc, argv) int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize; XSetWindowAttributes window_attributes; Arg args[16]; - Dimension timerWidth, boardWidth, w, h, sep, bor, wr, hr; + Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr; XrmValue vFrom, vTo; XtGeometryResult gres; char *p; XrmDatabase xdb; int forceMono = False; +#define INDIRECTION +#ifdef INDIRECTION + // [HGM] before anything else, expand any indirection files amongst options + char *argvCopy[1000]; // 1000 seems enough + char newArgs[10000]; // holds actual characters + int k = 0; + + srandom(time(0)); // [HGM] book: make random truly random + + j = 0; + for(i=0; i= 1000-2) { printf(_("too many arguments\n")); exit(-1); } +//fprintf(stderr, "arg %s\n", argv[i]); + if(argv[i][0] != '@') argvCopy[j++] = argv[i]; else { + char c; + FILE *f = fopen(argv[i]+1, "rb"); + if(f == NULL) { fprintf(stderr, _("ignore %s\n"), argv[i]); continue; } // do not expand non-existing + argvCopy[j++] = newArgs + k; // get ready for first argument from file + while((c = fgetc(f)) != EOF) { // each line of file inserts 1 argument in the list + if(c == '\n') { + if(j >= 1000-2) { printf(_("too many arguments\n")); exit(-1); } + newArgs[k++] = 0; // terminate current arg + if(k >= 10000-1) { printf(_("too long arguments\n")); exit(-1); } + argvCopy[j++] = newArgs + k; // get ready for next + } else { + if(k >= 10000-1) { printf(_("too long arguments\n")); exit(-1); } + newArgs[k++] = c; + } + } + newArgs[k] = 0; + j--; + fclose(f); + } + } + argvCopy[j] = NULL; + argv = argvCopy; + argc = j; +#if 0 + if(appData.debugMode,1) { // OK, appData is not initialized here yet... + for(i=0; i 1) { fprintf(stderr, _("%s: unrecognized argument %s\n"), programName, argv[1]); + fprintf(stderr, "Recognized options:\n"); + for(i = 0; i < XtNumber(shellOptions); i++) { + j = fprintf(stderr, " %s%s", shellOptions[i].option, + (shellOptions[i].argKind == XrmoptionSepArg + ? " ARG" : "")); + if (i++ < XtNumber(shellOptions)) { + fprintf(stderr, "%*c%s%s\n", 40 - j, ' ', + shellOptions[i].option, + (shellOptions[i].argKind == XrmoptionSepArg + ? " ARG" : "")); + } else { + fprintf(stderr, "\n"); + } + } exit(2); } - + + p = getenv("HOME"); + if (p == NULL) p = "/tmp"; + i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1; + gameCopyFilename = (char*) malloc(i); + gamePasteFilename = (char*) malloc(i); + snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid()); + snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid()); + + XtGetApplicationResources(shellWidget, (XtPointer) &appData, + clientResources, XtNumber(clientResources), + NULL, 0); + + { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string. + static char buf[MSG_SIZ]; + EscapeExpand(buf, appData.initString); + appData.initString = strdup(buf); + EscapeExpand(buf, appData.secondInitString); + appData.secondInitString = strdup(buf); + EscapeExpand(buf, appData.firstComputerString); + appData.firstComputerString = strdup(buf); + EscapeExpand(buf, appData.secondComputerString); + appData.secondComputerString = strdup(buf); + } + if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) { chessDir = "."; } else { @@ -1896,27 +2468,21 @@ main(argc, argv) exit(1); } } - - p = getenv("HOME"); - if (p == NULL) p = "/tmp"; - i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1; - gameCopyFilename = (char*) malloc(i); - gamePasteFilename = (char*) malloc(i); - sprintf(gameCopyFilename, "%s/.xboard%05uc.pgn", p, getpid()); - sprintf(gamePasteFilename, "%s/.xboard%05up.pgn", p, getpid()); - XtGetApplicationResources(shellWidget, (XtPointer) &appData, - clientResources, XtNumber(clientResources), - NULL, 0); - - if (appData.debugMode) { - if ((debugFP = fopen("xboard.debug", "w")) == NULL) { - printf(_("Failed to open file xboard.debug \n")); - exit(errno); - } + if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) { + /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */ + if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) { + printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile); + exit(errno); + } setbuf(debugFP, NULL); } - + + /* [HGM,HR] make sure board size is acceptable */ + if(appData.NrFiles > BOARD_SIZE || + appData.NrRanks > BOARD_SIZE ) + DisplayFatalError(_("Recompile with BOARD_SIZE > 12, to support this size"), 0, 2); + #if !HIGHDRAG /* This feature does not work; animation needs a rewrite */ appData.highlightDragging = FALSE; @@ -1927,9 +2493,25 @@ main(argc, argv) xScreen = DefaultScreen(xDisplay); wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True); + gameInfo.variant = StringToVariant(appData.variant); + InitPosition(FALSE); +#if 0 /* * Determine boardSize */ + gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] boardsize: make sure we start as 8x8 + +//#ifndef IDSIZE + // [HGM] as long as we have not created the possibility to change size while running, start with requested size + gameInfo.boardWidth = appData.NrFiles > 0 ? appData.NrFiles : 8; + gameInfo.boardHeight = appData.NrRanks > 0 ? appData.NrRanks : 8; + gameInfo.holdingsWidth = appData.holdingsSize > 0 ? 2 : 0; +#endif + + +#ifdef IDSIZE + InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine +#else if (isdigit(appData.boardSize[0])) { i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize, &lineGap, &clockFontPxlSize, &coordFontPxlSize, @@ -1994,7 +2576,7 @@ main(argc, argv) exit(1); } if (appData.debugMode) { - fprintf(stderr, _("\ + fprintf(stderr, _("\ XBoard square size (hint): %d\n\ %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p); } @@ -2003,22 +2585,24 @@ XBoard square size (hint): %d\n\ fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize); } } - - boardWidth = lineGap + BOARD_SIZE * (squareSize + lineGap); + + /* [HR] height treated separately (hacked) */ + boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap); + boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap); if (appData.showJail == 1) { /* Jail on top and bottom */ XtSetArg(boardArgs[1], XtNwidth, boardWidth); XtSetArg(boardArgs[2], XtNheight, - boardWidth + 2*(lineGap + squareSize)); + boardHeight + 2*(lineGap + squareSize)); } else if (appData.showJail == 2) { /* Jail on sides */ XtSetArg(boardArgs[1], XtNwidth, boardWidth + 2*(lineGap + squareSize)); - XtSetArg(boardArgs[2], XtNheight, boardWidth); + XtSetArg(boardArgs[2], XtNheight, boardHeight); } else { /* No jail */ XtSetArg(boardArgs[1], XtNwidth, boardWidth); - XtSetArg(boardArgs[2], XtNheight, boardWidth); + XtSetArg(boardArgs[2], XtNheight, boardHeight); } /* @@ -2031,6 +2615,9 @@ XBoard square size (hint): %d\n\ coordFontID = XLoadFont(xDisplay, appData.coordFont); coordFontStruct = XQueryFont(xDisplay, coordFontID); appData.font = FindFont(appData.font, fontPxlSize); + countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings + countFontStruct = XQueryFont(xDisplay, countFontID); +// appData.font = FindFont(appData.font, fontPxlSize); xdb = XtDatabase(xDisplay); XrmPutStringResource(&xdb, "*font", appData.font); @@ -2114,6 +2701,20 @@ XBoard square size (hint): %d\n\ if (forceMono) { fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"), programName); + + if (appData.bitmapDirectory == NULL || + appData.bitmapDirectory[0] == NULLCHAR) + appData.bitmapDirectory = DEF_BITMAP_DIR; + } + + if (appData.lowTimeWarning && !appData.monoMode) { + vFrom.addr = (caddr_t) appData.lowTimeWarningColor; + vFrom.size = strlen(appData.lowTimeWarningColor); + XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo); + if (vTo.addr == NULL) + appData.monoMode = True; + else + lowTimeWarningColor = *(Pixel *) vTo.addr; } if (appData.monoMode && appData.debugMode) { @@ -2121,7 +2722,7 @@ XBoard square size (hint): %d\n\ (unsigned long) XWhitePixel(xDisplay, xScreen), (unsigned long) XBlackPixel(xDisplay, xScreen)); } - + if (parse_cpair(ColorShout, appData.colorShout) < 0 || parse_cpair(ColorSShout, appData.colorSShout) < 0 || parse_cpair(ColorChannel1, appData.colorChannel1) < 0 || @@ -2142,9 +2743,9 @@ XBoard square size (hint): %d\n\ } textColors[ColorNone].fg = textColors[ColorNone].bg = -1; textColors[ColorNone].attr = 0; - + XtAppAddActions(appContext, boardActions, XtNumber(boardActions)); - + /* * widget hierarchy */ @@ -2165,51 +2766,69 @@ XBoard square size (hint): %d\n\ formArgs, XtNumber(formArgs)); XtSetArg(args[0], XtNdefaultDistance, &sep); XtGetValues(formWidget, args, 1); - + j = 0; widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar); + XtSetArg(args[0], XtNtop, XtChainTop); + XtSetArg(args[1], XtNbottom, XtChainTop); + XtSetValues(menuBarWidget, args, 2); widgetList[j++] = whiteTimerWidget = XtCreateWidget("whiteTime", labelWidgetClass, formWidget, timerArgs, XtNumber(timerArgs)); XtSetArg(args[0], XtNfont, clockFontStruct); - XtSetValues(whiteTimerWidget, args, 1); - + XtSetArg(args[1], XtNtop, XtChainTop); + XtSetArg(args[2], XtNbottom, XtChainTop); + XtSetValues(whiteTimerWidget, args, 3); + widgetList[j++] = blackTimerWidget = XtCreateWidget("blackTime", labelWidgetClass, formWidget, timerArgs, XtNumber(timerArgs)); XtSetArg(args[0], XtNfont, clockFontStruct); - XtSetValues(blackTimerWidget, args, 1); - + XtSetArg(args[1], XtNtop, XtChainTop); + XtSetArg(args[2], XtNbottom, XtChainTop); + XtSetValues(blackTimerWidget, args, 3); + if (appData.titleInWindow) { - widgetList[j++] = titleWidget = + widgetList[j++] = titleWidget = XtCreateWidget("title", labelWidgetClass, formWidget, titleArgs, XtNumber(titleArgs)); + XtSetArg(args[0], XtNtop, XtChainTop); + XtSetArg(args[1], XtNbottom, XtChainTop); + XtSetValues(titleWidget, args, 2); } if (appData.showButtonBar) { widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar); + XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge + XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing + XtSetArg(args[2], XtNtop, XtChainTop); + XtSetArg(args[3], XtNbottom, XtChainTop); + XtSetValues(buttonBarWidget, args, 4); } widgetList[j++] = messageWidget = XtCreateWidget("message", labelWidgetClass, formWidget, messageArgs, XtNumber(messageArgs)); - + XtSetArg(args[0], XtNtop, XtChainTop); + XtSetArg(args[1], XtNbottom, XtChainTop); + XtSetValues(messageWidget, args, 2); + widgetList[j++] = boardWidget = XtCreateWidget("board", widgetClass, formWidget, boardArgs, XtNumber(boardArgs)); XtManageChildren(widgetList, j); - + timerWidth = (boardWidth - sep) / 2; XtSetArg(args[0], XtNwidth, timerWidth); XtSetValues(whiteTimerWidget, args, 1); XtSetValues(blackTimerWidget, args, 1); - + XtSetArg(args[0], XtNbackground, &timerBackgroundPixel); XtSetArg(args[1], XtNforeground, &timerForegroundPixel); XtGetValues(whiteTimerWidget, args, 2); - + if (appData.showButtonBar) { XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel); XtSetArg(args[1], XtNforeground, &buttonForegroundPixel); @@ -2289,7 +2908,11 @@ XBoard square size (hint): %d\n\ } i = 0; XtSetArg(args[0], XtNfromVert, messageWidget); - XtSetValues(boardWidget, args, 1); + XtSetArg(args[1], XtNtop, XtChainTop); + XtSetArg(args[2], XtNbottom, XtChainBottom); + XtSetArg(args[3], XtNleft, XtChainLeft); + XtSetArg(args[4], XtNright, XtChainRight); + XtSetValues(boardWidget, args, 5); XtRealizeWidget(shellWidget); @@ -2299,6 +2922,7 @@ XBoard square size (hint): %d\n\ * The value "2" is probably larger than needed. */ XawFormDoLayout(formWidget, False); + #define WIDTH_FUDGE 2 i = 0; XtSetArg(args[i], XtNborderWidth, &bor); i++; @@ -2318,7 +2942,7 @@ XBoard square size (hint): %d\n\ fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"), programName, gres, w, h, wr, hr); } - + /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */ /* The size used for the child widget in layout lags one resize behind its true size, so we resize a second time, 1 pixel smaller. Yeech! */ @@ -2329,6 +2953,9 @@ XBoard square size (hint): %d\n\ programName, gres, w, h, wr, hr); } /* !! end hack */ + XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing + XtSetArg(args[1], XtNright, XtChainRight); + XtSetValues(messageWidget, args, 2); if (appData.titleInWindow) { i = 0; @@ -2353,8 +2980,12 @@ XBoard square size (hint): %d\n\ XawFormDoLayout(formWidget, True); xBoardWindow = XtWindow(boardWidget); - - /* + + // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would + // not need to go into InitDrawingSizes(). +#endif + + /* * Create X checkmark bitmap and initialize option menu checks. */ ReadBitmap(&xMarkPixmap, "checkmark.bm", @@ -2445,19 +3076,19 @@ XBoard square size (hint): %d\n\ if (appData.periodicUpdates) { XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"), args, 1); - } + } if (appData.ponderNextMove) { XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"), args, 1); - } + } if (appData.popupExitMessage) { XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Exit Message"), args, 1); - } + } if (appData.popupMoveErrors) { XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"), args, 1); - } + } if (appData.premove) { XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Premove"), args, 1); @@ -2470,8 +3101,8 @@ XBoard square size (hint): %d\n\ XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"), args, 1); } - if (appData.showThinking) { - XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Thinking"), + if (appData.hideThinkingFromHuman) { + XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"), args, 1); } if (appData.testLegality) { @@ -2490,14 +3121,14 @@ XBoard square size (hint): %d\n\ i = 0; XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++; XtSetValues(shellWidget, args, i); - + /* * Create a cursor for the board widget. */ window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2); XChangeWindowAttributes(xDisplay, xBoardWindow, CWCursor, &window_attributes); - + /* * Inhibit shell resizing. */ @@ -2507,7 +3138,9 @@ XBoard square size (hint): %d\n\ shellArgs[4].value = shellArgs[2].value = w; shellArgs[5].value = shellArgs[3].value = h; XtSetValues(shellWidget, &shellArgs[2], 4); - + marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board + marginH = h - boardHeight; + CatchDeleteWindow(shellWidget, "QuitProc"); CreateGCs(); @@ -2522,13 +3155,13 @@ XBoard square size (hint): %d\n\ CreateXIMPieces(); /* Create regular pieces */ if (!useImages) CreatePieces(); -#endif +#endif CreatePieceMenus(); if (appData.animate || appData.animateDragging) CreateAnimVars(); - + XtAugmentTranslations(formWidget, XtParseTranslationTable(globalTranslations)); XtAugmentTranslations(boardWidget, @@ -2545,7 +3178,7 @@ XBoard square size (hint): %d\n\ /* end why */ InitBackEnd2(); - + if (errorExitStatus == -1) { if (appData.icsActive) { /* We now wait until we see "login:" from the ICS before @@ -2560,10 +3193,11 @@ XBoard square size (hint): %d\n\ signal(SIGUSR1, CmailSigHandler); } } + gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes() + InitPosition(TRUE); XtAppMainLoop(appContext); - if (appData.debugMode) fclose(debugFP); - + if (appData.debugMode) fclose(debugFP); // [DM] debug return 0; } @@ -2677,14 +3311,14 @@ Enables icsEnables[] = { { "menuHelp.Hint", False }, { "menuHelp.Book", False }, { "menuStep.Move Now", False }, - { "menuOptions.Periodic Updates", False }, - { "menuOptions.Show Thinking", False }, + { "menuOptions.Periodic Updates", False }, + { "menuOptions.Hide Thinking", False }, { "menuOptions.Ponder Next Move", False }, #endif { NULL, False } }; -Enables ncpEnables[] = { +Enables ncpEnables[] = { { "menuFile.Mail Move", False }, { "menuFile.Reload CMail Message", False }, { "menuMode.Machine White", False }, @@ -2707,15 +3341,15 @@ Enables ncpEnables[] = { { "menuOptions.ICS Alarm", False }, { "menuOptions.Move Sound", False }, { "menuOptions.Quiet Play", False }, - { "menuOptions.Show Thinking", False }, - { "menuOptions.Periodic Updates", False }, + { "menuOptions.Hide Thinking", False }, + { "menuOptions.Periodic Updates", False }, { "menuOptions.Ponder Next Move", False }, { "menuHelp.Hint", False }, { "menuHelp.Book", False }, { NULL, False } }; -Enables gnuEnables[] = { +Enables gnuEnables[] = { { "menuMode.ICS Client", False }, { "menuMode.ICS Input Box", False }, { "menuAction.Accept", False }, @@ -2741,7 +3375,7 @@ Enables gnuEnables[] = { { NULL, False } }; -Enables cmailEnables[] = { +Enables cmailEnables[] = { { "Action", True }, { "menuAction.Call Flag", False }, { "menuAction.Draw", True }, @@ -2754,7 +3388,7 @@ Enables cmailEnables[] = { { NULL, False } }; -Enables trainingOnEnables[] = { +Enables trainingOnEnables[] = { { "menuMode.Edit Comment", False }, { "menuMode.Pause", False }, { "menuStep.Forward", False }, @@ -2766,7 +3400,7 @@ Enables trainingOnEnables[] = { { NULL, False } }; -Enables trainingOffEnables[] = { +Enables trainingOffEnables[] = { { "menuMode.Edit Comment", True }, { "menuMode.Pause", True }, { "menuStep.Forward", True }, @@ -2818,11 +3452,10 @@ void SetICSMode() { SetMenuEnables(icsEnables); - #ifdef ZIPPY - /* icsEngineAnalyze */ - if (appData.zippyPlay && !appData.noChessProgram) +#ifdef ZIPPY + if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */ XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True); - #endif +#endif } void @@ -2892,7 +3525,7 @@ SetMachineThinkingEnables() * Find a font that matches "pattern" that is as close as * possible to the targetPxlSize. Prefer fonts that are k * pixels smaller to fonts that are k pixels larger. The - * pattern must be in the X Consortium standard format, + * pattern must be in the X Consortium standard format, * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*". * The return value should be freed with XtFree when no * longer needed. @@ -2918,14 +3551,14 @@ char *FindFont(pattern, targetPxlSize) strcat(base_fnt_lst, strInt); strcat(base_fnt_lst, strchr(p + 2, '-')); - if ((fntSet = XCreateFontSet(xDisplay, - base_fnt_lst, - &missing_list, - &missing_count, + if ((fntSet = XCreateFontSet(xDisplay, + base_fnt_lst, + &missing_list, + &missing_count, &def_string)) == NULL) { - fprintf(stderr, _("Unable to create font set.\n")); - exit (2); + fprintf(stderr, _("Unable to create font set.\n")); + exit (2); } nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts); @@ -2980,10 +3613,10 @@ char *FindFont(pattern, targetPxlSize) } #ifdef ENABLE_NLS if (missing_count > 0) - XFreeStringList(missing_list); + XFreeStringList(missing_list); XFreeFontSet(xDisplay, fntSet); #else - XFreeFontNames(fonts); + XFreeFontNames(fonts); #endif return p; } @@ -2994,29 +3627,35 @@ void CreateGCs() | GCBackground | GCFunction | GCPlaneMask; XGCValues gc_values; GC copyInvertedGC; - + gc_values.plane_mask = AllPlanes; gc_values.line_width = lineGap; gc_values.line_style = LineSolid; gc_values.function = GXcopy; - + gc_values.foreground = XBlackPixel(xDisplay, xScreen); gc_values.background = XBlackPixel(xDisplay, xScreen); lineGC = XtGetGC(shellWidget, value_mask, &gc_values); - + gc_values.foreground = XBlackPixel(xDisplay, xScreen); gc_values.background = XWhitePixel(xDisplay, xScreen); coordGC = XtGetGC(shellWidget, value_mask, &gc_values); XSetFont(xDisplay, coordGC, coordFontID); - + + // [HGM] make font for holdings counts (white on black0 + gc_values.foreground = XWhitePixel(xDisplay, xScreen); + gc_values.background = XBlackPixel(xDisplay, xScreen); + countGC = XtGetGC(shellWidget, value_mask, &gc_values); + XSetFont(xDisplay, countGC, countFontID); + if (appData.monoMode) { gc_values.foreground = XWhitePixel(xDisplay, xScreen); gc_values.background = XWhitePixel(xDisplay, xScreen); - highlineGC = XtGetGC(shellWidget, value_mask, &gc_values); + highlineGC = XtGetGC(shellWidget, value_mask, &gc_values); gc_values.foreground = XWhitePixel(xDisplay, xScreen); gc_values.background = XBlackPixel(xDisplay, xScreen); - lightSquareGC = wbPieceGC + lightSquareGC = wbPieceGC = XtGetGC(shellWidget, value_mask, &gc_values); gc_values.foreground = XBlackPixel(xDisplay, xScreen); @@ -3040,16 +3679,16 @@ void CreateGCs() } else { gc_values.foreground = highlightSquareColor; gc_values.background = highlightSquareColor; - highlineGC = XtGetGC(shellWidget, value_mask, &gc_values); + highlineGC = XtGetGC(shellWidget, value_mask, &gc_values); gc_values.foreground = premoveHighlightColor; gc_values.background = premoveHighlightColor; - prelineGC = XtGetGC(shellWidget, value_mask, &gc_values); + prelineGC = XtGetGC(shellWidget, value_mask, &gc_values); gc_values.foreground = lightSquareColor; gc_values.background = darkSquareColor; lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values); - + gc_values.foreground = darkSquareColor; gc_values.background = lightSquareColor; darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values); @@ -3061,19 +3700,19 @@ void CreateGCs() gc_values.foreground = whitePieceColor; gc_values.background = darkSquareColor; wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values); - + gc_values.foreground = whitePieceColor; gc_values.background = lightSquareColor; wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values); - + gc_values.foreground = whitePieceColor; gc_values.background = jailSquareColor; wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values); - + gc_values.foreground = blackPieceColor; gc_values.background = darkSquareColor; bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values); - + gc_values.foreground = blackPieceColor; gc_values.background = lightSquareColor; blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values); @@ -3102,31 +3741,31 @@ void loadXIM(xim, xmask, filename, dest, mask) fprintf(stderr, _("%s: error loading XIM!\n"), programName); exit(1); } - + w = fgetc(fp); h = fgetc(fp); - + for (y=0; ydepth); XPutImage(xDisplay, *dest, lightSquareGC, xim, - 0, 0, 0, 0, w, h); + 0, 0, 0, 0, w, h); - /* create Pixmap of clipmask + /* create Pixmap of clipmask Note: We assume the white/black pieces have the same outline, so we make only 6 masks. This is okay since the XPM clipmask routines do the same. */ @@ -3149,7 +3788,7 @@ void loadXIM(xim, xmask, filename, dest, mask) temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay), w, h, xim->depth); XPutImage(xDisplay, temp, lightSquareGC, xmask, - 0, 0, 0, 0, w, h); + 0, 0, 0, 0, w, h); /* now create the 1-bit version */ *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay), @@ -3159,14 +3798,17 @@ void loadXIM(xim, xmask, filename, dest, mask) values.background = 0; /* Don't use XtGetGC, not read only */ - maskGC = XCreateGC(xDisplay, *mask, + maskGC = XCreateGC(xDisplay, *mask, GCForeground | GCBackground, &values); - XCopyPlane(xDisplay, temp, *mask, maskGC, + XCopyPlane(xDisplay, temp, *mask, maskGC, 0, 0, squareSize, squareSize, 0, 0, 1); XFreePixmap(xDisplay, temp); } } + +char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl"; + void CreateXIMPieces() { int piece, kind; @@ -3181,7 +3823,7 @@ void CreateXIMPieces() Not sure if needed, but can't hurt */ XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */ - + /* temp needed by loadXIM() */ ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay), 0, 0, ss, ss, AllPlanes, XYPixmap); @@ -3197,36 +3839,39 @@ void CreateXIMPieces() } fprintf(stderr, _("\nLoading XIMs...\n")); /* Load pieces */ - for (piece = (int) WhitePawn; piece <= (int) WhiteKing; piece++) { + for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) { fprintf(stderr, "%d", piece+1); for (kind=0; kind<4; kind++) { fprintf(stderr, "."); - sprintf(buf, "%s/%c%s%u.xim", + snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim", ExpandPathName(appData.pixmapDirectory), - ToLower(PieceToChar((ChessSquare)piece)), + piece <= (int) WhiteKing ? "" : "w", + pieceBitmapNames[piece], ximkind[kind], ss); ximPieceBitmap[kind][piece] = XGetImage(xDisplay, DefaultRootWindow(xDisplay), 0, 0, ss, ss, AllPlanes, XYPixmap); if (appData.debugMode) fprintf(stderr, _("(File:%s:) "), buf); - loadXIM(ximPieceBitmap[kind][piece], + loadXIM(ximPieceBitmap[kind][piece], ximtemp, buf, - &(xpmPieceBitmap[kind][piece]), - &(ximMaskPm[piece%6])); + &(xpmPieceBitmap2[kind][piece]), + &(ximMaskPm2[piece])); + if(piece <= (int)WhiteKing) + xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece]; } fprintf(stderr," "); } /* Load light and dark squares */ - /* If the LSQ and DSQ pieces don't exist, we will + /* If the LSQ and DSQ pieces don't exist, we will draw them with solid squares. */ - sprintf(buf, "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss); + snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss); if (access(buf, 0) != 0) { useImageSqs = 0; } else { useImageSqs = 1; fprintf(stderr, _("light square ")); - ximLightSquare= + ximLightSquare= XGetImage(xDisplay, DefaultRootWindow(xDisplay), 0, 0, ss, ss, AllPlanes, XYPixmap); if (appData.debugMode) @@ -3234,11 +3879,11 @@ void CreateXIMPieces() loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL); fprintf(stderr, _("dark square ")); - sprintf(buf, "%s/dsq%u.xim", + snprintf(buf,sizeof(buf), "%s/dsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss); if (appData.debugMode) fprintf(stderr, _("(File:%s:) "), buf); - ximDarkSquare= + ximDarkSquare= XGetImage(xDisplay, DefaultRootWindow(xDisplay), 0, 0, ss, ss, AllPlanes, XYPixmap); loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL); @@ -3262,15 +3907,15 @@ void CreateXPMPieces() #if 0 /* Apparently some versions of Xpm don't define XpmFormat at all --tpm */ if (appData.debugMode) { - fprintf(stderr, "XPM Library Version: %d.%d%c\n", + fprintf(stderr, "XPM Library Version: %d.%d%c\n", XpmFormat, XpmVersion, (char)('a' + XpmRevision - 1)); } #endif - + /* The XSynchronize calls were copied from CreatePieces. Not sure if needed, but can't hurt */ XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */ - + /* Setup translations so piece colors match square colors */ symbols[0].name = "light_piece"; symbols[0].value = appData.whitePieceColor; @@ -3299,51 +3944,70 @@ void CreateXPMPieces() fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize); exit(1); } - for (piece = (int) WhitePawn; piece <= (int) WhiteKing; piece++) { + for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) { for (kind=0; kind<4; kind++) { if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow, pieces->xpm[piece][kind], - &(xpmPieceBitmap[kind][piece]), + &(xpmPieceBitmap2[kind][piece]), NULL, &attr)) != 0) { fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"), r, buf); - exit(1); - } - } + exit(1); + } + if(piece <= (int) WhiteKing) + xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece]; + } } useImageSqs = 0; xpmJailSquare = xpmLightSquare; } else { useImages = 1; - + fprintf(stderr, _("\nLoading XPMs...\n")); /* Load pieces */ - for (piece = (int) WhitePawn; piece <= (int) WhiteKing; piece++) { + for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) { fprintf(stderr, "%d ", piece+1); for (kind=0; kind<4; kind++) { - sprintf(buf, "%s/%c%s%u.xpm", + snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm", ExpandPathName(appData.pixmapDirectory), - ToLower(PieceToChar((ChessSquare)piece)), + piece > (int) WhiteKing ? "w" : "", + pieceBitmapNames[piece], xpmkind[kind], ss); if (appData.debugMode) { fprintf(stderr, _("(File:%s:) "), buf); } if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf, - &(xpmPieceBitmap[kind][piece]), + &(xpmPieceBitmap2[kind][piece]), NULL, &attr)) != 0) { - fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), - r, buf); - exit(1); - } - } + if(piece != (int)WhiteKing && piece > (int)WhiteQueen) { + // [HGM] missing: read of unorthodox piece failed; substitute King. + snprintf(buf, sizeof(buf), "%s/k%s%u.xpm", + ExpandPathName(appData.pixmapDirectory), + xpmkind[kind], ss); + if (appData.debugMode) { + fprintf(stderr, _("(Replace by File:%s:) "), buf); + } + r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf, + &(xpmPieceBitmap2[kind][piece]), + NULL, &attr); + } + if (r != 0) { + fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), + r, buf); + exit(1); + } + } + if(piece <= (int) WhiteKing) + xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece]; + } } /* Load light and dark squares */ - /* If the LSQ and DSQ pieces don't exist, we will + /* If the LSQ and DSQ pieces don't exist, we will draw them with solid squares. */ fprintf(stderr, _("light square ")); - sprintf(buf, "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss); + snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss); if (access(buf, 0) != 0) { useImageSqs = 0; } else { @@ -3357,7 +4021,7 @@ void CreateXPMPieces() exit(1); } fprintf(stderr, _("dark square ")); - sprintf(buf, "%s/dsq%u.xpm", + snprintf(buf, sizeof(buf), "%s/dsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss); if (appData.debugMode) { fprintf(stderr, _("(File:%s:) "), buf); @@ -3372,7 +4036,7 @@ void CreateXPMPieces() fprintf(stderr, _("Done.\n")); } XSynchronize(xDisplay, False); /* Work-around for xlib/xt - buffering bug */ + buffering bug */ } #endif /* HAVE_LIBXPM */ @@ -3383,18 +4047,21 @@ void CreatePieces() int piece, kind; char buf[MSG_SIZ]; u_int ss = squareSize; - + XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */ for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) { - for (piece = (int) WhitePawn; piece <= (int) WhiteKing; piece++) { - sprintf(buf, "%c%u%c.bm", ToLower(PieceToChar((ChessSquare)piece)), + for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) { + sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "", + pieceBitmapNames[piece], ss, kind == SOLID ? 's' : 'o'); - ReadBitmap(&pieceBitmap[kind][piece], buf, NULL, ss, ss); + ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss); + if(piece <= (int)WhiteKing) + pieceBitmap[kind][piece] = pieceBitmap2[kind][piece]; } } - + XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */ } @@ -3406,21 +4073,24 @@ void CreatePieces() int piece, kind; char buf[MSG_SIZ]; u_int ss = squareSize; - + XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */ while (bib->squareSize != ss && bib->squareSize != 0) bib++; for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) { - for (piece = (int) WhitePawn; piece <= (int) WhiteKing; piece++) { - sprintf(buf, "%c%u%c.bm", ToLower(PieceToChar((ChessSquare)piece)), + for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) { + sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "", + pieceBitmapNames[piece], ss, kind == SOLID ? 's' : 'o'); - ReadBitmap(&pieceBitmap[kind][piece], buf, + ReadBitmap(&pieceBitmap2[kind][piece], buf, bib->bits[kind][piece], ss, ss); + if(piece <= (int)WhiteKing) + pieceBitmap[kind][piece] = pieceBitmap2[kind][piece]; } } - + XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */ } @@ -3436,27 +4106,28 @@ void ReadBitmap(pm, name, bits, wreq, hreq) u_int w, h; int errcode; char msg[MSG_SIZ], fullname[MSG_SIZ]; - + if (*appData.bitmapDirectory != NULLCHAR) { strcpy(fullname, appData.bitmapDirectory); strcat(fullname, "/"); strcat(fullname, name); errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname, &w, &h, pm, &x_hot, &y_hot); + fprintf(stderr, "load %s\n", name); if (errcode != BitmapSuccess) { switch (errcode) { case BitmapOpenFailed: - sprintf(msg, _("Can't open bitmap file %s"), fullname); + snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname); break; case BitmapFileInvalid: - sprintf(msg, _("Invalid bitmap in file %s"), fullname); + snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname); break; case BitmapNoMemory: - sprintf(msg, _("Ran out of memory reading bitmap file %s"), + snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"), fullname); break; default: - sprintf(msg, _("Unknown XReadBitmapFile error %d on file %s"), + snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"), errcode, fullname); break; } @@ -3471,9 +4142,12 @@ void ReadBitmap(pm, name, bits, wreq, hreq) } } if (bits == NULL) { +#if 0 fprintf(stderr, _("%s: No built-in bitmap for %s; giving up\n"), programName, name); exit(1); +#endif + ; // [HGM] bitmaps: make it non-fatal if we have no bitmap; } else { *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits, wreq, hreq); @@ -3482,22 +4156,26 @@ void ReadBitmap(pm, name, bits, wreq, hreq) void CreateGrid() { - int i; - + int i, j; + if (lineGap == 0) return; - for (i = 0; i < BOARD_SIZE + 1; i++) { - gridSegments[i].x1 = 0; - gridSegments[i].x2 = - lineGap + BOARD_SIZE * (squareSize + lineGap); - gridSegments[i].y1 = gridSegments[i].y2 - = lineGap / 2 + (i * (squareSize + lineGap)); - gridSegments[i + BOARD_SIZE + 1].y1 = 0; - gridSegments[i + BOARD_SIZE + 1].y2 = - BOARD_SIZE * (squareSize + lineGap); - gridSegments[i + BOARD_SIZE + 1].x1 = - gridSegments[i + BOARD_SIZE + 1].x2 - = lineGap / 2 + (i * (squareSize + lineGap)); + /* [HR] Split this into 2 loops for non-square boards. */ + + for (i = 0; i < BOARD_HEIGHT + 1; i++) { + gridSegments[i].x1 = 0; + gridSegments[i].x2 = + lineGap + BOARD_WIDTH * (squareSize + lineGap); + gridSegments[i].y1 = gridSegments[i].y2 + = lineGap / 2 + (i * (squareSize + lineGap)); + } + + for (j = 0; j < BOARD_WIDTH + 1; j++) { + gridSegments[j + i].y1 = 0; + gridSegments[j + i].y2 = + lineGap + BOARD_HEIGHT * (squareSize + lineGap); + gridSegments[j + i].x1 = gridSegments[j + i].x2 + = lineGap / 2 + (j * (squareSize + lineGap)); } } @@ -3532,7 +4210,7 @@ void CreateMenuBarPopup(parent, name, mb) entry = XtCreateManagedWidget(mi->string, smeLineObjectClass, menu, args, j); } else { - XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); + XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass, menu, args, j+1); XtAddCallback(entry, XtNcallback, @@ -3541,7 +4219,7 @@ void CreateMenuBarPopup(parent, name, mb) } mi++; } -} +} Widget CreateMenuBar(mb) Menu *mb; @@ -3565,13 +4243,13 @@ Widget CreateMenuBar(mb) XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++; if (tinyLayout) { char shortName[2]; - shortName[0] = _(mb->name)[0]; + shortName[0] = _(mb->name)[0]; shortName[1] = NULLCHAR; XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++; } - else { - XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++; - } + else { + XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++; + } XtSetArg(args[j], XtNborderWidth, 0); j++; anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass, @@ -3605,7 +4283,7 @@ Widget CreateButtonBar(mi) XtSetArg(args[j], XtNinternalWidth, 2); j++; XtSetArg(args[j], XtNborderWidth, 0); j++; } - XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++; + XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++; button = XtCreateManagedWidget(mi->string, commandWidgetClass, buttonBar, args, j); XtAddCallback(button, XtNcallback, @@ -3614,7 +4292,7 @@ Widget CreateButtonBar(mi) mi++; } return buttonBar; -} +} Widget CreatePieceMenu(name, color) @@ -3628,17 +4306,17 @@ CreatePieceMenu(name, color) menu = XtCreatePopupShell(name, simpleMenuWidgetClass, boardWidget, args, 0); - + for (i = 0; i < PIECE_MENU_SIZE; i++) { String item = pieceMenuStrings[color][i]; - + if (strcmp(item, "----") == 0) { entry = XtCreateManagedWidget(item, smeLineObjectClass, menu, NULL, 0); } else { - XtSetArg(args[0], XtNlabel, XtNewString(_(item))); + XtSetArg(args[0], XtNlabel, XtNewString(_(item))); entry = XtCreateManagedWidget(item, smeBSBObjectClass, - menu, args, 1); + menu, args, 1); selection = pieceMenuTranslation[color][i]; XtAddCallback(entry, XtNcallback, (XtCallbackProc) PieceMenuSelect, @@ -3662,7 +4340,7 @@ CreatePieceMenus() whitePieceMenu = CreatePieceMenu("menuW", 0); blackPieceMenu = CreatePieceMenu("menuB", 1); - + XtRegisterGrabAction(PieceMenuPopup, True, (unsigned)(ButtonPressMask|ButtonReleaseMask), GrabModeAsync, GrabModeAsync); @@ -3672,21 +4350,21 @@ CreatePieceMenus() boardWidget, args, 1); for (i = 0; i < DROP_MENU_SIZE; i++) { String item = dropMenuStrings[i]; - + if (strcmp(item, "----") == 0) { entry = XtCreateManagedWidget(item, smeLineObjectClass, dropMenu, NULL, 0); } else { - XtSetArg(args[0], XtNlabel, XtNewString(_(item))); + XtSetArg(args[0], XtNlabel, XtNewString(_(item))); entry = XtCreateManagedWidget(item, smeBSBObjectClass, - dropMenu, args, 1); + dropMenu, args, 1); selection = dropMenuTranslation[i]; XtAddCallback(entry, XtNcallback, (XtCallbackProc) DropMenuSelect, (caddr_t) selection); } } -} +} void SetupDropMenu() { @@ -3705,7 +4383,7 @@ void SetupDropMenu() && !appData.icsActive)); count = 0; while (p && *p++ == dmEnables[i].piece) count++; - sprintf(label, "%s %d", dmEnables[i].widget, count); + snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count); j = 0; XtSetArg(args[j], XtNlabel, label); j++; XtSetValues(entry, args, j); @@ -3740,17 +4418,17 @@ void PieceMenuPopup(w, event, params, num_params) default: return; } - - if (((pmFromX = EventToSquare(event->xbutton.x, BOARD_SIZE)) < 0) || - ((pmFromY = EventToSquare(event->xbutton.y, BOARD_SIZE)) < 0)) { + + if (((pmFromX = EventToSquare(event->xbutton.x, BOARD_WIDTH)) < 0) || + ((pmFromY = EventToSquare(event->xbutton.y, BOARD_HEIGHT)) < 0)) { pmFromX = pmFromY = -1; return; } if (flipView) - pmFromX = BOARD_SIZE - 1 - pmFromX; + pmFromX = BOARD_WIDTH - 1 - pmFromX; else - pmFromY = BOARD_SIZE - 1 - pmFromY; - + pmFromY = BOARD_HEIGHT - 1 - pmFromY; + XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu)); } @@ -3806,7 +4484,7 @@ void BlackClock(w, event, prms, nprms) int EventToSquare(x, limit) int x; { - if (x <= 0) + if (x <= 0) return -2; if (x < lineGap) return -1; @@ -3832,17 +4510,17 @@ static void drawHighlight(file, rank, gc) int x, y; if (lineGap == 0 || appData.blindfold) return; - + if (flipView) { - x = lineGap/2 + ((BOARD_SIZE-1)-file) * + x = lineGap/2 + ((BOARD_WIDTH-1)-file) * (squareSize + lineGap); y = lineGap/2 + rank * (squareSize + lineGap); } else { x = lineGap/2 + file * (squareSize + lineGap); - y = lineGap/2 + ((BOARD_SIZE-1)-rank) * + y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) * (squareSize + lineGap); } - + XDrawRectangle(xDisplay, xBoardWindow, gc, x, y, squareSize+lineGap, squareSize+lineGap); } @@ -4014,6 +4692,7 @@ static void colorDrawPiece(piece, square_color, x, y, dest) int square_color, x, y; Drawable dest; { + if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap; switch (square_color) { case 1: /* light */ XCopyPlane(xDisplay, *pieceToSolid(piece), @@ -4066,7 +4745,7 @@ static void colorDrawPieceImage(piece, square_color, x, y, dest) } XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, - squareSize, squareSize, x, y); + squareSize, squareSize, x, y); } typedef void (*DrawFunc)(); @@ -4087,6 +4766,32 @@ DrawFunc ChooseDrawFunc() } } +/* [HR] determine square color depending on chess variant. */ +static int SquareColor(row, column) + int row, column; +{ + int square_color; + + if (gameInfo.variant == VariantXiangqi) { + if (column >= 3 && column <= 5 && row >= 0 && row <= 2) { + square_color = 1; + } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) { + square_color = 0; + } else if (row <= 4) { + square_color = 0; + } else { + square_color = 1; + } + } else { + square_color = ((column + row) % 2) == 1; + } + + /* [hgm] holdings: next line makes all holdings squares light */ + if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1; + + return square_color; +} + void DrawSquare(row, column, piece, do_flash) int row, column, do_flash; ChessSquare piece; @@ -4100,56 +4805,93 @@ void DrawSquare(row, column, piece, do_flash) /* Calculate delay in milliseconds (2-delays per complete flash) */ flash_delay = 500 / appData.flashRate; - + if (flipView) { - x = lineGap + ((BOARD_SIZE-1)-column) * + x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap); y = lineGap + row * (squareSize + lineGap); } else { x = lineGap + column * (squareSize + lineGap); - y = lineGap + ((BOARD_SIZE-1)-row) * + y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap); } - - square_color = ((column + row) % 2) == 1; - - 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= 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= 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, + x + squareSize - overall.width - 2, y + squareSize - font_descent - 1, string, 1); } else { XDrawString(xDisplay, xBoardWindow, coordGC, - x + squareSize - overall.width - 2, + x + squareSize - overall.width - 2, y + squareSize - font_descent - 1, string, 1); } } - if (appData.showCoords && column == (flipView ? 7 : 0)) { - string[0] = '1' + row; - XTextExtents(coordFontStruct, string, 1, &direction, + 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, @@ -4157,8 +4899,8 @@ void DrawSquare(row, column, piece, do_flash) } else { XDrawString(xDisplay, xBoardWindow, coordGC, x + 2, y + font_ascent + 1, string, 1); - } - } + } + } } @@ -4196,9 +4938,9 @@ static int too_many_diffs(b1, b2) { int i, j; int c = 0; - - for (i=0; i 4) /* Castling causes 4 diffs */ return 1; @@ -4220,9 +4962,9 @@ static int castling_matrix[4][5] = { /* Checks whether castling occurred. If it did, *rrow and *rcol are set to the destination (row,col) of the rook that moved. - + Returns 1 if castling occurred, 0 if not. - + Note: Only handles a max of 1 castling move, so be sure to call too_many_diffs() first. */ @@ -4272,7 +5014,7 @@ void XDrawPosition(w, repaint, board) static Board lastBoard; Arg args[16]; int rrow, rcol; - + if (board == NULL) { if (!lastBoardValid) return; board = lastBoard; @@ -4287,7 +5029,7 @@ void XDrawPosition(w, repaint, board) * It would be simpler to clear the window with XClearWindow() * but this causes a very distracting flicker. */ - + if (!repaint && lastBoardValid && lastFlipView == flipView) { /* If too much changes (begin observing new game, etc.), don't @@ -4304,11 +5046,11 @@ void XDrawPosition(w, repaint, board) } } - /* First pass -- Draw (newly) empty squares and repair damage. - This prevents you from having a piece show up twice while it + /* First pass -- Draw (newly) empty squares and repair damage. + This prevents you from having a piece show up twice while it is flashing on its new square */ - for (i = 0; i < BOARD_SIZE; i++) - for (j = 0; j < BOARD_SIZE; j++) + for (i = 0; i < BOARD_HEIGHT; i++) + for (j = 0; j < BOARD_WIDTH; j++) if ((board[i][j] != lastBoard[i][j] && board[i][j] == EmptySquare) || damage[i][j]) { DrawSquare(i, j, board[i][j], 0); @@ -4316,18 +5058,18 @@ void XDrawPosition(w, repaint, board) } /* Second pass -- Draw piece(s) in new position and flash them */ - for (i = 0; i < BOARD_SIZE; i++) - for (j = 0; j < BOARD_SIZE; j++) + for (i = 0; i < BOARD_HEIGHT; i++) + for (j = 0; j < BOARD_WIDTH; j++) if (board[i][j] != lastBoard[i][j]) { - DrawSquare(i, j, board[i][j], do_flash); + DrawSquare(i, j, board[i][j], do_flash); } } else { if (lineGap > 0) XDrawSegments(xDisplay, xBoardWindow, lineGC, - gridSegments, (BOARD_SIZE + 1) * 2); - - for (i = 0; i < BOARD_SIZE; i++) - for (j = 0; j < BOARD_SIZE; j++) { + gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2); + + for (i = 0; i < BOARD_HEIGHT; i++) + for (j = 0; j < BOARD_WIDTH; j++) { DrawSquare(i, j, board[i][j], 0); damage[i][j] = False; } @@ -4374,6 +5116,13 @@ void DrawPositionProc(w, event, prms, nprms) /* * event handler for parsing user moves */ +// [HGM] This routine will need quite some reworking. Although the backend still supports the old +// way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform +// it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it +// should be made to use the new way, of calling UserMoveTest early to determine the legality of the +// move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions), +// and at the end FinishMove() to perform the move after optional promotion popups. +// For now I patched it to allow self-capture with King, and suppress clicks between board and holdings. void HandleUserMove(w, event, prms, nprms) Widget w; XEvent *event; @@ -4383,7 +5132,7 @@ void HandleUserMove(w, event, prms, nprms) int x, y; Boolean saveAnimate; static int second = 0; - + if (w != boardWidget || errorExitStatus != -1) return; if (event->type == ButtonPress) ErrorPopDown(); @@ -4399,19 +5148,26 @@ void HandleUserMove(w, event, prms, nprms) return; } } - - x = EventToSquare(event->xbutton.x, BOARD_SIZE); - y = EventToSquare(event->xbutton.y, BOARD_SIZE); + + x = EventToSquare(event->xbutton.x, BOARD_WIDTH); + y = EventToSquare(event->xbutton.y, BOARD_HEIGHT); if (!flipView && y >= 0) { - y = BOARD_SIZE - 1 - y; + y = BOARD_HEIGHT - 1 - y; } if (flipView && x >= 0) { - x = BOARD_SIZE - 1 - x; + x = BOARD_WIDTH - 1 - x; } + /* [HGM] holdings: next 5 lines: ignore all clicks between board and holdings */ + if(event->type == ButtonPress + && ( x == BOARD_LEFT-1 || x == BOARD_RGHT + || x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize + || x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize) ) + return; + if (fromX == -1) { if (event->type == ButtonPress) { - /* First square */ + /* First square */ if (OKToStartUserMove(x, y)) { fromX = x; fromY = y; @@ -4420,7 +5176,7 @@ void HandleUserMove(w, event, prms, nprms) if (appData.highlightDragging) { SetHighlights(x, y, -1, -1); } - } + } } return; } @@ -4430,13 +5186,18 @@ void HandleUserMove(w, event, prms, nprms) x >= 0 && y >= 0) { ChessSquare fromP; ChessSquare toP; + int frc; + /* Check if clicking again on the same color piece */ fromP = boards[currentMove][fromY][fromX]; toP = boards[currentMove][y][x]; - if ((WhitePawn <= fromP && fromP <= WhiteKing && - WhitePawn <= toP && toP <= WhiteKing) || - (BlackPawn <= fromP && fromP <= BlackKing && - BlackPawn <= toP && toP <= BlackKing)) { + frc = gameInfo.variant == VariantFischeRandom || gameInfo.variant == VariantCapaRandom; + if ((WhitePawn <= fromP && fromP <= WhiteKing && // [HGM] this test should go, as UserMoveTest now does it. + WhitePawn <= toP && toP <= WhiteKing && + !(fromP == WhiteKing && toP == WhiteRook && frc)) || + (BlackPawn <= fromP && fromP <= BlackKing && + BlackPawn <= toP && toP <= BlackKing && + !(fromP == BlackKing && toP == BlackRook && frc))) { /* Clicked again on same color piece -- changed his mind */ second = (x == fromX && y == fromY); if (appData.highlightDragging) { @@ -4471,7 +5232,7 @@ void HandleUserMove(w, event, prms, nprms) SetHighlights(x, y, -1, -1); } return; - } + } /* Completed move */ toX = x; @@ -4796,7 +5557,7 @@ void EditCommentPopUp(index, title, text) if (editShell == NULL) { editShell = - CommentCreate(title, text, True, EditCommentCallback, 4); + CommentCreate(title, text, True, EditCommentCallback, 4); XtRealizeWidget(editShell); CatchDeleteWindow(editShell, "EditCommentPopDown"); } else { @@ -4875,7 +5636,7 @@ void ICSInputBoxPopUp() int j; char *title = _("ICS Input"); XtTranslations tr; - + if (ICSInputShell == NULL) { ICSInputShell = MiscCreate(title, "", True, NULL, 1); tr = XtParseTranslationTable(ICSInputTranslations); @@ -4883,7 +5644,7 @@ void ICSInputBoxPopUp() XtOverrideTranslations(edit, tr); XtRealizeWidget(ICSInputShell); CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown"); - + } else { edit = XtNameToWidget(ICSInputShell, "*form.text"); j = 0; @@ -4911,7 +5672,7 @@ void ICSInputSendText() int j; Arg args[16]; String val; - + edit = XtNameToWidget(ICSInputShell, "*form.text"); j = 0; XtSetArg(args[j], XtNstring, &val); j++; @@ -5040,8 +5801,7 @@ void AnalysisPopDown() XtPopdown(analysisShell); XSync(xDisplay, False); analysisUp = False; - /* icsEngineAnalyze */ - if (appData.icsEngineAnalyze) ExitAnalyzeMode(); + if (appData.icsEngineAnalyze) ExitAnalyzeMode(); /* [DM] icsEngineAnalyze */ } @@ -5057,10 +5817,10 @@ void FileNamePopUp(label, def, proc, openMode) int x, y, i; int win_x, win_y; unsigned int mask; - + fileProc = proc; /* I can't see a way not */ fileOpenMode = openMode; /* to use globals here */ - + i = 0; XtSetArg(args[i], XtNresizable, True); i++; XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++; @@ -5068,11 +5828,11 @@ void FileNamePopUp(label, def, proc, openMode) fileNameShell = popup = XtCreatePopupShell("File name prompt", transientShellWidgetClass, shellWidget, args, i); - + layout = XtCreateManagedWidget(layoutName, formWidgetClass, popup, layoutArgs, XtNumber(layoutArgs)); - + i = 0; XtSetArg(args[i], XtNlabel, label); i++; XtSetArg(args[i], XtNvalue, def); i++; @@ -5082,21 +5842,21 @@ void FileNamePopUp(label, def, proc, openMode) XawDialogAddButton(dialog, _("ok"), FileNameCallback, (XtPointer) dialog); XawDialogAddButton(dialog, _("cancel"), FileNameCallback, - (XtPointer) dialog); + (XtPointer) dialog); XtRealizeWidget(popup); CatchDeleteWindow(popup, "FileNamePopDown"); - + XQueryPointer(xDisplay, xBoardWindow, &root, &child, &x, &y, &win_x, &win_y, &mask); - + XtSetArg(args[0], XtNx, x - 10); XtSetArg(args[1], XtNy, y - 30); XtSetValues(popup, args, 2); - + XtPopup(popup, XtGrabExclusive); filenameUp = True; - + edit = XtNameToWidget(dialog, "*value"); XtSetKeyboardFocus(popup, edit); } @@ -5116,15 +5876,15 @@ void FileNameCallback(w, client_data, call_data) { String name; Arg args[16]; - + XtSetArg(args[0], XtNlabel, &name); XtGetValues(w, args, 1); - + if (strcmp(name, _("cancel")) == 0) { FileNamePopDown(); return; } - + FileNameAction(w, NULL, NULL, NULL); } @@ -5141,7 +5901,7 @@ void FileNameAction(w, event, prms, nprms) int index; name = XawDialogGetValueString(w = XtParent(w)); - + if ((name != NULL) && (*name != NULLCHAR)) { strcpy(buf, name); XtPopdown(w = XtParent(XtParent(w))); @@ -5170,7 +5930,7 @@ void FileNameAction(w, event, prms, nprms) ModeHighlight(); return; } - + XtPopdown(w = XtParent(XtParent(w))); XtDestroyWidget(w); filenameUp = False; @@ -5188,7 +5948,7 @@ void PromotionPopUp() j = 0; XtSetArg(args[j], XtNwidth, &bw_width); j++; XtGetValues(boardWidget, args, j); - + j = 0; XtSetArg(args[j], XtNresizable, True); j++; XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++; @@ -5198,48 +5958,64 @@ void PromotionPopUp() layout = XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell, layoutArgs, XtNumber(layoutArgs)); - + j = 0; - XtSetArg(args[j], XtNlabel, _("Promote pawn to what?")); j++; + XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++; XtSetArg(args[j], XtNborderWidth, 0); j++; dialog = XtCreateManagedWidget("promotion", dialogWidgetClass, layout, args, j); - - XawDialogAddButton(dialog, _("Queen"), PromotionCallback, + + if(gameInfo.variant != VariantShogi) { + XawDialogAddButton(dialog, _("Queen"), PromotionCallback, (XtPointer) dialog); - XawDialogAddButton(dialog, _("Rook"), PromotionCallback, + XawDialogAddButton(dialog, _("Rook"), PromotionCallback, (XtPointer) dialog); - XawDialogAddButton(dialog, _("Bishop"), PromotionCallback, + XawDialogAddButton(dialog, _("Bishop"), PromotionCallback, (XtPointer) dialog); - XawDialogAddButton(dialog, _("Knight"), PromotionCallback, + XawDialogAddButton(dialog, _("Knight"), PromotionCallback, (XtPointer) dialog); if (!appData.testLegality || gameInfo.variant == VariantSuicide || gameInfo.variant == VariantGiveaway) { - XawDialogAddButton(dialog, _("King"), PromotionCallback, + XawDialogAddButton(dialog, _("King"), PromotionCallback, + (XtPointer) dialog); + } + if(gameInfo.variant == VariantCapablanca || + gameInfo.variant == VariantGothic || + gameInfo.variant == VariantCapaRandom) { + XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback, + (XtPointer) dialog); + XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback, (XtPointer) dialog); } - XawDialogAddButton(dialog, _("cancel"), PromotionCallback, + } else // [HGM] shogi + { + XawDialogAddButton(dialog, _("Promote"), PromotionCallback, + (XtPointer) dialog); + XawDialogAddButton(dialog, _("Defer"), PromotionCallback, + (XtPointer) dialog); + } + XawDialogAddButton(dialog, _("cancel"), PromotionCallback, (XtPointer) dialog); - + XtRealizeWidget(promotionShell); CatchDeleteWindow(promotionShell, "PromotionPopDown"); - + j = 0; XtSetArg(args[j], XtNwidth, &pw_width); j++; XtGetValues(promotionShell, args, j); - + XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2, lineGap + squareSize/3 + - ((toY == 7) ^ (flipView) ? + ((toY == BOARD_HEIGHT-1) ^ (flipView) ? 0 : 6*(squareSize + lineGap)), &x, &y); - + j = 0; XtSetArg(args[j], XtNx, x); j++; XtSetArg(args[j], XtNy, y); j++; XtSetValues(promotionShell, args, j); - + XtPopup(promotionShell, XtGrabNone); - + promotionUp = True; } @@ -5258,20 +6034,24 @@ void PromotionCallback(w, client_data, call_data) String name; Arg args[16]; int promoChar; - + XtSetArg(args[0], XtNlabel, &name); XtGetValues(w, args, 1); - + PromotionPopDown(); - + if (fromX == -1) return; - + if (strcmp(name, _("cancel")) == 0) { fromX = fromY = -1; ClearHighlights(); return; } else if (strcmp(name, _("Knight")) == 0) { promoChar = 'n'; + } else if (strcmp(name, _("Promote")) == 0) { + promoChar = '+'; + } else if (strcmp(name, _("Defer")) == 0) { + promoChar = '='; } else { promoChar = ToLower(name[0]); } @@ -5316,28 +6096,28 @@ void ErrorPopUp(title, label, modal) Dimension bw_width, pw_width; Dimension pw_height; int i; - + i = 0; XtSetArg(args[i], XtNresizable, True); i++; XtSetArg(args[i], XtNtitle, title); i++; - errorShell = + errorShell = XtCreatePopupShell("errorpopup", transientShellWidgetClass, shellWidget, args, i); layout = XtCreateManagedWidget(layoutName, formWidgetClass, errorShell, layoutArgs, XtNumber(layoutArgs)); - + i = 0; XtSetArg(args[i], XtNlabel, label); i++; XtSetArg(args[i], XtNborderWidth, 0); i++; dialog = XtCreateManagedWidget("dialog", dialogWidgetClass, layout, args, i); - + XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog); - + XtRealizeWidget(errorShell); CatchDeleteWindow(errorShell, "ErrorPopDown"); - + i = 0; XtSetArg(args[i], XtNwidth, &bw_width); i++; XtGetValues(boardWidget, args, i); @@ -5430,7 +6210,7 @@ char *ModeToWidgetName(mode) case EndOfGame: return NULL; } -} +} void ModeHighlight() { @@ -5438,7 +6218,7 @@ void ModeHighlight() static int oldPausing = FALSE; static GameMode oldmode = (GameMode) -1; char *wname; - + if (!boardWidget || !XtIsRealized(boardWidget)) return; if (pausing != oldPausing) { @@ -5495,6 +6275,7 @@ void ModeHighlight() gameMode == Training || gameMode == PlayFromGameFile); } + /* * Button/menu procedures */ @@ -5672,7 +6453,7 @@ SendPositionSelection(Widget w, Atom *selection, Atom *target, return True; } else { return False; - } + } } /* note: when called from menu all parameters are NULL, so no clue what the @@ -5687,7 +6468,7 @@ void CopyPositionProc(w, event, prms, nprms) int ret; if (selected_fen_position) free(selected_fen_position); - selected_fen_position = (char *)PositionToFEN(currentMove); + selected_fen_position = (char *)PositionToFEN(currentMove, NULL); if (!selected_fen_position) return; ret = XtOwnSelection(menuBarWidget, XA_PRIMARY, CurrentTime, @@ -5761,7 +6542,7 @@ SendGameSelection(Widget w, Atom *selection, Atom *target, return True; } else { return False; - } + } } /* note: when called from menu all parameters are NULL, so no clue what the @@ -5876,40 +6657,39 @@ void AnalyzeModeProc(w, event, prms, nprms) Cardinal *nprms; { char buf[MSG_SIZ]; - + if (!first.analysisSupport) { - sprintf(buf, _("%s does not support analysis"), first.tidy); + snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy); DisplayError(buf, 0); return; } - /* icsEngineAnalyze */ + /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */ if (appData.icsActive) { - if (gameMode != IcsObserving) { - sprintf(buf,_("You are not observing a game")); - DisplayError(buf, 0); - /* secure check */ - if (appData.icsEngineAnalyze) { - if (appData.debugMode) - fprintf(debugFP, _("Found unexpected active ICS engine analyze \n")); - ExitAnalyzeMode(); - ModeHighlight(); - return; - } - return; - } else { - /* if enable, use want disable icsEngineAnalyze */ - if (appData.icsEngineAnalyze) { - ExitAnalyzeMode(); - ModeHighlight(); - return; + if (gameMode != IcsObserving) { + sprintf(buf,_("You are not observing a game")); + DisplayError(buf, 0); + /* secure check */ + if (appData.icsEngineAnalyze) { + if (appData.debugMode) + fprintf(debugFP, _("Found unexpected active ICS engine analyze \n")); + ExitAnalyzeMode(); + ModeHighlight(); + } + return; + } + /* if enable, use want disable icsEngineAnalyze */ + if (appData.icsEngineAnalyze) { + ExitAnalyzeMode(); + ModeHighlight(); + return; } appData.icsEngineAnalyze = TRUE; if (appData.debugMode) - fprintf(debugFP, "ICS engine analyze starting... \n"); - } - } + fprintf(debugFP, _("ICS engine analyze starting... \n")); + } if (!appData.showThinking) ShowThinkingProc(w,event,prms,nprms); + AnalyzeModeEvent(); } @@ -5921,7 +6701,7 @@ void AnalyzeFileProc(w, event, prms, nprms) { if (!first.analysisSupport) { char buf[MSG_SIZ]; - sprintf(buf, _("%s does not support analysis"), first.tidy); + snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy); DisplayError(buf, 0); return; } @@ -6078,6 +6858,33 @@ void ResignProc(w, event, prms, nprms) ResignEvent(); } +void AdjuWhiteProc(w, event, prms, nprms) + Widget w; + XEvent *event; + String *prms; + Cardinal *nprms; +{ + UserAdjudicationEvent(+1); +} + +void AdjuBlackProc(w, event, prms, nprms) + Widget w; + XEvent *event; + String *prms; + Cardinal *nprms; +{ + UserAdjudicationEvent(-1); +} + +void AdjuDrawProc(w, event, prms, nprms) + Widget w; + XEvent *event; + String *prms; + Cardinal *nprms; +{ + UserAdjudicationEvent(0); +} + void EnterKeyProc(w, event, prms, nprms) Widget w; XEvent *event; @@ -6555,7 +7362,7 @@ void PeriodicUpdatesProc(w, event, prms, nprms) Arg args[16]; PeriodicUpdatesEvent(!appData.periodicUpdates); - + if (appData.periodicUpdates) { XtSetArg(args[0], XtNleftBitmap, xMarkPixmap); } else { @@ -6689,8 +7496,10 @@ void ShowThinkingProc(w, event, prms, nprms) { Arg args[16]; - ShowThinkingEvent(!appData.showThinking); - + appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent + ShowThinkingEvent(); +#if 0 + // [HGM] thinking: currently no suc menu item; replaced by Hide Thinking (From Human) if (appData.showThinking) { XtSetArg(args[0], XtNleftBitmap, xMarkPixmap); } else { @@ -6698,6 +7507,27 @@ void ShowThinkingProc(w, event, prms, nprms) } XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Thinking"), args, 1); +#endif +} + +void HideThinkingProc(w, event, prms, nprms) + Widget w; + XEvent *event; + String *prms; + Cardinal *nprms; +{ + Arg args[16]; + + appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent + ShowThinkingEvent(); + + if (appData.hideThinkingFromHuman) { + XtSetArg(args[0], XtNleftBitmap, xMarkPixmap); + } else { + XtSetArg(args[0], XtNleftBitmap, None); + } + XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"), + args, 1); } void InfoProc(w, event, prms, nprms) @@ -6707,7 +7537,7 @@ void InfoProc(w, event, prms, nprms) Cardinal *nprms; { char buf[MSG_SIZ]; - sprintf(buf, "xterm -e info --directory %s --directory . -f %s &", + snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &", INFODIR, INFOFILE); system(buf); } @@ -6724,7 +7554,7 @@ void ManProc(w, event, prms, nprms) name = prms[0]; else name = "xboard"; - sprintf(buf, "xterm -e man %s &", name); + snprintf(buf, sizeof(buf), "xterm -e man %s &", name); system(buf); } @@ -6758,11 +7588,12 @@ void AboutProc(w, event, prms, nprms) #else char *zippy = ""; #endif - sprintf(buf, "%s%s\n\n%s\n%s\n\n%s%s\n%s", + snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s", programVersion, zippy, "Copyright 1991 Digital Equipment Corporation", - "Enhancements Copyright 1992-2001 Free Software Foundation", - PRODUCT, " is free software and carries NO WARRANTY;", + "Enhancements Copyright 1992-2009 Free Software Foundation", + "Enhancements Copyright 2005 Alessandro Scotti", + PACKAGE, " is free software and carries NO WARRANTY;", "see the file COPYING for more information."); ErrorPopUp(_("About XBoard"), buf, FALSE); } @@ -6801,7 +7632,7 @@ void Iconify(w, event, prms, nprms) Cardinal *nprms; { Arg args[16]; - + fromX = fromY = -1; XtSetArg(args[0], XtNiconic, True); XtSetValues(shellWidget, args, 1); @@ -6812,10 +7643,10 @@ void DisplayMessage(message, extMessage) { char buf[MSG_SIZ]; Arg arg; - + if (extMessage) { if (*message) { - sprintf(buf, "%s %s", message, extMessage); + snprintf(buf, sizeof(buf), "%s %s", message, extMessage); message = buf; } else { message = extMessage; @@ -6845,17 +7676,28 @@ void DisplayTitle(text) strcpy(icon, text); strcpy(title, text); } else if (appData.icsActive) { - sprintf(icon, "%s", appData.icsHost); - sprintf(title, "%s: %s", programName, appData.icsHost); + snprintf(icon, sizeof(icon), "%s", appData.icsHost); + snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost); } else if (appData.cmailGameName[0] != NULLCHAR) { - sprintf(icon, "%s", "CMail"); - sprintf(title, "%s: %s", programName, "CMail"); + snprintf(icon, sizeof(icon), "%s", "CMail"); + snprintf(title,sizeof(title), "%s: %s", programName, "CMail"); +#ifdef GOTHIC + // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it + } else if (gameInfo.variant == VariantGothic) { + strcpy(icon, programName); + strcpy(title, GOTHIC); +#endif +#ifdef FALCON + } else if (gameInfo.variant == VariantFalcon) { + strcpy(icon, programName); + strcpy(title, FALCON); +#endif } else if (appData.noChessProgram) { strcpy(icon, programName); strcpy(title, programName); } else { strcpy(icon, first.tidy); - sprintf(title, "%s: %s", programName, first.tidy); + snprintf(title,sizeof(title), "%s: %s", programName, first.tidy); } i = 0; XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++; @@ -6879,9 +7721,9 @@ void DisplayError(message, error) fprintf(stderr, "%s: %s: %s\n", programName, message, strerror(error)); } - sprintf(buf, "%s: %s", message, strerror(error)); + snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error)); message = buf; - } + } ErrorPopUp(_("Error"), message, FALSE); } @@ -6915,7 +7757,7 @@ void DisplayFatalError(message, error, status) } else { fprintf(stderr, "%s: %s: %s\n", programName, message, strerror(error)); - sprintf(buf, "%s: %s", message, strerror(error)); + snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error)); message = buf; } if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) { @@ -6969,9 +7811,9 @@ void DisplayIcsInteractionTitle(message) XSetErrorHandler(oldHandler); } if (oldICSInteractionTitle == NULL) { - oldICSInteractionTitle = "xterm"; + oldICSInteractionTitle = "xterm"; } - } + } printf("\033]0;%s\007", message); fflush(stdout); } @@ -7031,7 +7873,7 @@ void AskQuestionCallback(w, client_data, call_data) XtSetArg(args[0], XtNlabel, &name); XtGetValues(w, args, 1); - + if (strcmp(name, _("cancel")) == 0) { AskQuestionPopDown(); } else { @@ -7049,28 +7891,28 @@ void AskQuestion(title, question, replyPrefix, pr) int x, y, i; int win_x, win_y; unsigned int mask; - + strcpy(pendingReplyPrefix, replyPrefix); pendingReplyPR = pr; - + i = 0; XtSetArg(args[i], XtNresizable, True); i++; XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++; askQuestionShell = popup = XtCreatePopupShell(title, transientShellWidgetClass, shellWidget, args, i); - + layout = XtCreateManagedWidget(layoutName, formWidgetClass, popup, layoutArgs, XtNumber(layoutArgs)); - + i = 0; XtSetArg(args[i], XtNlabel, question); i++; XtSetArg(args[i], XtNvalue, ""); i++; XtSetArg(args[i], XtNborderWidth, 0); i++; dialog = XtCreateManagedWidget("question", dialogWidgetClass, layout, args, i); - + XawDialogAddButton(dialog, _("enter"), AskQuestionCallback, (XtPointer) dialog); XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback, @@ -7078,17 +7920,17 @@ void AskQuestion(title, question, replyPrefix, pr) XtRealizeWidget(popup); CatchDeleteWindow(popup, "AskQuestionPopDown"); - + XQueryPointer(xDisplay, xBoardWindow, &root, &child, &x, &y, &win_x, &win_y, &mask); - + XtSetArg(args[0], XtNx, x - 10); XtSetArg(args[1], XtNy, y - 30); XtSetValues(popup, args, 2); - + XtPopup(popup, XtGrabExclusive); askQuestionUp = True; - + edit = XtNameToWidget(dialog, "*value"); XtSetKeyboardFocus(popup, edit); } @@ -7104,7 +7946,7 @@ PlaySound(name) putc(BELLCHAR, stderr); } else { char buf[2048]; - sprintf(buf, "%s '%s' &", appData.soundProgram, name); + snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name); system(buf); } } @@ -7234,7 +8076,7 @@ static char *ExpandPathName(path) static char static_buf[2000]; char *d, *s, buf[2000]; struct passwd *pwd; - + s = path; d = static_buf; @@ -7269,12 +8111,12 @@ static char *ExpandPathName(path) strcpy(d, s); return static_buf; -} +} char *HostName() { static char host_name[MSG_SIZ]; - + #if HAVE_GETHOSTNAME gethostname(host_name, MSG_SIZ); return host_name; @@ -7302,6 +8144,9 @@ void ScheduleDelayedEvent(cb, millisec) DelayedEventCallback cb; long millisec; { + if(delayedEventTimerXID && delayedEventCallback == cb) + // [HGM] alive: replace, rather than add or flush identical event + XtRemoveTimeOut(delayedEventTimerXID); delayedEventCallback = cb; delayedEventTimerXID = XtAppAddTimeOut(appContext, millisec, @@ -7371,8 +8216,8 @@ AnalysisClockCallback(arg, id) XtPointer arg; XtIntervalId *id; { - if (gameMode == AnalyzeMode || gameMode == AnalyzeFile - || appData.icsEngineAnalyze) { + if (gameMode == AnalyzeMode || gameMode == AnalyzeFile + || appData.icsEngineAnalyze) { // [DM] AnalysisPeriodicEvent(0); StartAnalysisClock(); } @@ -7433,7 +8278,15 @@ DisplayTimerLabel(w, color, timer, highlight) { char buf[MSG_SIZ]; Arg args[16]; - + + /* check for low time warning */ + Pixel foregroundOrWarningColor = timerForegroundPixel; + + if (timer > 0 && + appData.lowTimeWarning && + (timer / 1000) < appData.icsAlarmTime) + foregroundOrWarningColor = lowTimeWarningColor; + if (appData.clockMode) { sprintf(buf, "%s: %s", color, TimeString(timer)); XtSetArg(args[0], XtNlabel, buf); @@ -7441,15 +8294,16 @@ DisplayTimerLabel(w, color, timer, highlight) sprintf(buf, "%s ", color); XtSetArg(args[0], XtNlabel, buf); } - + if (highlight) { - XtSetArg(args[1], XtNbackground, timerForegroundPixel); + + XtSetArg(args[1], XtNbackground, foregroundOrWarningColor); XtSetArg(args[2], XtNforeground, timerBackgroundPixel); } else { XtSetArg(args[1], XtNbackground, timerBackgroundPixel); - XtSetArg(args[2], XtNforeground, timerForegroundPixel); + XtSetArg(args[2], XtNforeground, foregroundOrWarningColor); } - + XtSetValues(w, args, 3); } @@ -7459,6 +8313,8 @@ DisplayWhiteClock(timeRemaining, highlight) int highlight; { Arg args[16]; + + if(appData.noGUI) return; DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight); if (highlight && iconPixmap == bIconPixmap) { iconPixmap = wIconPixmap; @@ -7473,6 +8329,8 @@ DisplayBlackClock(timeRemaining, highlight) int highlight; { Arg args[16]; + + if(appData.noGUI) return; DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight); if (highlight && iconPixmap == wIconPixmap) { iconPixmap = bIconPixmap; @@ -7491,12 +8349,12 @@ typedef int CPKind; typedef struct { CPKind kind; int pid; - int fdTo, fdFrom; + int fdTo, fdFrom; } ChildProc; int StartChildProcess(cmdLine, dir, pr) - char *cmdLine; + char *cmdLine; char *dir; ProcRef *pr; { @@ -7505,7 +8363,7 @@ int StartChildProcess(cmdLine, dir, pr) int to_prog[2], from_prog[2]; ChildProc *cp; char buf[MSG_SIZ]; - + if (appData.debugMode) { fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine); } @@ -7529,30 +8387,34 @@ int StartChildProcess(cmdLine, dir, pr) if ((pid = fork()) == 0) { /* Child process */ - dup2(to_prog[0], 0); - dup2(from_prog[1], 1); - close(to_prog[0]); - close(to_prog[1]); + // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1 + close(to_prog[1]); // first close the unused pipe ends close(from_prog[0]); - close(from_prog[1]); - dup2(1, fileno(stderr)); /* force stderr to the pipe */ + dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1 + dup2(from_prog[1], 1); + if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original + close(from_prog[1]); // and closing again loses one of the pipes! + if(fileno(stderr) >= 2) // better safe than sorry... + dup2(1, fileno(stderr)); /* force stderr to the pipe */ if (dir[0] != NULLCHAR && chdir(dir) != 0) { perror(dir); exit(1); } + nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc + execvp(argv[0], argv); - + /* If we get here, exec failed */ perror(argv[0]); exit(1); } - + /* Parent process */ close(to_prog[0]); close(from_prog[1]); - + cp = (ChildProc *) calloc(1, sizeof(ChildProc)); cp->kind = CPReal; cp->pid = pid; @@ -7562,22 +8424,37 @@ int StartChildProcess(cmdLine, dir, pr) return 0; } +// [HGM] kill: implement the 'hard killing' of AS's Winboard_x +static RETSIGTYPE AlarmCallBack(int n) +{ + return; +} + void -DestroyChildProcess(pr, signal) +DestroyChildProcess(pr, signalType) ProcRef pr; - int signal; + int signalType; { ChildProc *cp = (ChildProc *) pr; if (cp->kind != CPReal) return; cp->kind = CPNone; - if (signal) { - kill(cp->pid, SIGTERM); + if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill + signal(SIGALRM, AlarmCallBack); + alarm(3); + if(wait((int *) 0) == -1) { // process does not terminate on its own accord + kill(cp->pid, SIGKILL); // kill it forcefully + wait((int *) 0); // and wait again + } + } else { + if (signalType) { + kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested + } + /* Process is exiting either because of the kill or because of + a quit command sent by the backend; either way, wait for it to die. + */ + wait((int *) 0); } - /* Process is exiting either because of the kill or because of - a quit command sent by the backend; either way, wait for it to die. - */ - wait((int *) 0); close(cp->fdFrom); close(cp->fdTo); } @@ -7600,9 +8477,9 @@ int OpenTelnet(host, port, pr) char cmdLine[MSG_SIZ]; if (port[0] == NULLCHAR) { - sprintf(cmdLine, "%s %s", appData.telnetProgram, host); + snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host); } else { - sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port); + snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port); } return StartChildProcess(cmdLine, "", pr); } @@ -7656,7 +8533,7 @@ int OpenTCP(host, port, pr) sa.sin_port = htons(uport); memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length); - if (connect(s, (struct sockaddr *) &sa, + if (connect(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) { return errno; } @@ -7717,7 +8594,7 @@ int OpenRcmd(host, user, cmd, pr) { DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1); return -1; -} +} #define INPUT_SOURCE_BUF_SIZE 8192 @@ -7733,7 +8610,7 @@ typedef struct { } InputSource; void -DoInputCallback(closure, source, xid) +DoInputCallback(closure, source, xid) caddr_t closure; int *source; XtInputId *xid; @@ -7771,7 +8648,7 @@ DoInputCallback(closure, source, xid) else error = 0; (is->func)(is, is->closure, is->buf, count, error); - } + } } InputSourceRef AddInputSource(pr, lineByLine, func, closure) @@ -7796,7 +8673,7 @@ InputSourceRef AddInputSource(pr, lineByLine, func, closure) if (lineByLine) { is->unused = is->buf; } - + is->xid = XtAppAddInput(appContext, is->fd, (XtPointer) (XtInputReadMask), (XtInputCallbackProc) DoInputCallback, @@ -7852,7 +8729,7 @@ int OutputToProcessDelayed(pr, message, count, outError, msdelay) ChildProc *cp = (ChildProc *) pr; int outCount = 0; int r; - + while (count--) { r = write(cp->fdTo, message++, 1); if (r == -1) { @@ -7886,6 +8763,8 @@ int OutputToProcessDelayed(pr, message, count, outError, msdelay) and dark squares, and all pieces must use the same background square colors/images. */ +static int xpmDone = 0; + static void CreateAnimMasks (pieceDepth) int pieceDepth; @@ -7908,7 +8787,7 @@ CreateAnimMasks (pieceDepth) XFreePixmap(xDisplay, buf); buf = XCreatePixmap(xDisplay, xBoardWindow, - squareSize, squareSize, pieceDepth); + squareSize, squareSize, pieceDepth); values.foreground = XBlackPixel(xDisplay, xScreen); values.background = XWhitePixel(xDisplay, xScreen); bufGC = XCreateGC(xDisplay, buf, @@ -7916,22 +8795,23 @@ CreateAnimMasks (pieceDepth) for (piece = WhitePawn; piece <= BlackKing; piece++) { /* Begin with empty mask */ + if(!xpmDone) // [HGM] pieces: keep using existing xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow, squareSize, squareSize, 1); XSetFunction(xDisplay, maskGC, GXclear); XFillRectangle(xDisplay, xpmMask[piece], maskGC, 0, 0, squareSize, squareSize); - + /* Take a copy of the piece */ if (White(piece)) kind = 0; else kind = 2; XSetFunction(xDisplay, bufGC, GXcopy); - XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % 6], + XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn], buf, bufGC, 0, 0, squareSize, squareSize, 0, 0); - + /* XOR the background (light) over the piece */ XSetFunction(xDisplay, bufGC, GXxor); if (useImageSqs) @@ -7941,7 +8821,7 @@ CreateAnimMasks (pieceDepth) XSetForeground(xDisplay, bufGC, lightSquareColor); XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize); } - + /* We now have an inverted piece image with the background erased. Construct mask by just selecting all the non-zero pixels - no need to reconstruct the original image. */ @@ -7971,7 +8851,7 @@ InitAnimState (anim, info) { XtGCMask mask; XGCValues values; - + /* Each buffer is square size, same depth as window */ anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow, squareSize, squareSize, info->depth); @@ -7999,19 +8879,20 @@ InitAnimState (anim, info) static void CreateAnimVars () { - static int done = 0; + static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes XWindowAttributes info; - if (done) return; - done = 1; + if (xpmDone && gameInfo.variant == old) return; + if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet XGetWindowAttributes(xDisplay, xBoardWindow, &info); - + InitAnimState(&game, &info); InitAnimState(&player, &info); - + /* For XPM pieces, we need bitmaps to use as masks. */ if (useImages) CreateAnimMasks(info.depth); + xpmDone = 1; } #ifndef HAVE_USLEEP @@ -8031,20 +8912,20 @@ FrameDelay (time) int time; { struct itimerval delay; - + XSync(xDisplay, False); if (time > 0) { frameWaiting = True; signal(SIGALRM, FrameAlarm); - delay.it_interval.tv_sec = + delay.it_interval.tv_sec = delay.it_value.tv_sec = time / 1000; - delay.it_interval.tv_usec = + delay.it_interval.tv_usec = delay.it_value.tv_usec = (time % 1000) * 1000; setitimer(ITIMER_REAL, &delay, NULL); #if 0 /* Ugh -- busy-wait! --tpm */ - while (frameWaiting); + while (frameWaiting); #else while (frameWaiting) pause(); #endif @@ -8074,13 +8955,13 @@ ScreenSquare(column, row, pt, color) int column; int row; XPoint * pt; int * color; { if (flipView) { - pt->x = lineGap + ((BOARD_SIZE-1)-column) * (squareSize + lineGap); + pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap); pt->y = lineGap + row * (squareSize + lineGap); } else { pt->x = lineGap + column * (squareSize + lineGap); - pt->y = lineGap + ((BOARD_SIZE-1)-row) * (squareSize + lineGap); + pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap); } - *color = ((column + row) % 2) == 1; + *color = SquareColor(row, column); } /* Convert window coords to square */ @@ -8089,12 +8970,12 @@ static void BoardSquare(x, y, column, row) int x; int y; int * column; int * row; { - *column = EventToSquare(x, BOARD_SIZE); + *column = EventToSquare(x, BOARD_WIDTH); if (flipView && *column >= 0) - *column = BOARD_SIZE - 1 - *column; - *row = EventToSquare(y, BOARD_SIZE); + *column = BOARD_WIDTH - 1 - *column; + *row = EventToSquare(y, BOARD_HEIGHT); if (!flipView && *row >= 0) - *row = BOARD_SIZE - 1 - *row; + *row = BOARD_HEIGHT - 1 - *row; } /* Utilities */ @@ -8117,7 +8998,7 @@ SetRect(rect, x, y, width, height) /* Test if two frames overlap. If they do, return intersection rect within old and location of that rect within new. */ - + static Boolean Intersect(old, new, size, area, pt) XPoint * old; XPoint * new; @@ -8137,7 +9018,7 @@ Intersect(old, new, size, area, pt) /* For two overlapping frames, return the rect(s) in the old that do not intersect with the new. */ - + static void CalcUpdateRects(old, new, size, update, nUpdates) XPoint * old; XPoint * new; int size; @@ -8206,11 +9087,11 @@ Tween(start, mid, finish, factor, frames, nFrames) count ++; fraction = fraction / 2; } - + /* Midpoint */ frames[count] = *mid; count ++; - + /* Slow out, stepping 1/2, then 1/4, ... */ fraction = 2; for (n = 0; n < factor; n++) { @@ -8237,7 +9118,7 @@ SelectGCMask(piece, clip, outline, mask) #if HAVE_LIBXPM *mask = xpmMask[piece]; #else - *mask = ximMaskPm[piece%6]; + *mask = ximMaskPm[piece]; #endif } else { *mask = *pieceToSolid(piece); @@ -8257,7 +9138,7 @@ SelectGCMask(piece, clip, outline, mask) source = blPieceGC; } XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip); - + /* Outline only used in mono mode and is not modified */ if (White(piece)) *outline = bwPieceGC; @@ -8270,7 +9151,7 @@ OverlayPiece(piece, clip, outline, dest) ChessSquare piece; GC clip; GC outline; Drawable dest; { int kind; - + if (!useImages) { /* Draw solid rectangle which will be clipped to shape of piece */ XFillRectangle(xDisplay, dest, clip, @@ -8286,16 +9167,16 @@ OverlayPiece(piece, clip, outline, dest) kind = 0; else kind = 2; - XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % 6], + XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, clip, 0, 0, squareSize, squareSize, - 0, 0); + 0, 0); } } /* Animate the movement of a single piece */ -static void +static void BeginAnimation(anim, piece, startColor, start) AnimState *anim; ChessSquare piece; @@ -8303,11 +9184,11 @@ BeginAnimation(anim, piece, startColor, start) XPoint * start; { Pixmap mask; - + /* The old buffer is initialised with the start square (empty) */ BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf); anim->prevFrame = *start; - + /* The piece will be drawn using its own bitmap as a matte */ SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask); XSetClipMask(xDisplay, anim->pieceGC, mask); @@ -8323,12 +9204,12 @@ AnimationFrame(anim, frame, piece) XRectangle overlap; XPoint pt; int count, i; - + /* Save what we are about to draw into the new buffer */ XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC, frame->x, frame->y, squareSize, squareSize, 0, 0); - + /* Erase bits of the previous frame */ if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) { /* Where the new frame overlapped the previous, @@ -8357,7 +9238,7 @@ AnimationFrame(anim, frame, piece) 0, 0, squareSize, squareSize, 0, 0); anim->prevFrame = *frame; - + /* Draw piece over original screen contents, not current, and copy entire rect. Wipes out overlapping piece images. */ OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf); @@ -8430,6 +9311,10 @@ AnimateMove(board, fromX, fromY, toX, toY) if (!appData.animate || appData.blindfold) return; + if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing || + board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing) + return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square + if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return; piece = board[fromY][fromX]; if (piece >= EmptySquare) return; @@ -8441,10 +9326,9 @@ AnimateMove(board, fromX, fromY, toX, toY) #endif if (appData.debugMode) { - printf(hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") : - _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"), - piece, fromX, fromY, toX, toY); - } + fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") : + _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"), + piece, fromX, fromY, toX, toY); } ScreenSquare(fromX, fromY, &start, &startColor); ScreenSquare(toX, toY, &finish, &endColor); @@ -8462,14 +9346,14 @@ AnimateMove(board, fromX, fromY, toX, toY) mid.x = start.x + (finish.x - start.x) / 2; mid.y = start.y + (finish.y - start.y) / 2; } - + /* Don't use as many frames for very short moves */ if (abs(toY - fromY) + abs(toX - fromX) <= 2) Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames); else Tween(&start, &mid, &finish, kFactor, frames, &nFrames); FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames); - + /* Be sure end square is redrawn */ damage[toY][toX] = True; } @@ -8484,7 +9368,7 @@ DragPieceBegin(x, y) /* Are we animating? */ if (!appData.animateDragging || appData.blindfold) return; - + /* Figure out which square we start in and the mouse position relative to top left corner. */ BoardSquare(x, y, &boardX, &boardY); @@ -8515,6 +9399,11 @@ DragPieceBegin(x, y) /* Mark this square as needing to be redrawn. Note that we don't remove the piece though, since logically (ie as seen by opponent) the move hasn't been made yet. */ + if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 || + boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1) + XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC, + corner.x, corner.y, squareSize, squareSize, + 0, 0); // [HGM] zh: unstack in stead of grab damage[boardY][boardX] = True; } else { player.dragActive = False; @@ -8530,7 +9419,7 @@ DragPieceMove(x, y) /* Are we animating? */ if (!appData.animateDragging || appData.blindfold) return; - + /* Sanity check */ if (! player.dragActive) return; @@ -8558,7 +9447,7 @@ DragPieceEnd(x, y) /* Are we animating? */ if (!appData.animateDragging || appData.blindfold) return; - + /* Sanity check */ if (! player.dragActive) return; @@ -8595,3 +9484,10 @@ DrawDragPiece () damage[player.startBoardY][player.startBoardX] = TRUE; } +void +SetProgramStats( FrontEndProgramStats * stats ) +{ + // [HR] TODO + // [HGM] done, but perhaps backend should call this directly? + EngineOutputUpdate( stats ); +}