X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=xboard.c;h=1675b790f99eba15a66098730aff6b26546074a7;hb=7b4dacf6fe9f8c10b6eb4d6070869a3d933dbeb5;hp=d47a15d0ac74b6d61bc1fd1b2959e463e7851fd4;hpb=d5e1ced63182849f6c1fcaf3abb5d15d437545c5;p=xboard.git diff --git a/xboard.c b/xboard.c index d47a15d..1675b79 100644 --- a/xboard.c +++ b/xboard.c @@ -1,6 +1,5 @@ /* * xboard.c -- X front end for XBoard - * $Id: xboard.c,v 2.2 2003/11/06 07:22:14 mann Exp $ * * Copyright 1991 by Digital Equipment Corporation, Maynard, * Massachusetts. Enhancements Copyright @@ -495,16 +494,19 @@ char *chessDir, *programName, *programVersion, #define SOLID 0 #define OUTLINE 1 Pixmap pieceBitmap[2][(int)BlackPawn]; -Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD */ +Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */ +Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/ +Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */ Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare; int useImages, useImageSqs; -XImage *ximPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD */ -Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */ +XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */ +Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */ +Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */ XImage *ximLightSquare, *ximDarkSquare; XImage *xim_Cross; -#define pieceToSolid(piece) &pieceBitmap[SOLID][((int)(piece)) % (int)BlackPawn] -#define pieceToOutline(piece) &pieceBitmap[OUTLINE][((int)(piece)) % (int)BlackPawn] +#define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn] +#define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn] #define White(piece) ((int)(piece) < (int)BlackPawn) @@ -696,21 +698,27 @@ MenuItem buttonBar[] = { {NULL, NULL} }; -#define PIECE_MENU_SIZE 11 +#define PIECE_MENU_SIZE 18 String pieceMenuStrings[2][PIECE_MENU_SIZE] = { { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), - N_("Queen"), N_("King"), "----", N_("Empty square"), N_("Clear board") }, + N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"), + N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"), + N_("Empty square"), N_("Clear board") }, { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), - N_("Queen"), N_("King"), "----", N_("Empty square"), N_("Clear board") }, + N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"), + N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"), + N_("Empty square"), N_("Clear board") } }; /* must be in same order as PieceMenuStrings! */ ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = { { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop, - WhiteRook, WhiteQueen, WhiteKing, - (ChessSquare) 0, EmptySquare, ClearBoard }, + WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil, + WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0, + PromotePiece, DemotePiece, EmptySquare, ClearBoard }, { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop, - BlackRook, BlackQueen, BlackKing, - (ChessSquare) 0, EmptySquare, ClearBoard }, + BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil, + BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0, + PromotePiece, DemotePiece, EmptySquare, ClearBoard }, }; #define DROP_MENU_SIZE 6 @@ -2244,6 +2252,66 @@ void InitDrawingSizes(BoardSize boardSize, int flags) shellArgs[4].value = shellArgs[2].value = w; shellArgs[5].value = shellArgs[3].value = h; XtSetValues(shellWidget, &shellArgs[0], 6); + + // [HGM] pieces: tailor piece bitmaps to needs of specific variant + // (only for xpm) + if(useImages) { + for(i=0; i<4; i++) { + int p; + for(p=0; p<=(int)WhiteKing; p++) + xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults + if(gameInfo.variant == VariantShogi) { + xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1]; + xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2]; + xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3]; + xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4]; + xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance]; + } +#ifdef GOTHIC + if(gameInfo.variant == VariantGothic) { + xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver]; + } +#endif +#if !HAVE_LIBXPM + // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used! + for(p=0; p<=(int)WhiteKing; p++) + ximMaskPm[p] = ximMaskPm2[p]; // defaults + if(gameInfo.variant == VariantShogi) { + ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1]; + ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2]; + ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3]; + ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4]; + ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance]; + } +#ifdef GOTHIC + if(gameInfo.variant == VariantGothic) { + ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[i][(int)WhiteSilver]; + } +#endif +#endif + } + } else { + for(i=0; i<2; i++) { + int p; + for(p=0; p<=(int)WhiteKing; p++) + pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults + if(gameInfo.variant == VariantShogi) { + pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1]; + pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2]; + pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3]; + pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4]; + pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance]; + } +#ifdef GOTHIC + if(gameInfo.variant == VariantGothic) { + pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver]; + } +#endif + } + } +#if HAVE_LIBXPM + CreateAnimVars(); +#endif } #endif @@ -2329,6 +2397,20 @@ main(argc, argv) if (argc > 1) { fprintf(stderr, _("%s: unrecognized argument %s\n"), programName, argv[1]); + fprintf(stderr, "Recognized options:\n"); + for(i = 0; i < XtNumber(shellOptions); i++) { + j = fprintf(stderr, " %s%s", shellOptions[i].option, + (shellOptions[i].argKind == XrmoptionSepArg + ? " ARG" : "")); + if (i++ < XtNumber(shellOptions)) { + fprintf(stderr, "%*c%s%s\n", 40 - j, ' ', + shellOptions[i].option, + (shellOptions[i].argKind == XrmoptionSepArg + ? " ARG" : "")); + } else { + fprintf(stderr, "\n"); + } + } exit(2); } @@ -2586,6 +2668,10 @@ XBoard square size (hint): %d\n\ if (forceMono) { fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"), programName); + + if (appData.bitmapDirectory == NULL || + appData.bitmapDirectory[0] == NULLCHAR) + appData.bitmapDirectory = DEF_BITMAP_DIR; } if (appData.lowTimeWarning && !appData.monoMode) { @@ -3074,7 +3160,8 @@ XBoard square size (hint): %d\n\ signal(SIGUSR1, CmailSigHandler); } } - InitPosition(TRUE); + gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes() + InitPosition(TRUE); XtAppMainLoop(appContext); if (appData.debugMode) fclose(debugFP); // [DM] debug @@ -3686,6 +3773,9 @@ void loadXIM(xim, xmask, filename, dest, mask) } } + +char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl"; + void CreateXIMPieces() { int piece, kind; @@ -3716,13 +3806,14 @@ void CreateXIMPieces() } fprintf(stderr, _("\nLoading XIMs...\n")); /* Load pieces */ - for (piece = (int) WhitePawn; piece <= (int) WhiteKing; piece++) { + for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) { fprintf(stderr, "%d", piece+1); for (kind=0; kind<4; kind++) { fprintf(stderr, "."); - snprintf(buf, sizeof(buf), "%s/%c%s%u.xim", + snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim", ExpandPathName(appData.pixmapDirectory), - ToLower(PieceToChar((ChessSquare)piece)), + piece <= (int) WhiteKing ? "" : "w", + pieceBitmapNames[piece], ximkind[kind], ss); ximPieceBitmap[kind][piece] = XGetImage(xDisplay, DefaultRootWindow(xDisplay), @@ -3731,8 +3822,10 @@ void CreateXIMPieces() fprintf(stderr, _("(File:%s:) "), buf); loadXIM(ximPieceBitmap[kind][piece], ximtemp, buf, - &(xpmPieceBitmap[kind][piece]), - &(ximMaskPm[piece%(int)BlackPawn])); + &(xpmPieceBitmap2[kind][piece]), + &(ximMaskPm2[piece])); + if(piece <= (int)WhiteKing) + xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece]; } fprintf(stderr," "); } @@ -3818,17 +3911,19 @@ void CreateXPMPieces() fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize); exit(1); } - for (piece = (int) WhitePawn; piece <= (int) WhiteKing; piece++) { + for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) { for (kind=0; kind<4; kind++) { if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow, pieces->xpm[piece][kind], - &(xpmPieceBitmap[kind][piece]), + &(xpmPieceBitmap2[kind][piece]), NULL, &attr)) != 0) { fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"), r, buf); exit(1); } + if(piece <= (int) WhiteKing) + xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece]; } } useImageSqs = 0; @@ -3839,23 +3934,26 @@ void CreateXPMPieces() fprintf(stderr, _("\nLoading XPMs...\n")); /* Load pieces */ - for (piece = (int) WhitePawn; piece <= (int) WhiteKing; piece++) { + for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) { fprintf(stderr, "%d ", piece+1); for (kind=0; kind<4; kind++) { - snprintf(buf, sizeof(buf), "%s/%c%s%u.xpm", + snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm", ExpandPathName(appData.pixmapDirectory), - ToLower(PieceToChar((ChessSquare)piece)), + piece > (int) WhiteKing ? "w" : "", + pieceBitmapNames[piece], xpmkind[kind], ss); if (appData.debugMode) { fprintf(stderr, _("(File:%s:) "), buf); } if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf, - &(xpmPieceBitmap[kind][piece]), + &(xpmPieceBitmap2[kind][piece]), NULL, &attr)) != 0) { fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf); exit(1); } + if(piece <= (int) WhiteKing) + xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece]; } } /* Load light and dark squares */ @@ -3907,10 +4005,13 @@ void CreatePieces() buffering bug */ for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) { - for (piece = (int) WhitePawn; piece <= (int) WhiteKing; piece++) { - sprintf(buf, "%c%u%c.bm", ToLower(PieceToChar((ChessSquare)piece)), + for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) { + sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "", + pieceBitmapNames[piece], ss, kind == SOLID ? 's' : 'o'); - ReadBitmap(&pieceBitmap[kind][piece], buf, NULL, ss, ss); + ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss); + if(piece <= (int)WhiteKing) + pieceBitmap[kind][piece] = pieceBitmap2[kind][piece]; } } @@ -3932,11 +4033,14 @@ void CreatePieces() while (bib->squareSize != ss && bib->squareSize != 0) bib++; for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) { - for (piece = (int) WhitePawn; piece <= (int) WhiteKing; piece++) { - sprintf(buf, "%c%u%c.bm", ToLower(PieceToChar((ChessSquare)piece)), + for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) { + sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "", + pieceBitmapNames[piece], ss, kind == SOLID ? 's' : 'o'); - ReadBitmap(&pieceBitmap[kind][piece], buf, + ReadBitmap(&pieceBitmap2[kind][piece], buf, bib->bits[kind][piece], ss, ss); + if(piece <= (int)WhiteKing) + pieceBitmap[kind][piece] = pieceBitmap2[kind][piece]; } } @@ -3962,6 +4066,7 @@ void ReadBitmap(pm, name, bits, wreq, hreq) strcat(fullname, name); errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname, &w, &h, pm, &x_hot, &y_hot); + fprintf(stderr, "load %s\n", name); if (errcode != BitmapSuccess) { switch (errcode) { case BitmapOpenFailed: @@ -4651,17 +4756,6 @@ void DrawSquare(row, column, piece, do_flash) DrawFunc drawfunc; int flash_delay; - if(gameInfo.variant == VariantShogi) { // [HGM] shogi: in shogi Q is used for Lance - if(piece == WhiteQueen) piece = WhiteLance; else - if(piece == BlackQueen) piece = BlackLance; - } -#ifdef GOTHIC - else if(gameInfo.variant == VariantGothic) { // [HGM] shogi: in Gothic Chancelor has alternative look - if(piece == WhiteMarshall) piece = WhiteSilver; else - if(piece == BlackMarshall) piece = BlackSilver; - } -#endif - /* Calculate delay in milliseconds (2-delays per complete flash) */ flash_delay = 500 / appData.flashRate; @@ -5815,11 +5909,12 @@ void PromotionPopUp() layoutArgs, XtNumber(layoutArgs)); j = 0; - XtSetArg(args[j], XtNlabel, _("Promote pawn to what?")); j++; + XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++; XtSetArg(args[j], XtNborderWidth, 0); j++; dialog = XtCreateManagedWidget("promotion", dialogWidgetClass, layout, args, j); + if(gameInfo.variant != VariantShogi) { XawDialogAddButton(dialog, _("Queen"), PromotionCallback, (XtPointer) dialog); XawDialogAddButton(dialog, _("Rook"), PromotionCallback, @@ -5833,6 +5928,21 @@ void PromotionPopUp() XawDialogAddButton(dialog, _("King"), PromotionCallback, (XtPointer) dialog); } + if(gameInfo.variant == VariantCapablanca || + gameInfo.variant == VariantGothic || + gameInfo.variant == VariantCapaRandom) { + XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback, + (XtPointer) dialog); + XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback, + (XtPointer) dialog); + } + } else // [HGM] shogi + { + XawDialogAddButton(dialog, _("Promote"), PromotionCallback, + (XtPointer) dialog); + XawDialogAddButton(dialog, _("Defer"), PromotionCallback, + (XtPointer) dialog); + } XawDialogAddButton(dialog, _("cancel"), PromotionCallback, (XtPointer) dialog); @@ -5887,6 +5997,10 @@ void PromotionCallback(w, client_data, call_data) return; } else if (strcmp(name, _("Knight")) == 0) { promoChar = 'n'; + } else if (strcmp(name, _("Promote")) == 0) { + promoChar = '+'; + } else if (strcmp(name, _("Defer")) == 0) { + promoChar = '='; } else { promoChar = ToLower(name[0]); } @@ -7512,7 +7626,7 @@ void DisplayTitle(text) strcpy(title, text); } else if (appData.icsActive) { snprintf(icon, sizeof(icon), "%s", appData.icsHost); - snprintf(title, sizeof(title),"%s: %s", programName, appData.icsHost); + snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost); } else if (appData.cmailGameName[0] != NULLCHAR) { snprintf(icon, sizeof(icon), "%s", "CMail"); snprintf(title,sizeof(title), "%s: %s", programName, "CMail"); @@ -7556,7 +7670,7 @@ void DisplayError(message, error) fprintf(stderr, "%s: %s: %s\n", programName, message, strerror(error)); } - snprintf(buf,sizeof(buf), "%s: %s", message, strerror(error)); + snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error)); message = buf; } ErrorPopUp(_("Error"), message, FALSE); @@ -8111,12 +8225,12 @@ DisplayTimerLabel(w, color, timer, highlight) char buf[MSG_SIZ]; Arg args[16]; + /* check for low time warning */ Pixel foregroundOrWarningColor = timerForegroundPixel; - if (timer > 0 - && appData.lowTimeWarning - && (timer / 1000) < appData.icsAlarmTime) - + if (timer > 0 && + appData.lowTimeWarning && + (timer / 1000) < appData.icsAlarmTime) foregroundOrWarningColor = lowTimeWarningColor; if (appData.clockMode) { @@ -8311,7 +8425,7 @@ int OpenTelnet(host, port, pr) if (port[0] == NULLCHAR) { snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host); } else { - snprintf(cmdLine,sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port); + snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port); } return StartChildProcess(cmdLine, "", pr); } @@ -8595,6 +8709,8 @@ int OutputToProcessDelayed(pr, message, count, outError, msdelay) and dark squares, and all pieces must use the same background square colors/images. */ +static int xpmDone = 0; + static void CreateAnimMasks (pieceDepth) int pieceDepth; @@ -8625,6 +8741,7 @@ CreateAnimMasks (pieceDepth) for (piece = WhitePawn; piece <= BlackKing; piece++) { /* Begin with empty mask */ + if(!xpmDone) // [HGM] pieces: keep using existing xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow, squareSize, squareSize, 1); XSetFunction(xDisplay, maskGC, GXclear); @@ -8708,11 +8825,11 @@ InitAnimState (anim, info) static void CreateAnimVars () { - static int done = 0; + static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes XWindowAttributes info; - if (done) return; - done = 1; + if (xpmDone && gameInfo.variant == old) return; + if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet XGetWindowAttributes(xDisplay, xBoardWindow, &info); InitAnimState(&game, &info); @@ -8721,6 +8838,7 @@ CreateAnimVars () /* For XPM pieces, we need bitmaps to use as masks. */ if (useImages) CreateAnimMasks(info.depth); + xpmDone = 1; } #ifndef HAVE_USLEEP @@ -8946,7 +9064,7 @@ SelectGCMask(piece, clip, outline, mask) #if HAVE_LIBXPM *mask = xpmMask[piece]; #else - *mask = ximMaskPm[piece%(int)BlackPawn]; + *mask = ximMaskPm[piece]; #endif } else { *mask = *pieceToSolid(piece); @@ -8995,7 +9113,7 @@ OverlayPiece(piece, clip, outline, dest) kind = 0; else kind = 2; - XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn], + XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, clip, 0, 0, squareSize, squareSize, 0, 0); @@ -9139,6 +9257,10 @@ AnimateMove(board, fromX, fromY, toX, toY) if (!appData.animate || appData.blindfold) return; + if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing || + board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing) + return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square + if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return; piece = board[fromY][fromX]; if (piece >= EmptySquare) return;