X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=xboard.c;h=7a8a7ac7a0f360e1247c2261e7916939c1481e05;hb=b382d988c6f886f3a49483df9e3e36de0b6b0824;hp=b99438e1660ae8211908a5b470b18a65a47159bd;hpb=06d3d751525f40869ef6dfd96e33c590008123c2;p=xboard.git diff --git a/xboard.c b/xboard.c index b99438e..7a8a7ac 100644 --- a/xboard.c +++ b/xboard.c @@ -2,10 +2,10 @@ * xboard.c -- X front end for XBoard * * Copyright 1991 by Digital Equipment Corporation, Maynard, - * Massachusetts. + * Massachusetts. * * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006, - * 2007, 2008, 2009 Free Software Foundation, Inc. + * 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. * * The following terms apply to Digital Equipment Corporation's copyright * interest in XBoard: @@ -49,6 +49,8 @@ *------------------------------------------------------------------------ ** See the file ChangeLog for a revision history. */ +#define HIGHDRAG 1 + #include "config.h" #include @@ -58,6 +60,7 @@ #include #include #include +#include #if !OMIT_SOCKETS # if HAVE_SYS_SOCKET_H @@ -189,6 +192,7 @@ extern char *getenv(); #include "frontend.h" #include "backend.h" +#include "backendz.h" #include "moves.h" #include "xboard.h" #include "childio.h" @@ -200,7 +204,9 @@ extern char *getenv(); // must be moved to xengineoutput.h void EngineOutputProc P((Widget w, XEvent *event, - String *prms, Cardinal *nprms)); + String *prms, Cardinal *nprms)); +void EvalGraphProc P((Widget w, XEvent *event, + String *prms, Cardinal *nprms)); #ifdef __EMX__ @@ -220,21 +226,26 @@ void EngineOutputProc P((Widget w, XEvent *event, typedef struct { String string; + String ref; XtActionProc proc; } MenuItem; typedef struct { String name; + String ref; MenuItem *mi; } Menu; int main P((int argc, char **argv)); +FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed, + char *init_path, char *mode, int (*show_entry)(), char **name_return)); RETSIGTYPE CmailSigHandler P((int sig)); RETSIGTYPE IntSigHandler P((int sig)); RETSIGTYPE TermSizeSigHandler P((int sig)); void CreateGCs P((void)); void CreateXIMPieces P((void)); void CreateXPMPieces P((void)); +void CreateXPMBoard P((char *s, int n)); void CreatePieces P((void)); void CreatePieceMenus P((void)); Widget CreateMenuBar P((Menu *mb)); @@ -254,6 +265,12 @@ void HandleUserMove P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); void AnimateUserMove P((Widget w, XEvent * event, String * params, Cardinal * nParams)); +void HandlePV P((Widget w, XEvent * event, + String * params, Cardinal * nParams)); +void SelectPV P((Widget w, XEvent * event, + String * params, Cardinal * nParams)); +void StopPV P((Widget w, XEvent * event, + String * params, Cardinal * nParams)); void WhiteClock P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); void BlackClock P((Widget w, XEvent *event, @@ -262,6 +279,8 @@ void DrawPositionProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); void XDrawPosition P((Widget w, /*Boolean*/int repaint, Board board)); +void CommentClick P((Widget w, XEvent * event, + String * params, Cardinal * nParams)); void CommentPopUp P((char *title, char *label)); void CommentPopDown P((void)); void CommentCallback P((Widget w, XtPointer client_data, @@ -349,15 +368,19 @@ 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 UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); +void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); void StopObservingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); void StopExaminingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); +void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); +void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); void TruncateGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); void RetractMoveProc P((Widget w, XEvent *event, String *prms, @@ -387,10 +410,11 @@ void HighlightDraggingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); +void HighlightArrowProc P((Widget w, XEvent *event, String *prms, + Cardinal *nprms)); void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); -void OldSaveStyleProc P((Widget w, XEvent *event, String *prms, - Cardinal *nprms)); +void OneClickProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); void PonderNextMoveProc P((Widget w, XEvent *event, String *prms, @@ -438,6 +462,8 @@ 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 GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); +void GameListOptionsPopDown P(()); void ShufflePopDown P(()); void EnginePopDown P(()); void UciPopDown P(()); @@ -446,6 +472,10 @@ void NewVariantPopDown P(()); void SettingsPopDown P(()); void update_ics_width P(()); int get_term_width P(()); +int CopyMemoProc P(()); +void DrawArrowHighlight P((int fromX, int fromY, int toX,int toY)); +Boolean IsDrawArrowEnabled P(()); + /* * XBoard depends on Xt R4 or higher */ @@ -467,6 +497,8 @@ Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget, menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell, ICSInputShell, fileNameShell, askQuestionShell; Widget historyShell, evalGraphShell, gameListShell; +int hOffset; // [HGM] dual +XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2]; XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2]; XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6]; Font clockFontID, coordFontID, countFontID; @@ -520,7 +552,8 @@ 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; +Pixmap xpmBoardBitmap[2]; +int useImages, useImageSqs, useTexture, textureW[2], textureH[2]; 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 */ @@ -564,185 +597,205 @@ static Pixmap xpmMask[BlackKing + 1]; SizeDefaults sizeDefaults[] = SIZE_DEFAULTS; MenuItem fileMenu[] = { - {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}, - {N_("Load Previous Game"), LoadPrevGameProc}, - {N_("Reload Same Game"), ReloadGameProc}, - {N_("Save Game"), SaveGameProc}, - {"----", NothingProc}, - {N_("Copy Game"), CopyGameProc}, - {N_("Paste Game"), PasteGameProc}, - {"----", NothingProc}, - {N_("Load Position"), LoadPositionProc}, - {N_("Load Next Position"), LoadNextPositionProc}, - {N_("Load Previous Position"), LoadPrevPositionProc}, - {N_("Reload Same Position"), ReloadPositionProc}, - {N_("Save Position"), SavePositionProc}, - {"----", NothingProc}, - {N_("Copy Position"), CopyPositionProc}, - {N_("Paste Position"), PastePositionProc}, - {"----", NothingProc}, - {N_("Mail Move"), MailMoveProc}, - {N_("Reload CMail Message"), ReloadCmailMsgProc}, - {"----", NothingProc}, - {N_("Exit"), QuitProc}, - {NULL, NULL} + {N_("New Game Ctrl+N"), "New Game", ResetProc}, + {N_("New Shuffle Game ..."), "New Shuffle Game", ShuffleMenuProc}, + {N_("New Variant ... Alt+Shift+V"), "New Variant", NewVariantProc}, // [HGM] variant: not functional yet + {"----", NULL, NothingProc}, + {N_("Load Game Ctrl+O"), "Load Game", LoadGameProc}, + {N_("Load Position Ctrl+Shift+O"), "Load Position", LoadPositionProc}, +// {N_("Load Next Game"), "Load Next Game", LoadNextGameProc}, +// {N_("Load Previous Game"), "Load Previous Game", LoadPrevGameProc}, +// {N_("Reload Same Game"), "Reload Same Game", ReloadGameProc}, + {N_("Next Position Shift+PgDn"), "Load Next Position", LoadNextPositionProc}, + {N_("Prev Position Shift+PgUp"), "Load Previous Position", LoadPrevPositionProc}, + {"----", NULL, NothingProc}, +// {N_("Reload Same Position"), "Reload Same Position", ReloadPositionProc}, + {N_("Save Game Ctrl+S"), "Save Game", SaveGameProc}, + {N_("Save Position Ctrl+Shift+S"), "Save Position", SavePositionProc}, + {"----", NULL, NothingProc}, + {N_("Mail Move"), "Mail Move", MailMoveProc}, + {N_("Reload CMail Message"), "Reload CMail Message", ReloadCmailMsgProc}, + {"----", NULL, NothingProc}, + {N_("Quit Ctr+Q"), "Exit", QuitProc}, + {NULL, NULL, NULL} +}; + +MenuItem editMenu[] = { + {N_("Copy Game Ctrl+C"), "Copy Game", CopyGameProc}, + {N_("Copy Position Ctrl+Shift+C"), "Copy Position", CopyPositionProc}, + {"----", NULL, NothingProc}, + {N_("Paste Game Ctrl+V"), "Paste Game", PasteGameProc}, + {N_("Paste Position Ctrl+Shift+V"), "Paste Position", PastePositionProc}, + {"----", NULL, NothingProc}, + {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc}, + {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc}, + {N_("Edit Tags"), "Edit Tags", EditTagsProc}, + {N_("Edit Comment"), "Edit Comment", EditCommentProc}, + {"----", NULL, NothingProc}, + {N_("Revert Home"), "Revert", RevertProc}, + {N_("Annotate"), "Annotate", AnnotateProc}, + {N_("Truncate Game End"), "Truncate Game", TruncateGameProc}, + {"----", NULL, NothingProc}, + {N_("Backward Alt+Left"), "Backward", BackwardProc}, + {N_("Forward Alt+Right"), "Forward", ForwardProc}, + {N_("Back to Start Alt+Home"), "Back to Start", ToStartProc}, + {N_("Forward to End Alt+End"), "Forward to End", ToEndProc}, + {NULL, NULL, NULL} +}; + +MenuItem viewMenu[] = { + {N_("Flip View F2"), "Flip View", FlipViewProc}, + {"----", NULL, NothingProc}, + {N_("Engine Output Alt+Shift+O"), "Show Engine Output", EngineOutputProc}, + {N_("Move History Alt+Shift+H"), "Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code + {N_("Evaluation Graph Alt+Shift+E"), "Show Evaluation Graph", EvalGraphProc}, + {N_("Game List Alt+Shift+G"), "Show Game List", ShowGameListProc}, + {"----", NULL, NothingProc}, + {N_("Tags"), "Show Tags", EditTagsProc}, + {N_("Comments"), "Show Comments", EditCommentProc}, + {N_("ICS Input Box"), "ICS Input Box", IcsInputBoxProc}, + {NULL, NULL, NULL} }; MenuItem modeMenu[] = { - {N_("Machine White"), MachineWhiteProc}, - {N_("Machine Black"), MachineBlackProc}, - {N_("Two Machines"), TwoMachinesProc}, - {N_("Analysis Mode"), AnalyzeModeProc}, - {N_("Analyze File"), AnalyzeFileProc }, - {N_("ICS Client"), IcsClientProc}, - {N_("Edit Game"), EditGameProc}, - {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}, - {"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}, - {N_("Pause"), PauseProc}, - {NULL, NULL} + {N_("Machine White Ctrl+W"), "Machine White", MachineWhiteProc}, + {N_("Machine Black Ctrl+B"), "Machine Black", MachineBlackProc}, + {N_("Two Machines Ctrl+T"), "Two Machines", TwoMachinesProc}, + {N_("Analysis Mode Ctrl+A"), "Analysis Mode", AnalyzeModeProc}, + {N_("Analyze File Ctrl+F"), "Analyze File", AnalyzeFileProc }, + {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc}, + {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc}, + {N_("Training"), "Training", TrainingProc}, + {N_("ICS Client"), "ICS Client", IcsClientProc}, + {"----", NULL, NothingProc}, + {N_("Pause Pause"), "Pause", PauseProc}, + {NULL, NULL, NULL} }; MenuItem actionMenu[] = { - {N_("Accept"), AcceptProc}, - {N_("Decline"), DeclineProc}, - {N_("Rematch"), RematchProc}, - {"----", NothingProc}, - {N_("Call Flag"), CallFlagProc}, - {N_("Draw"), DrawProc}, - {N_("Adjourn"), AdjournProc}, - {N_("Abort"), AbortProc}, - {N_("Resign"), ResignProc}, - {"----", 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} + {N_("Accept F3"), "Accept", AcceptProc}, + {N_("Decline F4"), "Decline", DeclineProc}, + {N_("Rematch F12"), "Rematch", RematchProc}, + {"----", NULL, NothingProc}, + {N_("Call Flag F5"), "Call Flag", CallFlagProc}, + {N_("Draw F6"), "Draw", DrawProc}, + {N_("Adjourn F7"), "Adjourn", AdjournProc}, + {N_("Abort F8"),"Abort", AbortProc}, + {N_("Resign F9"), "Resign", ResignProc}, + {"----", NULL, NothingProc}, + {N_("Stop Observing F10"), "Stop Observing", StopObservingProc}, + {N_("Stop Examining F11"), "Stop Examining", StopExaminingProc}, + {N_("Upload to Examine"), "Upload to Examine", UploadProc}, + {"----", NULL, NothingProc}, + {N_("Adjudicate to White"), "Adjudicate to White", AdjuWhiteProc}, + {N_("Adjudicate to Black"), "Adjudicate to Black", AdjuBlackProc}, + {N_("Adjudicate Draw"), "Adjudicate Draw", AdjuDrawProc}, + {NULL, NULL, NULL} }; -MenuItem stepMenu[] = { - {N_("Backward"), BackwardProc}, - {N_("Forward"), ForwardProc}, - {N_("Back to Start"), ToStartProc}, - {N_("Forward to End"), ToEndProc}, - {N_("Revert"), RevertProc}, - {N_("Truncate Game"), TruncateGameProc}, - {"----", NothingProc}, - {N_("Move Now"), MoveNowProc}, - {N_("Retract Move"), RetractMoveProc}, - {NULL, NULL} +MenuItem engineMenu[] = { + {N_("Engine #1 Settings ..."), "Engine #1 Settings", FirstSettingsProc}, + {N_("Engine #2 Settings ..."), "Engine #2 Settings", SecondSettingsProc}, + {"----", NULL, NothingProc}, + {N_("Hint"), "Hint", HintProc}, + {N_("Book"), "Book", BookProc}, + {"----", NULL, NothingProc}, + {N_("Move Now Ctrl+M"), "Move Now", MoveNowProc}, + {N_("Retract Move Ctrl+X"), "Retract Move", RetractMoveProc}, + {NULL, 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}, - {N_("Auto Comment"), AutocommProc}, - {N_("Auto Flag"), AutoflagProc}, - {N_("Auto Flip View"), AutoflipProc}, - {N_("Auto Observe"), AutobsProc}, - {N_("Auto Raise Board"), AutoraiseProc}, - {N_("Auto Save"), AutosaveProc}, - {N_("Blindfold"), BlindfoldProc}, - {N_("Flash Moves"), FlashMovesProc}, - {N_("Get Move List"), GetMoveListProc}, + {N_("Time Control ... Alt+Shift+T"), "Time Control", TimeControlProc}, + {N_("Common Engine ... Alt+Shift+U"), "Common Engine", UciMenuProc}, + {N_("Adjudications ... Alt+Shift+J"), "Adjudications", EngineMenuProc}, + {N_("Game List ..."), "Game List", GameListOptionsPopUp}, + {"----", NULL, NothingProc}, + {N_("Always Queen Ctrl+Shift+Q"), "Always Queen", AlwaysQueenProc}, + {N_("Animate Dragging"), "Animate Dragging", AnimateDraggingProc}, + {N_("Animate Moving Ctrl+Shift+A"), "Animate Moving", AnimateMovingProc}, + {N_("Auto Comment"), "Auto Comment", AutocommProc}, + {N_("Auto Flag Ctrl+Shift+F"), "Auto Flag", AutoflagProc}, + {N_("Auto Flip View"), "Auto Flip View", AutoflipProc}, + {N_("Auto Observe"), "Auto Observe", AutobsProc}, + {N_("Auto Raise Board"), "Auto Raise Board", AutoraiseProc}, + {N_("Auto Save"), "Auto Save", AutosaveProc}, + {N_("Blindfold"), "Blindfold", BlindfoldProc}, + {N_("Flash Moves"), "Flash Moves", FlashMovesProc}, + {N_("Get Move List"), "Get Move List", GetMoveListProc}, #if HIGHDRAG - {N_("Highlight Dragging"), HighlightDraggingProc}, + {N_("Highlight Dragging"), "Highlight Dragging", HighlightDraggingProc}, #endif - {N_("Highlight Last Move"), HighlightLastMoveProc}, - {N_("Move Sound"), MoveSoundProc}, - {N_("ICS Alarm"), IcsAlarmProc}, - {N_("Old Save Style"), OldSaveStyleProc}, - {N_("Periodic Updates"), PeriodicUpdatesProc}, - {N_("Ponder Next Move"), PonderNextMoveProc}, - {N_("Popup Exit Message"), PopupExitMessageProc}, - {N_("Popup Move Errors"), PopupMoveErrorsProc}, - {N_("Premove"), PremoveProc}, - {N_("Quiet Play"), QuietPlayProc}, - {N_("Show Coords"), ShowCoordsProc}, - {N_("Hide Thinking"), HideThinkingProc}, - {N_("Test Legality"), TestLegalityProc}, - {"----", NothingProc}, - {N_("Save Settings Now"), SaveSettingsProc}, - {N_("Save Settings on Exit"), SaveOnExitProc}, - {NULL, NULL} + {N_("Highlight Last Move"), "Highlight Last Move", HighlightLastMoveProc}, + {N_("Highlight With Arrow"), "Arrow", HighlightArrowProc}, + {N_("Move Sound"), "Move Sound", MoveSoundProc}, + {N_("ICS Alarm"), "ICS Alarm", IcsAlarmProc}, + {N_("One-Click Moving"), "OneClick", OneClickProc}, + {N_("Periodic Updates"), "Periodic Updates", PeriodicUpdatesProc}, + {N_("Ponder Next Move Ctrl+Shift+P"), "Ponder Next Move", PonderNextMoveProc}, + {N_("Popup Exit Message"), "Popup Exit Message", PopupExitMessageProc}, + {N_("Popup Move Errors"), "Popup Move Errors", PopupMoveErrorsProc}, + {N_("Premove"), "Premove", PremoveProc}, + {N_("Quiet Play"), "Quiet Play", QuietPlayProc}, + {N_("Show Coords"), "Show Coords", ShowCoordsProc}, + {N_("Hide Thinking Ctrl+Shift+H"), "Hide Thinking", HideThinkingProc}, + {N_("Test Legality Ctrl+Shift+L"), "Test Legality", TestLegalityProc}, + {"----", NULL, NothingProc}, + {N_("Save Settings Now"), "Save Settings Now", SaveSettingsProc}, + {N_("Save Settings on Exit"), "Save Settings on Exit", SaveOnExitProc}, + {NULL, NULL, NULL} }; MenuItem helpMenu[] = { - {N_("Info XBoard"), InfoProc}, - {N_("Man XBoard"), ManProc}, - {"----", NothingProc}, - {N_("Hint"), HintProc}, - {N_("Book"), BookProc}, - {"----", NothingProc}, - {N_("About XBoard"), AboutProc}, - {NULL, NULL} + {N_("Info XBoard"), "Info XBoard", InfoProc}, + {N_("Man XBoard F1"), "Man XBoard", ManProc}, + {"----", NULL, NothingProc}, + {N_("About XBoard"), "About XBoard", AboutProc}, + {NULL, NULL, NULL} }; Menu menuBar[] = { - {N_("File"), fileMenu}, - {N_("Mode"), modeMenu}, - {N_("Action"), actionMenu}, - {N_("Step"), stepMenu}, - {N_("Options"), optionsMenu}, - {N_("Help"), helpMenu}, - {NULL, NULL} + {N_("File"), "File", fileMenu}, + {N_("Edit"), "Edit", editMenu}, + {N_("View"), "View", viewMenu}, + {N_("Mode"), "Mode", modeMenu}, + {N_("Action"), "Action", actionMenu}, + {N_("Engine"), "Engine", engineMenu}, + {N_("Options"), "Options", optionsMenu}, + {N_("Help"), "Help", helpMenu}, + {NULL, NULL, NULL} }; -#define PAUSE_BUTTON N_("P") +#define PAUSE_BUTTON "P" MenuItem buttonBar[] = { - {"<<", ToStartProc}, - {"<", BackwardProc}, - {PAUSE_BUTTON, PauseProc}, - {">", ForwardProc}, - {">>", ToEndProc}, - {NULL, NULL} + {"<<", "<<", ToStartProc}, + {"<", "<", BackwardProc}, + {PAUSE_BUTTON, PAUSE_BUTTON, PauseProc}, + {">", ">", ForwardProc}, + {">>", ">>", ToEndProc}, + {NULL, NULL, NULL} }; #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_("Elephant"), N_("Cannon"), - N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"), + 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_("Elephant"), N_("Cannon"), - N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"), + 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, WhiteAlfil, - WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0, + WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0, PromotePiece, DemotePiece, EmptySquare, ClearBoard }, { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop, BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil, - BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0, + BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0, PromotePiece, DemotePiece, EmptySquare, ClearBoard }, }; @@ -829,6 +882,9 @@ XtActionsRec boardActions[] = { { "DrawPosition", DrawPositionProc }, { "HandleUserMove", HandleUserMove }, { "AnimateUserMove", AnimateUserMove }, + { "HandlePV", HandlePV }, + { "SelectPV", SelectPV }, + { "StopPV", StopPV }, { "FileNameAction", FileNameAction }, { "AskQuestionProc", AskQuestionProc }, { "AskQuestionReplyAction", AskQuestionReplyAction }, @@ -837,10 +893,12 @@ XtActionsRec boardActions[] = { { "BlackClock", BlackClock }, { "Iconify", Iconify }, { "ResetProc", ResetProc }, + { "NewVariantProc", NewVariantProc }, { "LoadGameProc", LoadGameProc }, { "LoadNextGameProc", LoadNextGameProc }, { "LoadPrevGameProc", LoadPrevGameProc }, { "LoadSelectedProc", LoadSelectedProc }, + { "SetFilterProc", SetFilterProc }, { "ReloadGameProc", ReloadGameProc }, { "LoadPositionProc", LoadPositionProc }, { "LoadNextPositionProc", LoadNextPositionProc }, @@ -865,6 +923,7 @@ XtActionsRec boardActions[] = { { "EditPositionProc", EditPositionProc }, { "TrainingProc", EditPositionProc }, { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window + { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window { "ShowGameListProc", ShowGameListProc }, { "ShowMoveListProc", HistoryShowProc}, { "EditTagsProc", EditCommentProc }, @@ -884,16 +943,23 @@ XtActionsRec boardActions[] = { { "AdjuBlackProc", AdjuBlackProc }, { "AdjuDrawProc", AdjuDrawProc }, { "EnterKeyProc", EnterKeyProc }, + { "UpKeyProc", UpKeyProc }, + { "DownKeyProc", DownKeyProc }, { "StopObservingProc", StopObservingProc }, { "StopExaminingProc", StopExaminingProc }, + { "UploadProc", UploadProc }, { "BackwardProc", BackwardProc }, { "ForwardProc", ForwardProc }, { "ToStartProc", ToStartProc }, { "ToEndProc", ToEndProc }, { "RevertProc", RevertProc }, + { "AnnotateProc", AnnotateProc }, { "TruncateGameProc", TruncateGameProc }, { "MoveNowProc", MoveNowProc }, { "RetractMoveProc", RetractMoveProc }, + { "EngineMenuProc", (XtActionProc) EngineMenuProc }, + { "UciMenuProc", (XtActionProc) UciMenuProc }, + { "TimeControlProc", (XtActionProc) TimeControlProc }, { "AlwaysQueenProc", AlwaysQueenProc }, { "AnimateDraggingProc", AnimateDraggingProc }, { "AnimateMovingProc", AnimateMovingProc }, @@ -912,7 +978,6 @@ XtActionsRec boardActions[] = { { "HighlightLastMoveProc", HighlightLastMoveProc }, { "IcsAlarmProc", IcsAlarmProc }, { "MoveSoundProc", MoveSoundProc }, - { "OldSaveStyleProc", OldSaveStyleProc }, { "PeriodicUpdatesProc", PeriodicUpdatesProc }, { "PonderNextMoveProc", PonderNextMoveProc }, { "PopupExitMessageProc", PopupExitMessageProc }, @@ -933,6 +998,7 @@ XtActionsRec boardActions[] = { { "AboutProc", AboutProc }, { "DebugProc", DebugProc }, { "NothingProc", NothingProc }, + { "CommentClick", (XtActionProc) CommentClick }, { "CommentPopDown", (XtActionProc) CommentPopDown }, { "EditCommentPopDown", (XtActionProc) EditCommentPopDown }, { "TagsPopDown", (XtActionProc) TagsPopDown }, @@ -941,47 +1007,93 @@ XtActionsRec boardActions[] = { { "FileNamePopDown", (XtActionProc) FileNamePopDown }, { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown }, { "GameListPopDown", (XtActionProc) GameListPopDown }, + { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown }, { "PromotionPopDown", (XtActionProc) PromotionPopDown }, { "HistoryPopDown", (XtActionProc) HistoryPopDown }, { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown }, + { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown }, { "ShufflePopDown", (XtActionProc) ShufflePopDown }, { "EnginePopDown", (XtActionProc) EnginePopDown }, { "UciPopDown", (XtActionProc) UciPopDown }, { "TimeControlPopDown", (XtActionProc) TimeControlPopDown }, { "NewVariantPopDown", (XtActionProc) NewVariantPopDown }, { "SettingsPopDown", (XtActionProc) SettingsPopDown }, + { "CopyMemoProc", (XtActionProc) CopyMemoProc }, }; char globalTranslations[] = - ":R: ResignProc() \n \ - :r: ResetProc() \n \ - :g: LoadGameProc() \n \ - :N: LoadNextGameProc() \n \ - :P: LoadPrevGameProc() \n \ - :Q: QuitProc() \n \ - :F: ToEndProc() \n \ - :f: ForwardProc() \n \ - :B: ToStartProc() \n \ - :b: BackwardProc() \n \ - :p: PauseProc() \n \ - :d: DrawProc() \n \ - :t: CallFlagProc() \n \ - :i: Iconify() \n \ - :c: Iconify() \n \ - :v: FlipViewProc() \n \ - Control_L: BackwardProc() \n \ - Control_L: ForwardProc() \n \ - Control_R: BackwardProc() \n \ - Control_R: ForwardProc() \n \ + ":F9: ResignProc() \n \ + :Ctrln: ResetProc() \n \ + :MetaV: NewVariantProc() \n \ + :Ctrlo: LoadGameProc() \n \ + :MetaNext: LoadNextGameProc() \n \ + :MetaPrior: LoadPrevGameProc() \n \ + :Ctrls: SaveGameProc() \n \ + :Ctrlc: CopyGameProc() \n \ + :Ctrlv: PasteGameProc() \n \ + :CtrlO: LoadPositionProc() \n \ + :ShiftNext: LoadNextPositionProc() \n \ + :ShiftPrior: LoadPrevPositionProc() \n \ + :CtrlS: SavePositionProc() \n \ + :CtrlC: CopyPositionProc() \n \ + :CtrlV: PastePositionProc() \n \ + :Ctrlq: QuitProc() \n \ + :Ctrlw: MachineWhiteProc() \n \ + :Ctrlb: MachineBlackProc() \n \ + :Ctrlt: TwoMachinesProc() \n \ + :Ctrla: AnalysisModeProc() \n \ + :Ctrlf: AnalyzeFileProc() \n \ + :Ctrle: EditGameProc() \n \ + :CtrlE: EditPositionProc() \n \ + :MetaO: EngineOutputProc() \n \ + :MetaE: EvalGraphProc() \n \ + :MetaG: ShowGameListProc() \n \ + :MetaH: ShowMoveListProc() \n \ + :Pause: PauseProc() \n \ + :F3: AcceptProc() \n \ + :F4: DeclineProc() \n \ + :F12: RematchProc() \n \ + :F5: CallFlagProc() \n \ + :F6: DrawProc() \n \ + :F7: AdjournProc() \n \ + :F8: AbortProc() \n \ + :F10: StopObservingProc() \n \ + :F11: StopExaminingProc() \n \ + :Meta CtrlF12: DebugProc() \n \ + :MetaEnd: ToEndProc() \n \ + :MetaRight: ForwardProc() \n \ + :MetaHome: ToStartProc() \n \ + :MetaLeft: BackwardProc() \n \ + :Home: RevertProc() \n \ + :End: TruncateGameProc() \n \ + :Ctrlm: MoveNowProc() \n \ + :Ctrlx: RetractMoveProc() \n \ + :MetaJ: EngineMenuProc() \n \ + :MetaU: UciMenuProc() \n \ + :MetaT: TimeControlProc() \n \ + :CtrlQ: AlwaysQueenProc() \n \ + :CtrlF: AutoflagProc() \n \ + :CtrlA: AnimateMovingProc() \n \ + :CtrlP: PonderNextMoveProc() \n \ + :CtrlL: TestLegalityProc() \n \ + :CtrlH: HideThinkingProc() \n \ + :-: Iconify() \n \ + :F1: ManProc() \n \ + :F2: FlipViewProc() \n \ + .: BackwardProc() \n \ + .: ForwardProc() \n \ Shift1: AskQuestionProc(\"Direct command\",\ \"Send to chess program:\",,1) \n \ Shift2: AskQuestionProc(\"Direct command\",\ \"Send to second chess program:\",,2) \n"; char boardTranslations[] = - ": HandleUserMove() \n \ - : HandleUserMove() \n \ + ": HandleUserMove(0) \n \ + Shift: HandleUserMove(1) \n \ + : HandleUserMove(0) \n \ : AnimateUserMove() \n \ + : HandlePV() \n \ + : PieceMenuPopup(menuB) \n \ Shift: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\ PieceMenuPopup(menuB) \n \ Any: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \ @@ -995,8 +1107,14 @@ char whiteTranslations[] = ": WhiteClock()\n"; char blackTranslations[] = ": BlackClock()\n"; char ICSInputTranslations[] = + "Up: UpKeyProc() \n " + "Down: DownKeyProc() \n " "Return: EnterKeyProc() \n"; +// [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works, +// as the widget is destroyed before the up-click can call extend-end +char commentTranslations[] = ": extend-end() select-start() CommentClick() \n"; + String xboardResources[] = { "*fileName*value.translations: #override\\n Return: FileNameAction()", "*question*value.translations: #override\\n Return: AskQuestionReplyAction()", @@ -1245,12 +1363,13 @@ BoardToTop() #define JAWS_ARGS #define CW_USEDEFAULT (1<<31) #define ICS_TEXT_MENU_SIZE 90 +#define DEBUG_FILE "xboard.debug" #define SetCurrentDirectory chdir #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE) +#define OPTCHAR "-" +#define SEPCHAR " " // these two must some day move to frontend.h, when they are implemented -Boolean EvalGraphIsUp(); -Boolean MoveHistoryIsUp(); Boolean GameListIsUp(); // The option definition and parsing code common to XBoard and WinBoard is collected in this file @@ -1259,28 +1378,46 @@ Boolean GameListIsUp(); // front-end part of option handling // [HGM] This platform-dependent table provides the location for storing the color info +extern char *crWhite, * crBlack; + void * colorVariable[] = { - &appData.whitePieceColor, - &appData.blackPieceColor, + &appData.whitePieceColor, + &appData.blackPieceColor, &appData.lightSquareColor, - &appData.darkSquareColor, + &appData.darkSquareColor, &appData.highlightSquareColor, &appData.premoveHighlightColor, + &appData.lowTimeWarningColor, NULL, NULL, NULL, NULL, NULL, - NULL, - NULL, - NULL, + &crWhite, + &crBlack, NULL }; +// [HGM] font: keep a font for each square size, even non-stndard ones +#define NUM_SIZES 18 +#define MAX_SIZE 130 +Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE]; +char *fontTable[NUM_FONTS][MAX_SIZE]; + void ParseFont(char *name, int number) { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name + int size; + if(sscanf(name, "size%d:", &size)) { + // [HGM] font: font is meant for specific boardSize (likely from settings file); + // defer processing it until we know if it matches our board size + if(size >= 0 && sizeargLoc) { + int i, n = (int)ad->argLoc; + switch(n) { case 0: // CLOCK_FONT name = appData.clockFont; break; @@ -1355,7 +1494,14 @@ SaveFontArg(FILE *f, ArgDescriptor *ad) default: return; } - fprintf(f, "/%s=%s\n", ad->argName, name); + for(i=0; iargName, i, fontTable[n][i]); } void @@ -1366,20 +1512,20 @@ ExportSounds() void SaveAttribsArg(FILE *f, ArgDescriptor *ad) { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though - fprintf(f, "/%s=%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]); + fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]); } void SaveColor(FILE *f, ArgDescriptor *ad) { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already? if(colorVariable[(int)ad->argLoc]) - fprintf(f, "/%s=%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]); + fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]); } void SaveBoardSize(FILE *f, char *name, void *addr) { // wrapper to shield back-end from BoardSize & sizeInfo - fprintf(f, "/%s=%s\n", name, appData.boardSize); + fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize); } void @@ -1398,7 +1544,7 @@ GetActualPlacement(Widget wg, WindowPlacement *wp) int i; if(!wg) return; - + i = 0; XtSetArg(args[i], XtNx, &x); i++; XtSetArg(args[i], XtNy, &y); i++; @@ -1418,15 +1564,12 @@ GetWindowCoords() GetActualPlacement(shellWidget, &wpMain); if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory); + if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph); if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList); if(commentShell) GetActualPlacement(commentShell, &wpComment); else GetActualPlacement(editShell, &wpComment); if(tagsShell) GetActualPlacement(tagsShell, &wpTags); else GetActualPlacement(editTagsShell, &wpTags); -#if 0 - GetActualPlacement(hwndConsole, &wpConsole); - GetActualPlacement(evalGraphDialog, &wpEvalGraph); -#endif } void @@ -1438,7 +1581,9 @@ int MySearchPath(char *installDir, char *name, char *fullname) { // just append installDir and name. Perhaps ExpandPath should be used here? name = ExpandPathName(name); - if(name && name[0] == '/') strcpy(fullname, name); else { + if(name && name[0] == '/') + safeStrCpy(fullname, name, MSG_SIZ ); + else { sprintf(fullname, "%s%c%s", installDir, '/', name); } return 1; @@ -1448,7 +1593,7 @@ int MyGetFullPathName(char *name, char *fullname) { // should use ExpandPath? name = ExpandPathName(name); - strcpy(fullname, name); + safeStrCpy(fullname, name, MSG_SIZ ); return 1; } @@ -1458,12 +1603,6 @@ EnsureOnScreen(int *x, int *y, int minX, int minY) return; } -Boolean -EvalGraphIsUp() -{ - return False; -} - int MainWindowUp() { // [HGM] args: allows testing if main window is realized from back-end @@ -1474,6 +1613,7 @@ void PopUpStartupDialog() { // start menu not implemented in XBoard } + char * ConvertToLine(int argc, char **argv) { @@ -1481,19 +1621,24 @@ ConvertToLine(int argc, char **argv) int i; line[0] = NULLCHAR; - for(i=1; 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; -#endif - setbuf(stdout, NULL); setbuf(stderr, NULL); debugFP = stderr; + if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) { + printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION); + exit(0); + } + programName = strrchr(argv[0], '/'); if (programName == NULL) programName = argv[0]; @@ -1836,7 +1955,14 @@ main(argc, argv) fontPxlSize = szd->fontPxlSize; smallLayout = szd->smallLayout; tinyLayout = szd->tinyLayout; + // [HGM] font: use defaults from settings file if available and not overruled } + if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize]) + appData.clockFont = fontTable[CLOCK_FONT][squareSize]; + if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize]) + appData.font = fontTable[MESSAGE_FONT][squareSize]; + if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize]) + appData.coordFont = fontTable[COORD_FONT][squareSize]; /* Now, using squareSize as a hint, find a good XPM/XIM set size */ if (strlen(appData.pixmapDirectory) > 0) { @@ -1856,6 +1982,7 @@ XBoard square size (hint): %d\n\ fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize); } } + if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap; /* [HR] height treated separately (hacked) */ boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap); @@ -1972,7 +2099,7 @@ 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; @@ -1982,7 +2109,7 @@ XBoard square size (hint): %d\n\ vFrom.addr = (caddr_t) appData.lowTimeWarningColor; vFrom.size = strlen(appData.lowTimeWarningColor); XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo); - if (vTo.addr == NULL) + if (vTo.addr == NULL) appData.monoMode = True; else lowTimeWarningColor = *(Pixel *) vTo.addr; @@ -2339,6 +2466,11 @@ XBoard square size (hint): %d\n\ "menuOptions.Highlight Last Move"), args, 1); } + if (appData.highlightMoveWithArrow) { + XtSetValues(XtNameToWidget(menuBarWidget, + "menuOptions.Arrow"), + args, 1); + } if (appData.icsAlarm) { XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"), args, 1); @@ -2347,9 +2479,9 @@ XBoard square size (hint): %d\n\ XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"), args, 1); } - if (appData.oldSaveStyle) { + if (appData.oneClick) { XtSetValues(XtNameToWidget(menuBarWidget, - "menuOptions.Old Save Style"), args, 1); + "menuOptions.OneClick"), args, 1); } if (appData.periodicUpdates) { XtSetValues(XtNameToWidget(menuBarWidget, @@ -2432,6 +2564,8 @@ XBoard square size (hint): %d\n\ CreatePieces(); } else { CreateXPMPieces(); + CreateXPMBoard(appData.liteBackTextureFile, 1); + CreateXPMBoard(appData.darkBackTextureFile, 0); } #else CreateXIMPieces(); @@ -2455,10 +2589,24 @@ XBoard square size (hint): %d\n\ /* Why is the following needed on some versions of X instead * of a translation? */ - XtAddEventHandler(boardWidget, ExposureMask, False, + XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False, (XtEventHandler) EventProc, NULL); /* end why */ + /* [AS] Restore layout */ + if( wpMoveHistory.visible ) { + HistoryPopUp(); + } + + if( wpEvalGraph.visible ) + { + EvalGraphPopUp(); + }; + + if( wpEngineOutput.visible ) { + EngineOutputPopUp(); + } + InitBackEnd2(); if (errorExitStatus == -1) { @@ -2480,6 +2628,7 @@ XBoard square size (hint): %d\n\ } gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes() InitPosition(TRUE); + XtSetKeyboardFocus(shellWidget, formWidget); XtAppMainLoop(appContext); if (appData.debugMode) fclose(debugFP); // [DM] debug @@ -2541,22 +2690,33 @@ CmailSigHandlerCallBack(isr, closure, message, count, error) void ICSInitScript() { - FILE *f; - char buf[MSG_SIZ]; - char *p; + /* try to open the icsLogon script, either in the location given + * or in the users HOME directory + */ + + FILE *f; + char buf[MSG_SIZ]; + char *homedir; - f = fopen(appData.icsLogon, "r"); - if (f == NULL) { - p = getenv("HOME"); - if (p != NULL) { - strcpy(buf, p); - strcat(buf, "/"); - strcat(buf, appData.icsLogon); - f = fopen(buf, "r"); + f = fopen(appData.icsLogon, "r"); + if (f == NULL) + { + homedir = getenv("HOME"); + if (homedir != NULL) + { + safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) ); + strncat(buf, "/", MSG_SIZ - strlen(buf) - 1); + strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1); + f = fopen(buf, "r"); } } - if (f != NULL) - ProcessICSInitScript(f); + + if (f != NULL) + ProcessICSInitScript(f); + else + printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf); + + return; } void @@ -2579,9 +2739,15 @@ GreyRevert(grey) { Widget w; if (!menuBarWidget) return; - w = XtNameToWidget(menuBarWidget, "menuStep.Revert"); + w = XtNameToWidget(menuBarWidget, "menuEdit.Revert"); + if (w == NULL) { + DisplayError("menuEdit.Revert", 0); + } else { + XtSetSensitive(w, !grey); + } + w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate"); if (w == NULL) { - DisplayError("menuStep.Revert", 0); + DisplayError("menuEdit.Annotate", 0); } else { XtSetSensitive(w, !grey); } @@ -2613,13 +2779,16 @@ Enables icsEnables[] = { { "menuMode.Analyze File", False }, { "menuMode.Two Machines", False }, #ifndef ZIPPY - { "menuHelp.Hint", False }, - { "menuHelp.Book", False }, - { "menuStep.Move Now", False }, + { "menuEngine.Hint", False }, + { "menuEngine.Book", False }, + { "menuEngine.Move Now", False }, { "menuOptions.Periodic Updates", False }, { "menuOptions.Hide Thinking", False }, { "menuOptions.Ponder Next Move", False }, + { "menuEngine.Engine #1 Settings", False }, #endif + { "menuEngine.Engine #2 Settings", False }, + { "menuEdit.Annotate", False }, { NULL, False } }; @@ -2632,11 +2801,14 @@ Enables ncpEnables[] = { { "menuMode.Analyze File", False }, { "menuMode.Two Machines", False }, { "menuMode.ICS Client", False }, - { "menuMode.ICS Input Box", False }, + { "menuView.ICS Input Box", False }, { "Action", False }, - { "menuStep.Revert", False }, - { "menuStep.Move Now", False }, - { "menuStep.Retract Move", False }, + { "menuEdit.Revert", False }, + { "menuEdit.Annotate", False }, + { "menuEngine.Engine #1 Settings", False }, + { "menuEngine.Engine #2 Settings", False }, + { "menuEngine.Move Now", False }, + { "menuEngine.Retract Move", False }, { "menuOptions.Auto Comment", False }, { "menuOptions.Auto Flag", False }, { "menuOptions.Auto Flip View", False }, @@ -2649,21 +2821,23 @@ Enables ncpEnables[] = { { "menuOptions.Hide Thinking", False }, { "menuOptions.Periodic Updates", False }, { "menuOptions.Ponder Next Move", False }, - { "menuHelp.Hint", False }, - { "menuHelp.Book", False }, + { "menuEngine.Hint", False }, + { "menuEngine.Book", False }, { NULL, False } }; Enables gnuEnables[] = { { "menuMode.ICS Client", False }, - { "menuMode.ICS Input Box", False }, + { "menuView.ICS Input Box", False }, { "menuAction.Accept", False }, { "menuAction.Decline", False }, { "menuAction.Rematch", False }, { "menuAction.Adjourn", False }, { "menuAction.Stop Examining", False }, { "menuAction.Stop Observing", False }, - { "menuStep.Revert", False }, + { "menuAction.Upload to Examine", False }, + { "menuEdit.Revert", False }, + { "menuEdit.Annotate", False }, { "menuOptions.Auto Comment", False }, { "menuOptions.Auto Observe", False }, { "menuOptions.Auto Raise Board", False }, @@ -2696,60 +2870,60 @@ Enables cmailEnables[] = { Enables trainingOnEnables[] = { { "menuMode.Edit Comment", False }, { "menuMode.Pause", False }, - { "menuStep.Forward", False }, - { "menuStep.Backward", False }, - { "menuStep.Forward to End", False }, - { "menuStep.Back to Start", False }, - { "menuStep.Move Now", False }, - { "menuStep.Truncate Game", False }, + { "menuEdit.Forward", False }, + { "menuEdit.Backward", False }, + { "menuEdit.Forward to End", False }, + { "menuEdit.Back to Start", False }, + { "menuEngine.Move Now", False }, + { "menuEdit.Truncate Game", False }, { NULL, False } }; Enables trainingOffEnables[] = { { "menuMode.Edit Comment", True }, { "menuMode.Pause", True }, - { "menuStep.Forward", True }, - { "menuStep.Backward", True }, - { "menuStep.Forward to End", True }, - { "menuStep.Back to Start", True }, - { "menuStep.Move Now", True }, - { "menuStep.Truncate Game", True }, + { "menuEdit.Forward", True }, + { "menuEdit.Backward", True }, + { "menuEdit.Forward to End", True }, + { "menuEdit.Back to Start", True }, + { "menuEngine.Move Now", True }, + { "menuEdit.Truncate Game", True }, { NULL, False } }; Enables machineThinkingEnables[] = { { "menuFile.Load Game", False }, - { "menuFile.Load Next Game", False }, - { "menuFile.Load Previous Game", False }, - { "menuFile.Reload Same Game", False }, - { "menuFile.Paste Game", False }, +// { "menuFile.Load Next Game", False }, +// { "menuFile.Load Previous Game", False }, +// { "menuFile.Reload Same Game", False }, + { "menuEdit.Paste Game", False }, { "menuFile.Load Position", False }, - { "menuFile.Load Next Position", False }, - { "menuFile.Load Previous Position", False }, - { "menuFile.Reload Same Position", False }, - { "menuFile.Paste Position", False }, +// { "menuFile.Load Next Position", False }, +// { "menuFile.Load Previous Position", False }, +// { "menuFile.Reload Same Position", False }, + { "menuEdit.Paste Position", False }, { "menuMode.Machine White", False }, { "menuMode.Machine Black", False }, { "menuMode.Two Machines", False }, - { "menuStep.Retract Move", False }, + { "menuEngine.Retract Move", False }, { NULL, False } }; Enables userThinkingEnables[] = { { "menuFile.Load Game", True }, - { "menuFile.Load Next Game", True }, - { "menuFile.Load Previous Game", True }, - { "menuFile.Reload Same Game", True }, - { "menuFile.Paste Game", True }, +// { "menuFile.Load Next Game", True }, +// { "menuFile.Load Previous Game", True }, +// { "menuFile.Reload Same Game", True }, + { "menuEdit.Paste Game", True }, { "menuFile.Load Position", True }, - { "menuFile.Load Next Position", True }, - { "menuFile.Load Previous Position", True }, - { "menuFile.Reload Same Position", True }, - { "menuFile.Paste Position", True }, +// { "menuFile.Load Next Position", True }, +// { "menuFile.Load Previous Position", True }, +// { "menuFile.Reload Same Position", True }, + { "menuEdit.Paste Position", True }, { "menuMode.Machine White", True }, { "menuMode.Machine Black", True }, { "menuMode.Two Machines", True }, - { "menuStep.Retract Move", True }, + { "menuEngine.Retract Move", True }, { NULL, False } }; @@ -2757,7 +2931,7 @@ void SetICSMode() { SetMenuEnables(icsEnables); -#ifdef ZIPPY +#if ZIPPY if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */ XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True); #endif @@ -2824,6 +2998,51 @@ SetMachineThinkingEnables() } } +// [HGM] code borrowed from winboard.c (which should thus go to backend.c!) +#define HISTORY_SIZE 64 +static char *history[HISTORY_SIZE]; +int histIn = 0, histP = 0; + +void +SaveInHistory(char *cmd) +{ + if (history[histIn] != NULL) { + free(history[histIn]); + history[histIn] = NULL; + } + if (*cmd == NULLCHAR) return; + history[histIn] = StrSave(cmd); + histIn = (histIn + 1) % HISTORY_SIZE; + if (history[histIn] != NULL) { + free(history[histIn]); + history[histIn] = NULL; + } + histP = histIn; +} + +char * +PrevInHistory(char *cmd) +{ + int newhp; + if (histP == histIn) { + if (history[histIn] != NULL) free(history[histIn]); + history[histIn] = StrSave(cmd); + } + newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE; + if (newhp == histIn || history[newhp] == NULL) return NULL; + histP = newhp; + return history[histP]; +} + +char * +NextInHistory() +{ + if (histP == histIn) return NULL; + histP = (histP + 1) % HISTORY_SIZE; + return history[histP]; +} +// end of borrowed code + #define Abs(n) ((n)<0 ? -(n) : (n)) /* @@ -2835,7 +3054,8 @@ SetMachineThinkingEnables() * The return value should be freed with XtFree when no * longer needed. */ -char *FindFont(pattern, targetPxlSize) +char * +FindFont(pattern, targetPxlSize) char *pattern; int targetPxlSize; { @@ -2850,7 +3070,7 @@ char *FindFont(pattern, targetPxlSize) XFontStruct **fnt_list; base_fnt_lst = calloc(1, strlen(pattern) + 3); - sprintf(strInt, "%d", targetPxlSize); + snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize); p = strstr(pattern, "--"); strncpy(base_fnt_lst, pattern, p - pattern + 2); strcat(base_fnt_lst, strInt); @@ -2909,8 +3129,8 @@ char *FindFont(pattern, targetPxlSize) while (isdigit(*scalableTail)) scalableTail++; sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail); } else { - p = (char *) XtMalloc(strlen(best) + 1); - strcpy(p, best); + p = (char *) XtMalloc(strlen(best) + 2); + safeStrCpy(p, best, strlen(best)+1 ); } if (appData.debugMode) { fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"), @@ -3200,6 +3420,16 @@ void CreateXIMPieces() } #if HAVE_LIBXPM +void CreateXPMBoard(char *s, int kind) +{ + XpmAttributes attr; + attr.valuemask = 0; + if(s == NULL || *s == 0 || *s == '*') return; + if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) { + useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height; + } +} + void CreateXPMPieces() { int piece, kind, r; @@ -3296,7 +3526,7 @@ void CreateXPMPieces() exit(1); } } - if(piece <= (int) WhiteKing) + if(piece <= (int) WhiteKing) xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece]; } } @@ -3350,12 +3580,12 @@ void CreatePieces() for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) { 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(&pieceBitmap2[kind][piece], buf, NULL, ss, ss); - if(piece <= (int)WhiteKing) - pieceBitmap[kind][piece] = pieceBitmap2[kind][piece]; + snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "", + pieceBitmapNames[piece], + ss, kind == SOLID ? 's' : 'o'); + ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss); + if(piece <= (int)WhiteKing) + pieceBitmap[kind][piece] = pieceBitmap2[kind][piece]; } } @@ -3378,13 +3608,13 @@ void CreatePieces() for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) { 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(&pieceBitmap2[kind][piece], buf, - bib->bits[kind][piece], ss, ss); - if(piece <= (int)WhiteKing) - pieceBitmap[kind][piece] = pieceBitmap2[kind][piece]; + snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "", + pieceBitmapNames[piece], + ss, kind == SOLID ? 's' : 'o'); + ReadBitmap(&pieceBitmap2[kind][piece], buf, + bib->bits[kind][piece], ss, ss); + if(piece <= (int)WhiteKing) + pieceBitmap[kind][piece] = pieceBitmap2[kind][piece]; } } @@ -3405,12 +3635,12 @@ void ReadBitmap(pm, name, bits, wreq, hreq) 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); + safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) ); + strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1); + strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1); + 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: @@ -3500,8 +3730,8 @@ void CreateMenuBarPopup(parent, name, mb) entry = XtCreateManagedWidget(mi->string, smeLineObjectClass, menu, args, j); } else { - XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); - entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass, + XtSetArg(args[j], XtNlabel, XtNewString(mi->string)); + entry = XtCreateManagedWidget(mi->ref, smeBSBObjectClass, menu, args, j+1); XtAddCallback(entry, XtNcallback, (XtCallbackProc) MenuBarSelect, @@ -3527,18 +3757,18 @@ Widget CreateMenuBar(mb) formWidget, args, j); while (mb->name != NULL) { - strcpy(menuName, "menu"); - strcat(menuName, mb->name); + safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) ); + strncat(menuName, mb->ref, MSG_SIZ - strlen(menuName) - 1); j = 0; 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++; + XtSetArg(args[j], XtNlabel, XtNewString(mb->name)); j++; } XtSetArg(args[j], XtNborderWidth, 0); j++; @@ -3686,39 +3916,18 @@ void PieceMenuPopup(w, event, params, num_params) String *params; Cardinal *num_params; { - String whichMenu; - if (event->type != ButtonPress) return; - if (errorUp) ErrorPopDown(); - switch (gameMode) { - case EditPosition: - case IcsExamining: - whichMenu = params[0]; - break; - case IcsPlayingWhite: - case IcsPlayingBlack: - case EditGame: - case MachinePlaysWhite: - case MachinePlaysBlack: - if (appData.testLegality && - gameInfo.variant != VariantBughouse && - gameInfo.variant != VariantCrazyhouse) return; - SetupDropMenu(); - whichMenu = "menuD"; - break; - default: - return; - } - - if (((pmFromX = EventToSquare(event->xbutton.x, BOARD_WIDTH)) < 0) || - ((pmFromY = EventToSquare(event->xbutton.y, BOARD_HEIGHT)) < 0)) { - pmFromX = pmFromY = -1; - return; + String whichMenu; int menuNr; + if (event->type == ButtonRelease) + menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY); + else if (event->type == ButtonPress) + menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY); + switch(menuNr) { + case 0: whichMenu = params[0]; break; + case 1: SetupDropMenu(); whichMenu = "menuD"; break; + case 2: + case -1: if (errorUp) ErrorPopDown(); + default: return; } - if (flipView) - pmFromX = BOARD_WIDTH - 1 - pmFromX; - else - pmFromY = BOARD_HEIGHT - 1 - pmFromY; - XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu)); } @@ -3746,11 +3955,7 @@ void WhiteClock(w, event, prms, nprms) String *prms; Cardinal *nprms; { - if (gameMode == EditPosition || gameMode == IcsExamining) { - SetWhiteToPlayEvent(); - } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) { - CallFlagEvent(); - } + ClockClick(0); } void BlackClock(w, event, prms, nprms) @@ -3759,11 +3964,7 @@ void BlackClock(w, event, prms, nprms) String *prms; Cardinal *nprms; { - if (gameMode == EditPosition || gameMode == IcsExamining) { - SetBlackToPlayEvent(); - } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) { - CallFlagEvent(); - } + ClockClick(1); } @@ -3799,7 +4000,7 @@ static void drawHighlight(file, rank, gc) { int x, y; - if (lineGap == 0 || appData.blindfold) return; + if (lineGap == 0) return; if (flipView) { x = lineGap/2 + ((BOARD_WIDTH-1)-file) * @@ -3826,14 +4027,18 @@ SetHighlights(fromX, fromY, toX, toY) if (hi1X >= 0 && hi1Y >= 0) { drawHighlight(hi1X, hi1Y, lineGC); } + } // [HGM] first erase both, then draw new! + if (hi2X != toX || hi2Y != toY) { + if (hi2X >= 0 && hi2Y >= 0) { + drawHighlight(hi2X, hi2Y, lineGC); + } + } + if (hi1X != fromX || hi1Y != fromY) { if (fromX >= 0 && fromY >= 0) { drawHighlight(fromX, fromY, highlineGC); } } if (hi2X != toX || hi2Y != toY) { - if (hi2X >= 0 && hi2Y >= 0) { - drawHighlight(hi2X, hi2Y, lineGC); - } if (toX >= 0 && toY >= 0) { drawHighlight(toX, toY, highlineGC); } @@ -3883,11 +4088,34 @@ ClearPremoveHighlights() SetPremoveHighlights(-1, -1, -1, -1); } -static void BlankSquare(x, y, color, piece, dest) - int x, y, color; +static int CutOutSquare(x, y, x0, y0, kind) + int x, y, *x0, *y0, kind; +{ + int W = BOARD_WIDTH, H = BOARD_HEIGHT; + int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap); + *x0 = 0; *y0 = 0; + if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0; + if(textureW[kind] < W*squareSize) + *x0 = (textureW[kind] - squareSize) * nx/(W-1); + else + *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W); + if(textureH[kind] < H*squareSize) + *y0 = (textureH[kind] - squareSize) * ny/(H-1); + else + *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H); + return 1; +} + +static void BlankSquare(x, y, color, piece, dest, fac) + int x, y, color, fac; ChessSquare piece; Drawable dest; -{ +{ // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer + int x0, y0; + if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) { + XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0, + squareSize, squareSize, x*fac, y*fac); + } else if (useImages && useImageSqs) { Pixmap pm; switch (color) { @@ -3903,7 +4131,7 @@ static void BlankSquare(x, y, color, piece, dest) break; } XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0, - squareSize, squareSize, x, y); + squareSize, squareSize, x*fac, y*fac); } else { GC gc; switch (color) { @@ -3918,7 +4146,7 @@ static void BlankSquare(x, y, color, piece, dest) gc = jailSquareGC; break; } - XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize); + XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize); } } @@ -4011,7 +4239,7 @@ static void colorDrawPieceImage(piece, square_color, x, y, dest) int square_color, x, y; Drawable dest; { - int kind; + int kind, p = piece; switch (square_color) { case 1: /* light */ @@ -4033,6 +4261,15 @@ static void colorDrawPieceImage(piece, square_color, x, y, dest) } break; } + if(appData.upsideDown && flipView) kind ^= 2; // swap white and black pieces + if(useTexture & square_color+1) { + BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background + XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]); + XSetClipOrigin(xDisplay, wlPieceGC, x, y); + XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y); + XSetClipMask(xDisplay, wlPieceGC, None); + XSetClipOrigin(xDisplay, wlPieceGC, 0, 0); + } else XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y); @@ -4106,13 +4343,15 @@ void DrawSquare(row, column, piece, do_flash) (squareSize + lineGap); } + if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board + square_color = SquareColor(row, column); if ( // [HGM] holdings: blank out area between board and holdings column == BOARD_LEFT-1 || column == BOARD_RGHT || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize) || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) { - BlankSquare(x, y, 2, EmptySquare, xBoardWindow); + BlankSquare(x, y, 2, EmptySquare, xBoardWindow, 1); // [HGM] print piece counts next to holdings string[1] = NULLCHAR; @@ -4144,7 +4383,7 @@ void DrawSquare(row, column, piece, do_flash) } } else { if (piece == EmptySquare || appData.blindfold) { - BlankSquare(x, y, square_color, piece, xBoardWindow); + BlankSquare(x, y, square_color, piece, xBoardWindow, 1); } else { drawfunc = ChooseDrawFunc(); if (do_flash && appData.flashCount > 0) { @@ -4154,7 +4393,7 @@ void DrawSquare(row, column, piece, do_flash) XSync(xDisplay, False); do_flash_delay(flash_delay); - BlankSquare(x, y, square_color, piece, xBoardWindow); + BlankSquare(x, y, square_color, piece, xBoardWindow, 1); XSync(xDisplay, False); do_flash_delay(flash_delay); } @@ -4191,6 +4430,10 @@ void DrawSquare(row, column, piece, do_flash) x + 2, y + font_ascent + 1, string, 1); } } + if(!partnerUp && marker[row][column]) { + XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC, + x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360); + } } @@ -4207,7 +4450,14 @@ void EventProc(widget, unused, event) case Expose: if (event->xexpose.count > 0) return; /* no clipping is done */ XDrawPosition(widget, True, NULL); + if(twoBoards) { // [HGM] dual: draw other board in other orientation + flipView = !flipView; partnerUp = !partnerUp; + XDrawPosition(widget, True, NULL); + flipView = !flipView; partnerUp = !partnerUp; + } break; + case MotionNotify: + if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break; default: return; } @@ -4288,7 +4538,37 @@ static int check_castle_draw(newb, oldb, rrow, rcol) return 0; } -static int damage[BOARD_RANKS][BOARD_FILES]; +// [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph +void DrawSeekAxis( int x, int y, int xTo, int yTo ) +{ + XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo); +} + +void DrawSeekBackground( int left, int top, int right, int bottom ) +{ + XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top); +} + +void DrawSeekText(char *buf, int x, int y) +{ + XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf)); +} + +void DrawSeekDot(int x, int y, int colorNr) +{ + int square = colorNr & 0x80; + GC color; + colorNr &= 0x7F; + color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC; + if(square) + XFillRectangle(xDisplay, xBoardWindow, color, + x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9); + else + XFillArc(xDisplay, xBoardWindow, color, + x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360); +} + +static int damage[2][BOARD_RANKS][BOARD_FILES]; /* * event handler for redrawing the board @@ -4300,18 +4580,21 @@ void XDrawPosition(w, repaint, board) { int i, j, do_flash; static int lastFlipView = 0; - static int lastBoardValid = 0; - static Board lastBoard; + static int lastBoardValid[2] = {0, 0}; + static Board lastBoard[2]; Arg args[16]; int rrow, rcol; + int nr = twoBoards*partnerUp; + + if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up if (board == NULL) { - if (!lastBoardValid) return; - board = lastBoard; + if (!lastBoardValid[nr]) return; + board = lastBoard[nr]; } - if (!lastBoardValid || lastFlipView != flipView) { + if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) { XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None)); - XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"), + XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Flip View"), args, 1); } @@ -4320,19 +4603,20 @@ void XDrawPosition(w, repaint, board) * but this causes a very distracting flicker. */ - if (!repaint && lastBoardValid && lastFlipView == flipView) { + if ( lineGap && IsDrawArrowEnabled()) repaint = True; + if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) { /* If too much changes (begin observing new game, etc.), don't do flashing */ - do_flash = too_many_diffs(board, lastBoard) ? 0 : 1; + do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1; /* Special check for castling so we don't flash both the king and the rook (just flash the king). */ if (do_flash) { - if (check_castle_draw(board, lastBoard, &rrow, &rcol)) { + if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) { /* Draw rook with NO flashing. King will be drawn flashing later */ DrawSquare(rrow, rcol, board[rrow][rcol], 0); - lastBoard[rrow][rcol] = board[rrow][rcol]; + lastBoard[nr][rrow][rcol] = board[rrow][rcol]; } } @@ -4341,32 +4625,34 @@ void XDrawPosition(w, repaint, board) is flashing on its new square */ 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]) { + if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare) + || damage[nr][i][j]) { DrawSquare(i, j, board[i][j], 0); - damage[i][j] = False; + damage[nr][i][j] = False; } /* Second pass -- Draw piece(s) in new position and flash them */ for (i = 0; i < BOARD_HEIGHT; i++) for (j = 0; j < BOARD_WIDTH; j++) - if (board[i][j] != lastBoard[i][j]) { + if (board[i][j] != lastBoard[nr][i][j]) { DrawSquare(i, j, board[i][j], do_flash); } } else { if (lineGap > 0) XDrawSegments(xDisplay, xBoardWindow, lineGC, + twoBoards & partnerUp ? secondSegments : // [HGM] dual 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; + damage[nr][i][j] = False; } } - CopyBoard(lastBoard, board); - lastBoardValid = 1; + CopyBoard(lastBoard[nr], board); + lastBoardValid[nr] = 1; + if(nr == 0) { // [HGM] dual: no highlights on second board yet lastFlipView = flipView; /* Draw highlights */ @@ -4382,7 +4668,8 @@ void XDrawPosition(w, repaint, board) if (hi2X >= 0 && hi2Y >= 0) { drawHighlight(hi2X, hi2Y, highlineGC); } - + DrawArrowHighlight(hi1X, hi1Y, hi2X, hi2Y); + } /* If piece being dragged around board, must redraw that too */ DrawDragPiece(); @@ -4420,6 +4707,7 @@ void HandleUserMove(w, event, prms, nprms) Cardinal *nprms; { if (w != boardWidget || errorExitStatus != -1) return; + if(nprms) shiftKey = !strcmp(prms[0], "1"); if (promotionUp) { if (event->type == ButtonPress) { @@ -4444,6 +4732,12 @@ void AnimateUserMove (Widget w, XEvent * event, DragPieceMove(event->xmotion.x, event->xmotion.y); } +void HandlePV (Widget w, XEvent * event, + String * params, Cardinal * nParams) +{ // [HGM] pv: walk PV + MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap)); +} + Widget CommentCreate(name, text, mutable, callback, lines) char *name, *text; int /*Boolean*/ mutable; @@ -4495,6 +4789,7 @@ Widget CommentCreate(name, text, mutable, callback, lines) XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++; edit = XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j); + XtOverrideTranslations(edit, XtParseTranslationTable(commentTranslations)); if (mutable) { j = 0; @@ -4703,6 +4998,20 @@ Widget MiscCreate(name, text, mutable, callback, lines) static int savedIndex; /* gross that this is global */ +void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams) +{ + String val; + XawTextPosition index, dummy; + Arg arg; + + XawTextGetSelectionPos(w, &index, &dummy); + XtSetArg(arg, XtNstring, &val); + XtGetValues(w, &arg, 1); + ReplaceComment(savedIndex, val); + if(savedIndex != currentMove) ToNrEvent(savedIndex); + LoadVariation( index, val ); // [HGM] also does the actual moving to it, now +} + void EditCommentPopUp(index, title, text) int index; char *title, *text; @@ -4735,7 +5044,9 @@ void EditCommentPopUp(index, title, text) editUp = True; j = 0; XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++; - XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"), + XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"), + args, j); + XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"), args, j); } @@ -4784,7 +5095,9 @@ void EditCommentPopDown() editUp = False; j = 0; XtSetArg(args[j], XtNleftBitmap, None); j++; - XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"), + XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"), + args, j); + XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"), args, j); } @@ -4821,7 +5134,7 @@ void ICSInputBoxPopUp() ICSInputBoxUp = True; j = 0; XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++; - XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"), + XtSetValues(XtNameToWidget(menuBarWidget, "menuView.ICS Input Box"), args, j); } @@ -4836,6 +5149,7 @@ void ICSInputSendText() j = 0; XtSetArg(args[j], XtNstring, &val); j++; XtGetValues(edit, args, j); + SaveInHistory(val); SendMultiLineToICS(val); XtCallActionProc(edit, "select-all", NULL, NULL, 0); XtCallActionProc(edit, "kill-selection", NULL, NULL, 0); @@ -4852,7 +5166,7 @@ void ICSInputBoxPopDown() ICSInputBoxUp = False; j = 0; XtSetArg(args[j], XtNleftBitmap, None); j++; - XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"), + XtSetValues(XtNameToWidget(menuBarWidget, "menuView.ICS Input Box"), args, j); } @@ -4863,6 +5177,7 @@ void CommentPopUp(title, text) int j; Widget edit; + savedIndex = currentMove; // [HGM] vari if (commentShell == NULL) { commentShell = CommentCreate(title, text, False, CommentCallback, 4); @@ -4929,54 +5244,16 @@ void FileNamePopUp(label, def, proc, openMode) FileProc proc; char *openMode; { - Arg args[16]; - Widget popup, layout, dialog, edit; - Window root, child; - 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++; - XtSetArg(args[i], XtNtitle, XtNewString(_("File name prompt"))); i++; - 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++; - XtSetArg(args[i], XtNborderWidth, 0); i++; - dialog = XtCreateManagedWidget("fileName", dialogWidgetClass, - layout, args, i); - - XawDialogAddButton(dialog, _("ok"), FileNameCallback, (XtPointer) dialog); - XawDialogAddButton(dialog, _("cancel"), FileNameCallback, - (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); + { // [HGM] use file-selector dialog stolen from Ghostview + char *name; + int index; // this is not supported yet + FILE *f; + if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ", + def, openMode, NULL, &name)) + (void) (*fileProc)(f, index=0, name); + } } void FileNamePopDown() @@ -5021,7 +5298,7 @@ void FileNameAction(w, event, prms, nprms) name = XawDialogGetValueString(w = XtParent(w)); if ((name != NULL) && (*name != NULLCHAR)) { - strcpy(buf, name); + safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) ); XtPopdown(w = XtParent(XtParent(w))); XtDestroyWidget(w); filenameUp = False; @@ -5084,6 +5361,16 @@ void PromotionPopUp() layout, args, j); if(gameInfo.variant != VariantShogi) { + if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) { + XawDialogAddButton(dialog, _("Warlord"), PromotionCallback, + (XtPointer) dialog); + XawDialogAddButton(dialog, _("General"), PromotionCallback, + (XtPointer) dialog); + XawDialogAddButton(dialog, _("Lieutenant"), PromotionCallback, + (XtPointer) dialog); + XawDialogAddButton(dialog, _("Captain"), PromotionCallback, + (XtPointer) dialog); + } else { XawDialogAddButton(dialog, _("Queen"), PromotionCallback, (XtPointer) dialog); XawDialogAddButton(dialog, _("Rook"), PromotionCallback, @@ -5092,13 +5379,15 @@ void PromotionPopUp() (XtPointer) dialog); XawDialogAddButton(dialog, _("Knight"), PromotionCallback, (XtPointer) dialog); + } if (!appData.testLegality || gameInfo.variant == VariantSuicide || + gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) || gameInfo.variant == VariantGiveaway) { XawDialogAddButton(dialog, _("King"), PromotionCallback, (XtPointer) dialog); } - if(gameInfo.variant == VariantCapablanca || - gameInfo.variant == VariantGothic || + if(gameInfo.variant == VariantCapablanca || + gameInfo.variant == VariantGothic || gameInfo.variant == VariantCapaRandom) { XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback, (XtPointer) dialog); @@ -5536,9 +5825,9 @@ void MailMoveProc(w, event, prms, nprms) } /* this variable is shared between CopyPositionProc and SendPositionSelection */ -static char *selected_fen_position=NULL; +char *selected_fen_position=NULL; -static Boolean +Boolean SendPositionSelection(Widget w, Atom *selection, Atom *target, Atom *type_return, XtPointer *value_return, unsigned long *length_return, int *format_return) @@ -5551,7 +5840,7 @@ SendPositionSelection(Widget w, Atom *selection, Atom *target, * automatically call XtFree on the value returned. So have to * make a copy of it allocated with XtMalloc */ selection_tmp= XtMalloc(strlen(selected_fen_position)+16); - strcpy(selection_tmp, selected_fen_position); + safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 ); *value_return=selection_tmp; *length_return=strlen(selection_tmp); @@ -5590,6 +5879,7 @@ void CopyPositionProc(w, event, prms, nprms) * have a notion of a position that is selected but not copied. * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki */ + if(gameMode == EditPosition) EditPositionDone(TRUE); if (selected_fen_position) free(selected_fen_position); selected_fen_position = (char *)PositionToFEN(currentMove, NULL); if (!selected_fen_position) return; @@ -5625,7 +5915,7 @@ void PastePositionProc(w, event, prms, nprms) String *prms; Cardinal *nprms; { - XtGetSelectionValue(menuBarWidget, + XtGetSelectionValue(menuBarWidget, appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING, /* (XtSelectionCallbackProc) */ PastePositionCB, NULL, /* client_data passed to PastePositionCB */ @@ -5815,7 +6105,7 @@ void AnalyzeModeProc(w, event, prms, nprms) /* [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")); + snprintf(buf, MSG_SIZ, _("You are not observing a game")); DisplayError(buf, 0); /* secure check */ if (appData.icsEngineAnalyze) { @@ -6044,6 +6334,55 @@ void EnterKeyProc(w, event, prms, nprms) ICSInputSendText(); } +void UpKeyProc(w, event, prms, nprms) + Widget w; + XEvent *event; + String *prms; + Cardinal *nprms; +{ // [HGM] input: let up-arrow recall previous line from history + Widget edit; + int j; + Arg args[16]; + String val; + XawTextBlock t; + + if (!ICSInputBoxUp) return; + edit = XtNameToWidget(ICSInputShell, "*form.text"); + j = 0; + XtSetArg(args[j], XtNstring, &val); j++; + XtGetValues(edit, args, j); + val = PrevInHistory(val); + XtCallActionProc(edit, "select-all", NULL, NULL, 0); + XtCallActionProc(edit, "kill-selection", NULL, NULL, 0); + if(val) { + t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit; + XawTextReplace(edit, 0, 0, &t); + XawTextSetInsertionPoint(edit, 9999); + } +} + +void DownKeyProc(w, event, prms, nprms) + Widget w; + XEvent *event; + String *prms; + Cardinal *nprms; +{ // [HGM] input: let down-arrow recall next line from history + Widget edit; + String val; + XawTextBlock t; + + if (!ICSInputBoxUp) return; + edit = XtNameToWidget(ICSInputShell, "*form.text"); + val = NextInHistory(); + XtCallActionProc(edit, "select-all", NULL, NULL, 0); + XtCallActionProc(edit, "kill-selection", NULL, NULL, 0); + if(val) { + t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit; + XawTextReplace(edit, 0, 0, &t); + XawTextSetInsertionPoint(edit, 9999); + } +} + void StopObservingProc(w, event, prms, nprms) Widget w; XEvent *event; @@ -6062,6 +6401,15 @@ void StopExaminingProc(w, event, prms, nprms) StopExaminingEvent(); } +void UploadProc(w, event, prms, nprms) + Widget w; + XEvent *event; + String *prms; + Cardinal *nprms; +{ + UploadGameEvent(); +} + void ForwardProc(w, event, prms, nprms) Widget w; @@ -6106,7 +6454,16 @@ void RevertProc(w, event, prms, nprms) String *prms; Cardinal *nprms; { - RevertEvent(); + RevertEvent(False); +} + +void AnnotateProc(w, event, prms, nprms) + Widget w; + XEvent *event; + String *prms; + Cardinal *nprms; +{ + RevertEvent(True); } void TruncateGameProc(w, event, prms, nprms) @@ -6444,6 +6801,25 @@ void HighlightLastMoveProc(w, event, prms, nprms) "menuOptions.Highlight Last Move"), args, 1); } +void HighlightArrowProc(w, event, prms, nprms) + Widget w; + XEvent *event; + String *prms; + Cardinal *nprms; +{ + Arg args[16]; + + appData.highlightMoveWithArrow = !appData.highlightMoveWithArrow; + + if (appData.highlightMoveWithArrow) { + XtSetArg(args[0], XtNleftBitmap, xMarkPixmap); + } else { + XtSetArg(args[0], XtNleftBitmap, None); + } + XtSetValues(XtNameToWidget(menuBarWidget, + "menuOptions.Arrow"), args, 1); +} + void IcsAlarmProc(w, event, prms, nprms) Widget w; XEvent *event; @@ -6482,8 +6858,7 @@ void MoveSoundProc(w, event, prms, nprms) args, 1); } - -void OldSaveStyleProc(w, event, prms, nprms) +void OneClickProc(w, event, prms, nprms) Widget w; XEvent *event; String *prms; @@ -6491,14 +6866,14 @@ void OldSaveStyleProc(w, event, prms, nprms) { Arg args[16]; - appData.oldSaveStyle = !appData.oldSaveStyle; + appData.oneClick = !appData.oneClick; - if (appData.oldSaveStyle) { + if (appData.oneClick) { XtSetArg(args[0], XtNleftBitmap, xMarkPixmap); } else { XtSetArg(args[0], XtNleftBitmap, None); } - XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"), + XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.OneClick"), args, 1); } @@ -6807,23 +7182,23 @@ void DisplayMessage(message, extMessage) char *message, *extMessage; { /* display a message in the message widget */ - + char buf[MSG_SIZ]; Arg arg; - - if (extMessage) + + if (extMessage) { - if (*message) + if (*message) { snprintf(buf, sizeof(buf), "%s %s", message, extMessage); message = buf; - } - else + } + else { message = extMessage; }; }; - + /* need to test if messageWidget already exists, since this function can also be called during the startup, if for example a Xresource is not set up correctly */ @@ -6832,7 +7207,7 @@ void DisplayMessage(message, extMessage) XtSetArg(arg, XtNlabel, message); XtSetValues(messageWidget, &arg, 1); }; - + return; } @@ -6853,8 +7228,8 @@ void DisplayTitle(text) } if (*text != NULLCHAR) { - strcpy(icon, text); - strcpy(title, text); + safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) ); + safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) ); } else if (appData.icsActive) { snprintf(icon, sizeof(icon), "%s", appData.icsHost); snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost); @@ -6864,19 +7239,19 @@ void DisplayTitle(text) #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); + safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) ); + safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) ); #endif #ifdef FALCON } else if (gameInfo.variant == VariantFalcon) { - strcpy(icon, programName); - strcpy(title, FALCON); + safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) ); + safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) ); #endif } else if (appData.noChessProgram) { - strcpy(icon, programName); - strcpy(title, programName); + safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) ); + safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) ); } else { - strcpy(icon, first.tidy); + safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) ); snprintf(title,sizeof(title), "%s: %s", programName, first.tidy); } i = 0; @@ -6886,7 +7261,8 @@ void DisplayTitle(text) } -void DisplayError(message, error) +void +DisplayError(message, error) String message; int error; { @@ -7034,10 +7410,10 @@ void AskQuestionReplyAction(w, event, prms, nprms) String reply; reply = XawDialogGetValueString(w = XtParent(w)); - strcpy(buf, pendingReplyPrefix); - if (*buf) strcat(buf, " "); - strcat(buf, reply); - strcat(buf, "\n"); + safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) ); + if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1); + strncat(buf, reply, MSG_SIZ - strlen(buf) - 1); + strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1); OutputToProcess(pendingReplyPR, buf, strlen(buf), &err); AskQuestionPopDown(); @@ -7072,7 +7448,7 @@ void AskQuestion(title, question, replyPrefix, pr) int win_x, win_y; unsigned int mask; - strcpy(pendingReplyPrefix, replyPrefix); + safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) ); pendingReplyPR = pr; i = 0; @@ -7189,18 +7565,18 @@ Colorize(cc, continuation) if (textColors[(int)cc].bg > 0) { if (textColors[(int)cc].fg > 0) { - sprintf(buf, "\033[0;%d;%d;%dm", textColors[(int)cc].attr, - textColors[(int)cc].fg, textColors[(int)cc].bg); + snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr, + textColors[(int)cc].fg, textColors[(int)cc].bg); } else { - sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr, - textColors[(int)cc].bg); + snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr, + textColors[(int)cc].bg); } } else { if (textColors[(int)cc].fg > 0) { - sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr, + snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr, textColors[(int)cc].fg); } else { - sprintf(buf, "\033[0;%dm", textColors[(int)cc].attr); + snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr); } } count = strlen(buf); @@ -7250,11 +7626,12 @@ char *UserName() return getpwuid(getuid())->pw_name; } -static char *ExpandPathName(path) +static char * +ExpandPathName(path) char *path; { - static char static_buf[2000]; - char *d, *s, buf[2000]; + static char static_buf[4*MSG_SIZ]; + char *d, *s, buf[4*MSG_SIZ]; struct passwd *pwd; s = path; @@ -7270,25 +7647,25 @@ static char *ExpandPathName(path) if (*s == '~') { if (*(s+1) == '/') { - strcpy(d, getpwuid(getuid())->pw_dir); - strcat(d, s+1); + safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ ); + strcat(d, s+1); } else { - strcpy(buf, s+1); - *strchr(buf, '/') = 0; - pwd = getpwnam(buf); - if (!pwd) - { - fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"), - buf, path); - return NULL; - } - strcpy(d, pwd->pw_dir); - strcat(d, strchr(s+1, '/')); + safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) ); + { char *p; if(p = strchr(buf, '/')) *p = 0; } + pwd = getpwnam(buf); + if (!pwd) + { + fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"), + buf, path); + return NULL; + } + safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ ); + strcat(d, strchr(s+1, '/')); } } else - strcpy(d, s); + safeStrCpy(d, s, 4*MSG_SIZ ); return static_buf; } @@ -7463,16 +7840,16 @@ DisplayTimerLabel(w, color, timer, highlight) Pixel foregroundOrWarningColor = timerForegroundPixel; if (timer > 0 && - appData.lowTimeWarning && + appData.lowTimeWarning && (timer / 1000) < appData.icsAlarmTime) foregroundOrWarningColor = lowTimeWarningColor; if (appData.clockMode) { - sprintf(buf, "%s: %s", color, TimeString(timer)); - XtSetArg(args[0], XtNlabel, buf); + snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer)); + XtSetArg(args[0], XtNlabel, buf); } else { - sprintf(buf, "%s ", color); - XtSetArg(args[0], XtNlabel, buf); + snprintf(buf, MSG_SIZ, "%s ", color); + XtSetArg(args[0], XtNlabel, buf); } if (highlight) { @@ -7553,11 +7930,14 @@ int StartChildProcess(cmdLine, dir, pr) most simple-minded way possible. */ i = 0; - strcpy(buf, cmdLine); + safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) ); p = buf; for (;;) { + while(*p == ' ') p++; argv[i++] = p; - p = strchr(p, ' '); + if(*p == '"' || *p == '\'') + p = strchr(++argv[i-1], *p); + else p = strchr(p, ' '); if (p == NULL) break; *p++ = NULLCHAR; } @@ -8364,6 +8744,7 @@ OverlayPiece(piece, clip, outline, dest) kind = 0; else kind = 2; + if(appData.upsideDown && flipView) kind ^= 2; XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, clip, 0, 0, squareSize, squareSize, @@ -8383,7 +8764,7 @@ BeginAnimation(anim, piece, startColor, start) Pixmap mask; /* The old buffer is initialised with the start square (empty) */ - BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf); + BlankSquare(start->x, start->y, startColor, EmptySquare, anim->saveBuf, 0); anim->prevFrame = *start; /* The piece will be drawn using its own bitmap as a matte */ @@ -8488,6 +8869,29 @@ FrameSequence(anim, piece, startColor, start, finish, frames, nFrames) EndAnimation(anim, finish); } +void +AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY) +{ + int i, x, y; + ChessSquare piece = board[fromY][toY]; + board[fromY][toY] = EmptySquare; + DrawPosition(FALSE, board); + if (flipView) { + x = lineGap + ((BOARD_WIDTH-1)-toX) * (squareSize + lineGap); + y = lineGap + toY * (squareSize + lineGap); + } else { + x = lineGap + toX * (squareSize + lineGap); + y = lineGap + ((BOARD_HEIGHT-1)-toY) * (squareSize + lineGap); + } + for(i=1; i<4*kFactor; i++) { + int r = squareSize * 9 * i/(20*kFactor - 5); + XFillArc(xDisplay, xBoardWindow, highlineGC, + x + squareSize/2 - r, y+squareSize/2 - r, 2*r, 2*r, 0, 64*360); + FrameDelay(appData.animSpeed); + } + board[fromY][toY] = piece; +} + /* Main control logic for deciding what to animate and how */ void @@ -8508,8 +8912,8 @@ 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) + 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; @@ -8519,7 +8923,7 @@ AnimateMove(board, fromX, fromY, toX, toY) #if DONT_HOP hop = FALSE; #else - hop = (piece == WhiteKnight || piece == BlackKnight); + hop = abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1; #endif if (appData.debugMode) { @@ -8531,12 +8935,12 @@ AnimateMove(board, fromX, fromY, toX, toY) ScreenSquare(toX, toY, &finish, &endColor); if (hop) { - /* Knight: make diagonal movement then straight */ + /* Knight: make straight movement then diagonal */ if (abs(toY - fromY) < abs(toX - fromX)) { mid.x = start.x + (finish.x - start.x) / 2; - mid.y = finish.y; + mid.y = start.y; } else { - mid.x = finish.x; + mid.x = start.x; mid.y = start.y + (finish.y - start.y) / 2; } } else { @@ -8550,9 +8954,14 @@ AnimateMove(board, fromX, fromY, toX, toY) else Tween(&start, &mid, &finish, kFactor, frames, &nFrames); FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames); + if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged + int i,j; + for(i=0; i @@ -8692,17 +9112,214 @@ int get_term_width() return default_width; } -void update_ics_width() +void +update_ics_width() { - static int old_width = 0; - int new_width = get_term_width(); + static int old_width = 0; + int new_width = get_term_width(); - if (old_width != new_width) - ics_printf("set width %d\n", new_width); - old_width = new_width; + if (old_width != new_width) + ics_printf("set width %d\n", new_width); + old_width = new_width; } void NotifyFrontendLogin() { update_ics_width(); } + +/* [AS] Arrow highlighting support */ + +static double A_WIDTH = 5; /* Width of arrow body */ + +#define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */ +#define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */ + +static double Sqr( double x ) +{ + return x*x; +} + +static int Round( double x ) +{ + return (int) (x + 0.5); +} + +void SquareToPos(int rank, int file, int *x, int *y) +{ + if (flipView) { + *x = lineGap + ((BOARD_WIDTH-1)-file) * (squareSize + lineGap); + *y = lineGap + rank * (squareSize + lineGap); + } else { + *x = lineGap + file * (squareSize + lineGap); + *y = lineGap + ((BOARD_HEIGHT-1)-rank) * (squareSize + lineGap); + } +} + +/* Draw an arrow between two points using current settings */ +void DrawArrowBetweenPoints( int s_x, int s_y, int d_x, int d_y ) +{ + XPoint arrow[7]; + double dx, dy, j, k, x, y; + + if( d_x == s_x ) { + int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR; + + arrow[0].x = s_x + A_WIDTH + 0.5; + arrow[0].y = s_y; + + arrow[1].x = s_x + A_WIDTH + 0.5; + arrow[1].y = d_y - h; + + arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5; + arrow[2].y = d_y - h; + + arrow[3].x = d_x; + arrow[3].y = d_y; + + arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5; + arrow[5].y = d_y - h; + + arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5; + arrow[4].y = d_y - h; + + arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5; + arrow[6].y = s_y; + } + else if( d_y == s_y ) { + int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR; + + arrow[0].x = s_x; + arrow[0].y = s_y + A_WIDTH + 0.5; + + arrow[1].x = d_x - w; + arrow[1].y = s_y + A_WIDTH + 0.5; + + arrow[2].x = d_x - w; + arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5; + + arrow[3].x = d_x; + arrow[3].y = d_y; + + arrow[5].x = d_x - w; + arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5; + + arrow[4].x = d_x - w; + arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5; + + arrow[6].x = s_x; + arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5; + } + else { + /* [AS] Needed a lot of paper for this! :-) */ + dy = (double) (d_y - s_y) / (double) (d_x - s_x); + dx = (double) (s_x - d_x) / (double) (s_y - d_y); + + j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) ); + + k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) ); + + x = s_x; + y = s_y; + + arrow[0].x = Round(x - j); + arrow[0].y = Round(y + j*dx); + + arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice + arrow[1].y = Round(arrow[0].y - 2*j*dx); + + if( d_x > s_x ) { + x = (double) d_x - k; + y = (double) d_y - k*dy; + } + else { + x = (double) d_x + k; + y = (double) d_y + k*dy; + } + + x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends + + arrow[6].x = Round(x - j); + arrow[6].y = Round(y + j*dx); + + arrow[2].x = Round(arrow[6].x + 2*j); + arrow[2].y = Round(arrow[6].y - 2*j*dx); + + arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1)); + arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx); + + arrow[4].x = d_x; + arrow[4].y = d_y; + + arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1)); + arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx); + } + + XFillPolygon(xDisplay, xBoardWindow, highlineGC, arrow, 7, Nonconvex, CoordModeOrigin); +// Polygon( hdc, arrow, 7 ); +} + +/* [AS] Draw an arrow between two squares */ +void DrawArrowBetweenSquares( int s_col, int s_row, int d_col, int d_row ) +{ + int s_x, s_y, d_x, d_y, hor, vert, i; + + if( s_col == d_col && s_row == d_row ) { + return; + } + + /* Get source and destination points */ + SquareToPos( s_row, s_col, &s_x, &s_y); + SquareToPos( d_row, d_col, &d_x, &d_y); + + if( d_y > s_y ) { + d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides! + } + else if( d_y < s_y ) { + d_y += squareSize / 2 + squareSize / 4; + } + else { + d_y += squareSize / 2; + } + + if( d_x > s_x ) { + d_x += squareSize / 2 - squareSize / 4; + } + else if( d_x < s_x ) { + d_x += squareSize / 2 + squareSize / 4; + } + else { + d_x += squareSize / 2; + } + + s_x += squareSize / 2; + s_y += squareSize / 2; + + /* Adjust width */ + A_WIDTH = squareSize / 14.; //[HGM] make float + + DrawArrowBetweenPoints( s_x, s_y, d_x, d_y ); + + if(lineGap == 0) { + // this is a good idea, but it only works when lineGap == 0, because 'damage' on grid lines is not repaired + hor = 64*s_col + 32; vert = 64*s_row + 32; + for(i=0; i<= 64; i++) { + damage[0][vert+6>>6][hor+6>>6] = True; + damage[0][vert-6>>6][hor+6>>6] = True; + damage[0][vert+6>>6][hor-6>>6] = True; + damage[0][vert-6>>6][hor-6>>6] = True; + hor += d_col - s_col; vert += d_row - s_row; + } + } +} + +Boolean IsDrawArrowEnabled() +{ + return appData.highlightMoveWithArrow && squareSize >= 32; +} + +void DrawArrowHighlight(int fromX, int fromY, int toX,int toY) +{ + if( IsDrawArrowEnabled() && fromX >= 0 && fromY >= 0 && toX >= 0 && toY >= 0) + DrawArrowBetweenSquares(fromX, fromY, toX, toY); +}