X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=xboard.c;h=79b61a29602e4d2f99b69e99dc47040ad61f95c1;hb=a5b8066ad78ddeec1ddcca3b31ee26fe1052fc89;hp=05af22bd8201f75fb9718382a3307eda68d5e976;hpb=83d0f555a7dad1d410761ec89273d795f038860c;p=xboard.git diff --git a/xboard.c b/xboard.c index 05af22b..79b61a2 100644 --- a/xboard.c +++ b/xboard.c @@ -1022,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 }, @@ -1347,7 +1347,7 @@ XtResource clientResources[] = { XtRImmediate, (XtPointer) "xboard.debug"}, { "engineDebugOutput", "engineDebugOutput", XtRInt, sizeof(int), XtOffset(AppDataPtr, engineComments), - XtRImmediate, (XtPointer) 0}, + XtRImmediate, (XtPointer) 1}, { "noGUI", "noGUI", XtRBoolean, sizeof(Boolean), XtOffset(AppDataPtr, noGUI), XtRImmediate, (XtPointer) 0}, @@ -1401,6 +1401,12 @@ XtResource clientResources[] = { { "delayAfterQuit", "delayAfterQuit", XtRInt, sizeof(int), XtOffset(AppDataPtr, delayAfterQuit), XtRImmediate, (XtPointer) 0}, + { "keepAlive", "keepAlive", XtRInt, + sizeof(int), XtOffset(AppDataPtr, keepAlive), + XtRImmediate, (XtPointer) 0}, + { "forceIllegalMoves", "forceIllegalMoves", XtRBoolean, + sizeof(Boolean), XtOffset(AppDataPtr, forceIllegal), + XtRImmediate, (XtPointer) False}, }; XrmOptionDescRec shellOptions[] = { @@ -1768,6 +1774,8 @@ XrmOptionDescRec shellOptions[] = { { "-secondOptions", "secondOptions", XrmoptionSepArg, NULL }, { "-firstNeedsNoncompliantFEN", "firstNeedsNoncompliantFEN", XrmoptionSepArg, NULL }, { "-secondNeedsNoncompliantFEN", "secondNeedsNoncompliantFEN", XrmoptionSepArg, NULL }, + { "-keepAlive", "keepAlive", XrmoptionSepArg, NULL }, + { "-forceIllegalMoves", "forceIllegalMoves", XrmoptionNoArg, "True" }, }; @@ -2290,7 +2298,7 @@ void InitDrawingSizes(BoardSize boardSize, int flags) } #ifdef GOTHIC if(gameInfo.variant == VariantGothic) { - ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[i][(int)WhiteSilver]; + ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver]; } #endif #endif @@ -2320,6 +2328,19 @@ void InitDrawingSizes(BoardSize boardSize, int flags) } #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; @@ -2378,7 +2399,6 @@ main(argc, argv) #endif #endif - setbuf(stdout, NULL); setbuf(stderr, NULL); debugFP = stderr; @@ -2399,35 +2419,35 @@ main(argc, argv) XtAppInitialize(&appContext, "XBoard", shellOptions, XtNumber(shellOptions), &argc, argv, xboardResources, NULL, 0); - if (argc > 1) { + if (argc > 1) + { /* left over command line arguments, print out help and exit. + * Use two columns to print help + */ fprintf(stderr, _("%s: unrecognized argument %s\n"), programName, argv[1]); + fprintf(stderr, "Recognized options:\n"); - for(i = 0; i < XtNumber(shellOptions); i++) { + for(i = 0; i < XtNumber(shellOptions); i++) + { + /* print first column */ j = fprintf(stderr, " %s%s", shellOptions[i].option, (shellOptions[i].argKind == XrmoptionSepArg ? " ARG" : "")); - if (i++ < XtNumber(shellOptions)) { + /* print second column and end line */ + if (++i < XtNumber(shellOptions)) + { fprintf(stderr, "%*c%s%s\n", 40 - j, ' ', shellOptions[i].option, (shellOptions[i].argKind == XrmoptionSepArg ? " ARG" : "")); - } else { + } + else + { fprintf(stderr, "\n"); - } - } + }; + }; exit(2); - } - - if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) { - chessDir = "."; - } else { - if (chdir(chessDir) != 0) { - fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName); - perror(chessDir); - exit(1); - } - } + }; p = getenv("HOME"); if (p == NULL) p = "/tmp"; @@ -2441,6 +2461,28 @@ main(argc, argv) 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 { + if (chdir(chessDir) != 0) { + fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName); + perror(chessDir); + exit(1); + } + } + 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) { @@ -3953,9 +3995,23 @@ void CreateXPMPieces() if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf, &(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]; @@ -5089,10 +5145,40 @@ void HandleUserMove(w, event, prms, nprms) { int x, y; Boolean saveAnimate; - static int second = 0; + static int second = 0, promotionChoice = 0; + ChessMove moveType; if (w != boardWidget || errorExitStatus != -1) return; + x = EventToSquare(event->xbutton.x, BOARD_WIDTH); + y = EventToSquare(event->xbutton.y, BOARD_HEIGHT); + if (!flipView && y >= 0) { + y = BOARD_HEIGHT - 1 - y; + } + if (flipView && x >= 0) { + x = BOARD_WIDTH - 1 - x; + } + + if(promotionChoice) { // we are waiting for a click to indicate promotion piece + if(event->type == ButtonRelease) return; // ignore upclick of click-click destination + promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel + if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y); + if(gameInfo.holdingsWidth && + (WhiteOnMove(currentMove) + ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0 + : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) { + // click in right holdings, for determining promotion piece + ChessSquare p = boards[currentMove][y][x]; + if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p); + if(p != EmptySquare) { + FinishMove(NormalMove, fromX, fromY, toX, toY, ToLower(PieceToChar(p))); + fromX = fromY = -1; + return; + } + } + DrawPosition(FALSE, boards[currentMove]); + return; + } if (event->type == ButtonPress) ErrorPopDown(); if (promotionUp) { @@ -5107,15 +5193,6 @@ void HandleUserMove(w, event, prms, nprms) } } - x = EventToSquare(event->xbutton.x, BOARD_WIDTH); - y = EventToSquare(event->xbutton.y, BOARD_HEIGHT); - if (!flipView && y >= 0) { - y = BOARD_HEIGHT - 1 - y; - } - if (flipView && x >= 0) { - 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 @@ -5125,7 +5202,7 @@ void HandleUserMove(w, event, prms, nprms) if (fromX == -1) { if (event->type == ButtonPress) { - /* First square */ + /* First square, prepare to drag */ if (OKToStartUserMove(x, y)) { fromX = x; fromY = y; @@ -5140,39 +5217,8 @@ void HandleUserMove(w, event, prms, nprms) } /* fromX != -1 */ - if (event->type == ButtonPress && gameMode != EditPosition && - 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]; - 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) { - SetHighlights(x, y, -1, -1); - } else { - ClearHighlights(); - } - if (OKToStartUserMove(x, y)) { - fromX = x; - fromY = y; - DragPieceBegin(event->xbutton.x, event->xbutton.y); - } - return; - } - } - if (event->type == ButtonRelease && x == fromX && y == fromY) { + /* Click on single square in stead of drag-drop */ DragPieceEnd(event->xbutton.x, event->xbutton.y); if (appData.animateDragging) { /* Undo animation damage if any */ @@ -5192,7 +5238,34 @@ void HandleUserMove(w, event, prms, nprms) return; } - /* Completed move */ + moveType = UserMoveTest(fromX, fromY, x, y, NULLCHAR, event->type == ButtonRelease); + + if (moveType == Comment) { // kludge for indicating capture-own on Press + /* Clicked again on same color piece -- changed his mind */ + /* note that re-clicking same square always hits same color piece */ + second = (x == fromX && y == fromY); + if (appData.highlightDragging) { + SetHighlights(x, y, -1, -1); + } else { + ClearHighlights(); + } + if (OKToStartUserMove(x, y)) { + fromX = x; + fromY = y; + DragPieceBegin(event->xbutton.x, event->xbutton.y); + } + return; + } + + if(moveType == AmbiguousMove) { // kludge to indicate edit-position move + fromX = fromY = -1; + ClearHighlights(); + DragPieceEnd(event->xbutton.x, event->xbutton.y); + DrawPosition(FALSE, boards[currentMove]); + return; + } + + /* Complete move; (x,y) is now different from (fromX, fromY) on both Press and Release */ toX = x; toY = y; saveAnimate = appData.animate; @@ -5214,22 +5287,38 @@ void HandleUserMove(w, event, prms, nprms) /* Don't animate move and drag both */ appData.animate = FALSE; } - if (IsPromotion(fromX, fromY, toX, toY)) { - if (appData.alwaysPromoteToQueen) { - UserMoveEvent(fromX, fromY, toX, toY, 'q'); + if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight || + (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) && + appData.alwaysPromoteToQueen) { // promotion, but no choice + FinishMove(moveType, fromX, fromY, toX, toY, 'q'); + } else + if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) { + SetHighlights(fromX, fromY, toX, toY); + if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat) { + // [HGM] super: promotion to captured piece selected from holdings + ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX]; + promotionChoice = TRUE; + // kludge follows to temporarily execute move on display, without promoting yet + boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank + boards[currentMove][toY][toX] = p; + DrawPosition(FALSE, boards[currentMove]); + boards[currentMove][fromY][fromX] = p; // take back, but display stays + boards[currentMove][toY][toX] = q; + DisplayMessage("Click in holdings to choose piece", ""); + return; + } + PromotionPopUp(); + goto skipClearingFrom; // the skipped stuff is done asynchronously by PromotionCallback + } else + if(moveType != ImpossibleMove) { // valid move, but no promotion + FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR); + } else { // invalid move; could have set premove + ClearHighlights(); + } if (!appData.highlightLastMove || gotPremove) ClearHighlights(); if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY); fromX = fromY = -1; - } else { - SetHighlights(fromX, fromY, toX, toY); - PromotionPopUp(); - } - } else { - UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR); - if (!appData.highlightLastMove || gotPremove) ClearHighlights(); - if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY); - fromX = fromY = -1; - } +skipClearingFrom: appData.animate = saveAnimate; if (appData.animate || appData.animateDragging) { /* Undo animation damage if needed */ @@ -6014,7 +6103,7 @@ void PromotionCallback(w, client_data, call_data) promoChar = ToLower(name[0]); } - UserMoveEvent(fromX, fromY, toX, toY, promoChar); + FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar); if (!appData.highlightLastMove || gotPremove) ClearHighlights(); if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY); @@ -7599,19 +7688,34 @@ void Iconify(w, event, prms, nprms) void DisplayMessage(message, extMessage) char *message, *extMessage; { - char buf[MSG_SIZ]; - Arg arg; - - if (extMessage) { - if (*message) { - snprintf(buf, sizeof(buf), "%s %s", message, extMessage); - message = buf; - } else { - message = extMessage; - } - } - XtSetArg(arg, XtNlabel, message); - XtSetValues(messageWidget, &arg, 1); + /* display a message in the message widget */ + + char buf[MSG_SIZ]; + Arg arg; + + if (extMessage) + { + if (*message) + { + snprintf(buf, sizeof(buf), "%s %s", message, extMessage); + message = buf; + } + 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 */ + if(messageWidget) + { + XtSetArg(arg, XtNlabel, message); + XtSetValues(messageWidget, &arg, 1); + }; + + return; } void DisplayTitle(text) @@ -8102,6 +8206,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,