updated files for a new release, added a shortlog and a diffstat
[xboard.git] / xboard.c
index 86fda44..a27a3be 100644 (file)
--- a/xboard.c
+++ b/xboard.c
@@ -144,6 +144,7 @@ extern char *getenv();
 #include <X11/Shell.h>
 #include <X11/cursorfont.h>
 #include <X11/Xatom.h>
+#include <X11/Xmu/Atoms.h>
 #if USE_XAW3D
 #include <X11/Xaw3d/Dialog.h>
 #include <X11/Xaw3d/Form.h>
@@ -281,7 +282,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));
@@ -428,9 +428,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 );
@@ -1412,7 +1410,22 @@ XtResource clientResources[] = {
        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},
+    { "autoDisplayTags", "autoDisplayTags", XtRBoolean,
+       sizeof(Boolean), XtOffset(AppDataPtr, autoDisplayTags),
        XtRImmediate, (XtPointer) True},
+    { "autoDisplayComment", "autoDisplayComment", XtRBoolean,
+       sizeof(Boolean), XtOffset(AppDataPtr, autoDisplayComment),
+       XtRImmediate, (XtPointer) True},
+    { "pasteSelection", "pasteSelection", XtRBoolean,
+        sizeof(Boolean), XtOffset(AppDataPtr, pasteSelection),
+        XtRImmediate, (XtPointer) False},
 };
 
 XrmOptionDescRec shellOptions[] = {
@@ -1783,9 +1796,13 @@ XrmOptionDescRec shellOptions[] = {
     { "-keepAlive", "keepAlive", XrmoptionSepArg, NULL },
     { "-forceIllegalMoves", "forceIllegalMoves", XrmoptionNoArg, "True" },
     { "-keepLineBreaksICS", "keepLineBreaksICS", XrmoptionSepArg, NULL },
+    { "-wrapContinuationSequence", "wrapContinuationSequence", XrmoptionSepArg, NULL },
+    { "-useInternalWrap", "useInternalWrap", XrmoptionSepArg, NULL },
+    { "-autoDisplayTags", "autoDisplayTags", XrmoptionSepArg, NULL },
+    { "-autoDisplayComment", "autoDisplayComment", XrmoptionSepArg, NULL },
+    { "-pasteSelection", "pasteSelection", XrmoptionSepArg, NULL },
 };
 
-
 XtActionsRec boardActions[] = {
     { "DrawPosition", DrawPositionProc },
     { "HandleUserMove", HandleUserMove },
@@ -1897,7 +1914,6 @@ XtActionsRec boardActions[] = {
     { "TagsPopDown", (XtActionProc) TagsPopDown },
     { "ErrorPopDown", (XtActionProc) ErrorPopDown },
     { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
-    { "AnalysisPopDown", (XtActionProc) AnalysisPopDown },
     { "FileNamePopDown", (XtActionProc) FileNamePopDown },
     { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
     { "GameListPopDown", (XtActionProc) GameListPopDown },
@@ -2774,7 +2790,8 @@ XBoard square size (hint): %d\n\
     widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
     XtSetArg(args[0], XtNtop,    XtChainTop);
     XtSetArg(args[1], XtNbottom, XtChainTop);
-    XtSetValues(menuBarWidget, args, 2);
+    XtSetArg(args[2], XtNright,  XtChainLeft);
+    XtSetValues(menuBarWidget, args, 3);
 
     widgetList[j++] = whiteTimerWidget =
       XtCreateWidget("whiteTime", labelWidgetClass,
@@ -3190,6 +3207,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) {
@@ -5122,44 +5142,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);
@@ -5172,137 +5156,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,
@@ -5744,37 +5600,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;
@@ -5813,16 +5638,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;
@@ -6074,7 +5889,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);
@@ -6294,7 +6109,6 @@ void ResetProc(w, event, prms, nprms)
      Cardinal *nprms;
 {
     ResetGameEvent();
-    AnalysisPopDown();
 }
 
 int LoadGamePopUp(f, gameNumber, title)
@@ -6447,7 +6261,7 @@ SendPositionSelection(Widget w, Atom *selection, Atom *target,
   char *selection_tmp;
 
   if (!selected_fen_position) return False; /* should never happen */
-  if (*target == XA_STRING){
+  if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
     /* note: since no XtSelectionDoneProc was registered, Xt will
      * automatically call XtFree on the value returned.  So have to
      * make a copy of it allocated with XtMalloc */
@@ -6456,9 +6270,22 @@ SendPositionSelection(Widget w, Atom *selection, Atom *target,
 
     *value_return=selection_tmp;
     *length_return=strlen(selection_tmp);
-    *type_return=XA_STRING;
+    *type_return=*target;
     *format_return = 8; /* bits per byte */
     return True;
+  } else if (*target == XA_TARGETS(xDisplay)) {
+    Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
+    targets_tmp[0] = XA_UTF8_STRING(xDisplay);
+    targets_tmp[1] = XA_STRING;
+    *value_return = targets_tmp;
+    *type_return = XA_ATOM;
+    *length_return = 2;
+    *format_return = 8 * sizeof(Atom);
+    if (*format_return > 32) {
+      *length_return *= *format_return / 32;
+      *format_return = 32;
+    }
+    return True;
   } else {
     return False;
   }
@@ -6473,20 +6300,24 @@ void CopyPositionProc(w, event, prms, nprms)
   String *prms;
   Cardinal *nprms;
   {
-    int ret;
-
+    /*
+     * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
+     * have a notion of a position that is selected but not copied.
+     * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
+     */
     if (selected_fen_position) free(selected_fen_position);
     selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
     if (!selected_fen_position) return;
-    ret = XtOwnSelection(menuBarWidget, XA_PRIMARY,
-                        CurrentTime,
-                        SendPositionSelection,
-                        NULL/* lose_ownership_proc */ ,
-                        NULL/* transfer_done_proc */);
-    if (!ret) {
-      free(selected_fen_position);
-      selected_fen_position=NULL;
-    }
+    XtOwnSelection(menuBarWidget, XA_PRIMARY,
+                  CurrentTime,
+                  SendPositionSelection,
+                  NULL/* lose_ownership_proc */ ,
+                  NULL/* transfer_done_proc */);
+    XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
+                  CurrentTime,
+                  SendPositionSelection,
+                  NULL/* lose_ownership_proc */ ,
+                  NULL/* transfer_done_proc */);
   }
 
 /* function called when the data to Paste is ready */
@@ -6509,7 +6340,8 @@ void PastePositionProc(w, event, prms, nprms)
   String *prms;
   Cardinal *nprms;
 {
-    XtGetSelectionValue(menuBarWidget, XA_PRIMARY, XA_STRING,
+    XtGetSelectionValue(menuBarWidget, 
+      appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
       /* (XtSelectionCallbackProc) */ PastePositionCB,
       NULL, /* client_data passed to PastePositionCB */
 
@@ -6528,7 +6360,7 @@ SendGameSelection(Widget w, Atom *selection, Atom *target,
 {
   char *selection_tmp;
 
-  if (*target == XA_STRING){
+  if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
     FILE* f = fopen(gameCopyFilename, "r");
     long len;
     size_t count;
@@ -6545,9 +6377,22 @@ SendGameSelection(Widget w, Atom *selection, Atom *target,
     selection_tmp[len] = NULLCHAR;
     *value_return = selection_tmp;
     *length_return = len;
-    *type_return = XA_STRING;
+    *type_return = *target;
     *format_return = 8; /* bits per byte */
     return True;
+  } else if (*target == XA_TARGETS(xDisplay)) {
+    Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
+    targets_tmp[0] = XA_UTF8_STRING(xDisplay);
+    targets_tmp[1] = XA_STRING;
+    *value_return = targets_tmp;
+    *type_return = XA_ATOM;
+    *length_return = 2;
+    *format_return = 8 * sizeof(Atom);
+    if (*format_return > 32) {
+      *length_return *= *format_return / 32;
+      *format_return = 32;
+    }
+    return True;
   } else {
     return False;
   }
@@ -6567,11 +6412,21 @@ void CopyGameProc(w, event, prms, nprms)
   ret = SaveGameToFile(gameCopyFilename, FALSE);
   if (!ret) return;
 
-  ret = XtOwnSelection(menuBarWidget, XA_PRIMARY,
-                      CurrentTime,
-                      SendGameSelection,
-                      NULL/* lose_ownership_proc */ ,
-                      NULL/* transfer_done_proc */);
+  /*
+   * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
+   * have a notion of a game that is selected but not copied.
+   * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
+   */
+  XtOwnSelection(menuBarWidget, XA_PRIMARY,
+                CurrentTime,
+                SendGameSelection,
+                NULL/* lose_ownership_proc */ ,
+                NULL/* transfer_done_proc */);
+  XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
+                CurrentTime,
+                SendGameSelection,
+                NULL/* lose_ownership_proc */ ,
+                NULL/* transfer_done_proc */);
 }
 
 /* function called when the data to Paste is ready */
@@ -6602,7 +6457,8 @@ void PasteGameProc(w, event, prms, nprms)
   String *prms;
   Cardinal *nprms;
 {
-    XtGetSelectionValue(menuBarWidget, XA_PRIMARY, XA_STRING,
+    XtGetSelectionValue(menuBarWidget,
+      appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
       /* (XtSelectionCallbackProc) */ PasteGameCB,
       NULL, /* client_data passed to PasteGameCB */
 
@@ -7502,8 +7358,6 @@ void ShowThinkingProc(w, event, prms, nprms)
      String *prms;
      Cardinal *nprms;
 {
-    Arg args[16];
-
     appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
     ShowThinkingEvent();
 }
@@ -8398,10 +8252,6 @@ int StartChildProcess(cmdLine, dir, pr)
 
     SetUpChildIO(to_prog, from_prog);
 
-    #ifdef SIGWINCH
-    signal(SIGWINCH, TermSizeSigHandler);
-    #endif
-
     if ((pid = fork()) == 0) {
        /* Child process */
        // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
@@ -8716,11 +8566,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);
 
@@ -9370,7 +9242,7 @@ AnimateMove(board, fromX, fromY, toX, toY)
   damage[toY][toX] = True;
 }
 
-static void
+void
 DragPieceBegin(x, y)
      int x; int y;
 {
@@ -9440,7 +9312,7 @@ DragPieceMove(x, y)
 #endif
 }
 
-static void
+void
 DragPieceEnd(x, y)
      int x; int y;
 {