fixed bug when switching to variantsuper
[xboard.git] / xboard.c
index 3fbb9c4..909ca85 100644 (file)
--- a/xboard.c
+++ b/xboard.c
@@ -232,6 +232,7 @@ typedef struct {
 int main P((int argc, char **argv));
 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));
@@ -280,7 +281,6 @@ void AskQuestionReplyAction P((Widget w, XEvent *event,
 void AskQuestionProc P((Widget w, XEvent *event,
                          String *prms, Cardinal *nprms));
 void AskQuestionPopDown P((void));
-void PromotionPopUp P((void));
 void PromotionPopDown P((void));
 void PromotionCallback P((Widget w, XtPointer client_data,
                          XtPointer call_data));
@@ -427,9 +427,7 @@ void ErrorPopUp P((char *title, char *text, int modal));
 void ErrorPopDown P((void));
 static char *ExpandPathName P((char *path));
 static void CreateAnimVars P((void));
-static void DragPieceBegin P((int x, int y));
 static void DragPieceMove P((int x, int y));
-static void DragPieceEnd P((int x, int y));
 static void DrawDragPiece P((void));
 char *ModeToWidgetName P((GameMode mode));
 void EngineOutputUpdate( FrontEndProgramStats * stats );
@@ -446,6 +444,8 @@ void UciPopDown P(());
 void TimeControlPopDown P(());
 void NewVariantPopDown P(());
 void SettingsPopDown P(());
+void update_ics_width P(());
+int get_term_width P(());
 /*
 * XBoard depends on Xt R4 or higher
 */
@@ -1407,6 +1407,15 @@ XtResource clientResources[] = {
     { "forceIllegalMoves", "forceIllegalMoves", XtRBoolean,
        sizeof(Boolean), XtOffset(AppDataPtr, forceIllegal),
        XtRImmediate, (XtPointer) False},
+    { "keepLineBreaksICS", "keepLineBreaksICS", XtRBoolean,
+       sizeof(Boolean), XtOffset(AppDataPtr, noJoin),
+       XtRImmediate, (XtPointer) False},
+    { "wrapContinuationSequence", "wrapContinuationSequence", XtRString,
+       sizeof(String), XtOffset(AppDataPtr, wrapContSeq),
+       XtRString, ""},
+    { "useInternalWrap", "useInternalWrap", XtRBoolean,
+       sizeof(Boolean), XtOffset(AppDataPtr, useInternalWrap),
+       XtRImmediate, (XtPointer) True},
 };
 
 XrmOptionDescRec shellOptions[] = {
@@ -1776,9 +1785,11 @@ XrmOptionDescRec shellOptions[] = {
     { "-secondNeedsNoncompliantFEN", "secondNeedsNoncompliantFEN", XrmoptionSepArg, NULL },
     { "-keepAlive", "keepAlive", XrmoptionSepArg, NULL },
     { "-forceIllegalMoves", "forceIllegalMoves", XrmoptionNoArg, "True" },
+    { "-keepLineBreaksICS", "keepLineBreaksICS", XrmoptionSepArg, NULL },
+    { "-wrapContinuationSequence", "wrapContinuationSequence", XrmoptionSepArg, NULL },
+    { "-useInternalWrap", "useInternalWrap", XrmoptionSepArg, NULL },
 };
 
-
 XtActionsRec boardActions[] = {
     { "DrawPosition", DrawPositionProc },
     { "HandleUserMove", HandleUserMove },
@@ -1890,7 +1901,6 @@ XtActionsRec boardActions[] = {
     { "TagsPopDown", (XtActionProc) TagsPopDown },
     { "ErrorPopDown", (XtActionProc) ErrorPopDown },
     { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
-    { "AnalysisPopDown", (XtActionProc) AnalysisPopDown },
     { "FileNamePopDown", (XtActionProc) FileNamePopDown },
     { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
     { "GameListPopDown", (XtActionProc) GameListPopDown },
@@ -2767,6 +2777,7 @@ XBoard square size (hint): %d\n\
     widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
     XtSetArg(args[0], XtNtop,    XtChainTop);
     XtSetArg(args[1], XtNbottom, XtChainTop);
+    XtSetArg(args[1], XtNright,  XtChainLeft);
     XtSetValues(menuBarWidget, args, 2);
 
     widgetList[j++] = whiteTimerWidget =
@@ -3183,6 +3194,9 @@ XBoard square size (hint): %d\n\
            if (appData.icsInputBox) ICSInputBoxPopUp();
        }
 
+    #ifdef SIGWINCH
+    signal(SIGWINCH, TermSizeSigHandler);
+    #endif
        signal(SIGINT, IntSigHandler);
        signal(SIGTERM, IntSigHandler);
        if (*appData.cmailGameName != NULLCHAR) {
@@ -3207,6 +3221,11 @@ ShutDownFrontEnd()
     unlink(gamePasteFilename);
 }
 
+RETSIGTYPE TermSizeSigHandler(int sig)
+{
+    update_ics_width();
+}
+
 RETSIGTYPE
 IntSigHandler(sig)
      int sig;
@@ -5110,44 +5129,8 @@ void HandleUserMove(w, event, prms, nprms)
      String *prms;
      Cardinal *nprms;
 {
-    int x, y;
-    Boolean saveAnimate;
-    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) {
        if (event->type == ButtonPress) {
            XtPopdown(promotionShell);
@@ -5160,137 +5143,9 @@ void HandleUserMove(w, event, prms, nprms)
        }
     }
 
-    /* [HGM] holdings: next 5 lines: ignore all clicks between board and holdings */
-    if(event->type == ButtonPress
-            && ( x == BOARD_LEFT-1 || x == BOARD_RGHT
-              || x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize
-              || x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize) )
-       return;
-
-    if (fromX == -1) {
-       if (event->type == ButtonPress) {
-           /* First square, prepare to drag */
-           if (OKToStartUserMove(x, y)) {
-               fromX = x;
-               fromY = y;
-               second = 0;
-               DragPieceBegin(event->xbutton.x, event->xbutton.y);
-               if (appData.highlightDragging) {
-                   SetHighlights(x, y, -1, -1);
-               }
-           }
-       }
-       return;
-    }
-
-    /* fromX != -1 */
-    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 */
-           DrawPosition(FALSE, NULL);
-       }
-       if (second) {
-           /* Second up/down in same square; just abort move */
-           second = 0;
-           fromX = fromY = -1;
-           ClearHighlights();
-           gotPremove = 0;
-           ClearPremoveHighlights();
-       } else {
-           /* First upclick in same square; start click-click mode */
-           SetHighlights(x, y, -1, -1);
-       }
-       return;
-    }
-
-    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;
-    if (event->type == ButtonPress) {
-       /* Finish clickclick move */
-       if (appData.animate || appData.highlightLastMove) {
-           SetHighlights(fromX, fromY, toX, toY);
-       } else {
-           ClearHighlights();
-       }
-    } else {
-       /* Finish drag move */
-       if (appData.highlightLastMove) {
-           SetHighlights(fromX, fromY, toX, toY);
-       } else {
-           ClearHighlights();
-       }
-       DragPieceEnd(event->xbutton.x, event->xbutton.y);
-       /* Don't animate move and drag both */
-       appData.animate = FALSE;
-    }
-    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;
-skipClearingFrom:
-    appData.animate = saveAnimate;
-    if (appData.animate || appData.animateDragging) {
-       /* Undo animation damage if needed */
-       DrawPosition(FALSE, NULL);
-    }
+    // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
+    if(event->type == ButtonPress)   LeftClick(Press,   event->xbutton.x, event->xbutton.y);
+    if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
 }
 
 void AnimateUserMove (Widget w, XEvent * event,
@@ -5732,37 +5587,6 @@ void CommentPopUp(title, text)
     commentUp = True;
 }
 
-void AnalysisPopUp(title, text)
-     char *title, *text;
-{
-    Arg args[16];
-    int j;
-    Widget edit;
-
-    if (analysisShell == NULL) {
-       analysisShell = MiscCreate(title, text, False, NULL, 4);
-       XtRealizeWidget(analysisShell);
-       CatchDeleteWindow(analysisShell, "AnalysisPopDown");
-
-    } else {
-       edit = XtNameToWidget(analysisShell, "*form.text");
-       j = 0;
-       XtSetArg(args[j], XtNstring, text); j++;
-       XtSetValues(edit, args, j);
-       j = 0;
-       XtSetArg(args[j], XtNiconName, (XtArgVal) title);   j++;
-       XtSetArg(args[j], XtNtitle, (XtArgVal) title);      j++;
-       XtSetValues(analysisShell, args, j);
-    }
-
-    if (!analysisUp) {
-       XtPopup(analysisShell, XtGrabNone);
-    }
-    XSync(xDisplay, False);
-
-    analysisUp = True;
-}
-
 void CommentCallback(w, client_data, call_data)
      Widget w;
      XtPointer client_data, call_data;
@@ -5801,16 +5625,6 @@ void CommentPopDown()
     commentUp = False;
 }
 
-void AnalysisPopDown()
-{
-    if (!analysisUp) return;
-    XtPopdown(analysisShell);
-    XSync(xDisplay, False);
-    analysisUp = False;
-    if (appData.icsEngineAnalyze) ExitAnalyzeMode();    /* [DM] icsEngineAnalyze */
-}
-
-
 void FileNamePopUp(label, def, proc, openMode)
      char *label;
      char *def;
@@ -6062,7 +5876,7 @@ void PromotionCallback(w, client_data, call_data)
        promoChar = ToLower(name[0]);
     }
 
-    FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
+    UserMoveEvent(fromX, fromY, toX, toY, promoChar);
 
     if (!appData.highlightLastMove || gotPremove) ClearHighlights();
     if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
@@ -6282,7 +6096,6 @@ void ResetProc(w, event, prms, nprms)
      Cardinal *nprms;
 {
     ResetGameEvent();
-    AnalysisPopDown();
 }
 
 int LoadGamePopUp(f, gameNumber, title)
@@ -8700,11 +8513,33 @@ int OutputToProcess(pr, message, count, outError)
      int count;
      int *outError;
 {
+    static int line = 0;
     ChildProc *cp = (ChildProc *) pr;
     int outCount;
 
     if (pr == NoProc)
-      outCount = fwrite(message, 1, count, stdout);
+    {
+        if (appData.noJoin || !appData.useInternalWrap)
+            outCount = fwrite(message, 1, count, stdout);
+        else
+        {
+            int width = get_term_width();
+            int len = wrap(NULL, message, count, width, &line);
+            char *msg = malloc(len);
+            int dbgchk;
+
+            if (!msg)
+                outCount = fwrite(message, 1, count, stdout);
+            else
+            {
+                dbgchk = wrap(msg, message, count, width, &line);
+                if (dbgchk != len && appData.debugMode)
+                    fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
+                outCount = fwrite(msg, 1, dbgchk, stdout);
+                free(msg);
+            }
+        }
+    }
     else
       outCount = write(cp->fdTo, message, count);
 
@@ -9354,7 +9189,7 @@ AnimateMove(board, fromX, fromY, toX, toY)
   damage[toY][toX] = True;
 }
 
-static void
+void
 DragPieceBegin(x, y)
      int x; int y;
 {
@@ -9424,7 +9259,7 @@ DragPieceMove(x, y)
 #endif
 }
 
-static void
+void
 DragPieceEnd(x, y)
      int x; int y;
 {
@@ -9478,3 +9313,38 @@ SetProgramStats( FrontEndProgramStats * stats )
   // [HGM] done, but perhaps backend should call this directly?
     EngineOutputUpdate( stats );
 }
+
+#include <sys/ioctl.h>
+int get_term_width()
+{
+    int fd, default_width;
+
+    fd = STDIN_FILENO;
+    default_width = 79; // this is FICS default anyway...
+
+#if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
+    struct ttysize win;
+    if (!ioctl(fd, TIOCGSIZE, &win))
+        default_width = win.ts_cols;
+#elif defined(TIOCGWINSZ)
+    struct winsize win;
+    if (!ioctl(fd, TIOCGWINSZ, &win))
+        default_width = win.ws_col;
+#endif
+    return default_width;
+}
+
+void update_ics_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;
+}
+
+void NotifyFrontendLogin()
+{
+    update_ics_width();
+}