Merge branch 'master' into gtk
[xboard.git] / xboard.c
index d6821c3..424e2d2 100644 (file)
--- a/xboard.c
+++ b/xboard.c
@@ -1050,7 +1050,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 },
@@ -1257,6 +1257,9 @@ XtResource clientResources[] = {
     { "adjudicateLossThreshold", "adjudicateLossThreshold", XtRInt,
        sizeof(int), XtOffset(AppDataPtr, adjudicateLossThreshold),
        XtRImmediate, (XtPointer) 0},
+    { "adjudicateDrawMoves", "adjudicateDrawMoves", XtRInt,
+       sizeof(int), XtOffset(AppDataPtr, adjudicateDrawMoves),
+       XtRImmediate, (XtPointer) 0},
     { "pgnEventHeader", "pgnEventHeader", XtRString,
         sizeof(String), XtOffset(AppDataPtr, pgnEventHeader),
        XtRImmediate, (XtPointer) "Computer Chess Game" },
@@ -1372,7 +1375,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},
@@ -1426,6 +1429,9 @@ XtResource clientResources[] = {
     { "delayAfterQuit", "delayAfterQuit", XtRInt,
        sizeof(int), XtOffset(AppDataPtr, delayAfterQuit),
        XtRImmediate, (XtPointer) 0},
+    { "keepAlive", "keepAlive", XtRInt,
+       sizeof(int), XtOffset(AppDataPtr, keepAlive),
+       XtRImmediate, (XtPointer) 0},
 };
 
 XrmOptionDescRec shellOptions[] = {
@@ -1725,6 +1731,7 @@ XrmOptionDescRec shellOptions[] = {
     { "-pgnExtendedInfo", "pgnExtendedInfo", XrmoptionSepArg, NULL },
     { "-hideThinkingFromHuman", "hideThinkingFromHuman", XrmoptionSepArg, NULL },
     { "-adjudicateLossThreshold", "adjudicateLossThreshold", XrmoptionSepArg, NULL },
+    { "-adjudicateDrawMoves", "adjudicateDrawMoves", XrmoptionSepArg, NULL },
     { "-pgnEventHeader", "pgnEventHeader", XrmoptionSepArg, NULL },
     { "-firstIsUCI", "firstIsUCI", XrmoptionSepArg, NULL },
     { "-secondIsUCI", "secondIsUCI", XrmoptionSepArg, NULL },
@@ -1792,6 +1799,7 @@ XrmOptionDescRec shellOptions[] = {
     { "-secondOptions", "secondOptions", XrmoptionSepArg, NULL },
     { "-firstNeedsNoncompliantFEN", "firstNeedsNoncompliantFEN", XrmoptionSepArg, NULL },
     { "-secondNeedsNoncompliantFEN", "secondNeedsNoncompliantFEN", XrmoptionSepArg, NULL },
+    { "-keepAlive", "keepAlive", XrmoptionSepArg, NULL },
 };
 
 
@@ -2084,7 +2092,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
@@ -2114,6 +2122,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;
@@ -2173,7 +2194,6 @@ main(argc, argv)
 #endif
 #endif
 
-
     setbuf(stdout, NULL);
     setbuf(stderr, NULL);
     debugFP = stderr;
@@ -2273,6 +2293,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)  {
@@ -4120,14 +4162,18 @@ void HandleUserMove(w, event, prms, nprms)
        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];
-       if ((WhitePawn <= fromP && fromP < WhiteKing && // [HGM] this test should go, as UserMoveTest now does it.
-            WhitePawn <= toP && toP <= WhiteKing) ||   //       For now I made it less critical by exempting King
-           (BlackPawn <= fromP && fromP < BlackKing && //       moves, to not interfere with FRC castlings.
-            BlackPawn <= toP && toP <= BlackKing)) {
+       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) {
@@ -6607,23 +6653,33 @@ char *HostName()
 #endif /* not HAVE_GETHOSTNAME */
 }
 
-gint delayedEventTimerTag = 0;
+guint delayedEventTimerTag = 0;
 DelayedEventCallback delayedEventCallback = 0;
 
 void
 FireDelayedEvent(data)
      gpointer data;
 {
-    delayedEventTimerTag = 0;
-    delayedEventCallback();
+  /* remove timer */
+  g_source_remove(delayedEventTimerTag);
+  delayedEventTimerTag = 0;
+
+  /* call function */
+  delayedEventCallback();
+
+  return;
 }
 
 void
 ScheduleDelayedEvent(cb, millisec)
-     DelayedEventCallback cb; long millisec;
+     DelayedEventCallback cb; guint millisec;
 {
+    if(delayedEventTimerTag && delayedEventCallback == cb)
+       // [HGM] alive: replace, rather than add or flush identical event
+       g_source_remove(delayedEventTimerTag);
     delayedEventCallback = cb;
-    delayedEventTimerTag = gtk_timeout_add(millisec,(GtkFunction) FireDelayedEvent, NULL);
+    delayedEventTimerTag = g_timeout_add(millisec,(GSourceFunc) FireDelayedEvent, NULL);
+    return;
 }
 
 DelayedEventCallback
@@ -6644,14 +6700,14 @@ CancelDelayedEvent()
 {
   if (delayedEventTimerTag)
     {
-      gtk_timeout_remove(delayedEventTimerTag);
+      g_source_remove(delayedEventTimerTag);
       delayedEventTimerTag = 0;
     }
 
   return;
 }
 
-gint loadGameTimerTag = 0;
+guint loadGameTimerTag = 0;
 
 int LoadGameTimerRunning()
 {
@@ -6661,7 +6717,7 @@ int LoadGameTimerRunning()
 int StopLoadGameTimer()
 {
     if (loadGameTimerTag != 0) {
-       gtk_timeout_remove(loadGameTimerTag);
+       g_source_remove(loadGameTimerTag);
        loadGameTimerTag = 0;
        return TRUE;
     } else {
@@ -6673,8 +6729,12 @@ void
 LoadGameTimerCallback(data)
      gpointer data;
 {
-    loadGameTimerTag = 0;
-    AutoPlayGameLoop();
+  /* remove timer */
+  g_source_remove(loadGameTimerTag);
+  loadGameTimerTag = 0;
+
+  AutoPlayGameLoop();
+  return;
 }
 
 void
@@ -6682,12 +6742,13 @@ StartLoadGameTimer(millisec)
      long millisec;
 {
   loadGameTimerTag =
-    gtk_timeout_add( millisec, (GtkFunction) LoadGameTimerCallback, NULL);
+    g_timeout_add( millisec, (GSourceFunc) LoadGameTimerCallback, NULL);
+  return;
 }
 
-gint analysisClockTag = 0;
+guint analysisClockTag = 0;
 
-void
+gboolean
 AnalysisClockCallback(data)
      gpointer data;
 {
@@ -6695,18 +6756,20 @@ AnalysisClockCallback(data)
          || appData.icsEngineAnalyze)
       {
        AnalysisPeriodicEvent(0);
-       StartAnalysisClock();
+       return 1; /* keep on going */
       }
+    return 0; /* stop timer */
 }
 
 void
 StartAnalysisClock()
 {
-    analysisClockTag =
-      gtk_timeout_add( 2000,(GtkFunction) AnalysisClockCallback, NULL);
+  analysisClockTag =
+    g_timeout_add( 2000,(GSourceFunc) AnalysisClockCallback, NULL);
+  return;
 }
 
-gint clockTimerTag = 0;
+guint clockTimerTag = 0;
 
 int ClockTimerRunning()
 {
@@ -6717,7 +6780,7 @@ int StopClockTimer()
 {
     if (clockTimerTag != 0)
       {
-       gtk_timeout_remove(clockTimerTag);
+       g_source_remove(clockTimerTag);
        clockTimerTag = 0;
        return TRUE;
       }
@@ -6731,17 +6794,20 @@ void
 ClockTimerCallback(data)
      gpointer data;
 {
-    clockTimerTag = 0;
-    DecrementClocks();
-    return;
+  /* remove timer */
+  g_source_remove(clockTimerTag);
+  clockTimerTag = 0;
+
+  DecrementClocks();
+  return;
 }
 
 void
 StartClockTimer(millisec)
      long millisec;
 {
-    clockTimerTag = gtk_timeout_add(millisec,(GtkFunction) ClockTimerCallback,NULL);
-    return;
+  clockTimerTag = g_timeout_add(millisec,(GSourceFunc) ClockTimerCallback,NULL);
+  return;
 }
 
 void
@@ -7085,51 +7151,75 @@ typedef struct {
     int lineByLine;
     char *unused;
     InputCallback func;
-    XtInputId xid;
+    guint sid;
     char buf[INPUT_SOURCE_BUF_SIZE];
     VOIDSTAR closure;
 } InputSource;
 
 void
-DoInputCallback(closure, source, xid)
-     caddr_t closure;
-     int *source;
-     XtInputId *xid;
+DoInputCallback(io,cond,data)
+     GIOChannel   *io;
+     GIOCondition  cond;
+     gpointer *data;
 {
-    InputSource *is = (InputSource *) closure;
-    int count;
-    int error;
-    char *p, *q;
+  /* read input from one of the input source (for example a chess program, ICS, etc).
+   * and call a function that will handle the input
+   */
 
-    if (is->lineByLine) {
-       count = read(is->fd, is->unused,
-                    INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
-       if (count <= 0) {
-           (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
-           return;
+  int count; /* how many bytes did we read */
+  int error; 
+  char *p, *q;
+  
+  /* All information (callback function, file descriptor, etc) is
+   * saved in an InputSource structure 
+   */
+  InputSource *is = (InputSource *) data; 
+  
+  if (is->lineByLine) 
+    {
+      count = read(is->fd, is->unused,
+                  INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
+
+      if (count <= 0) 
+       {
+         (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
+         return;
        }
-       is->unused += count;
-       p = is->buf;
-       while (p < is->unused) {
-           q = memchr(p, '\n', is->unused - p);
-           if (q == NULL) break;
-           q++;
-           (is->func)(is, is->closure, p, q - p, 0);
-           p = q;
+      is->unused += count;
+      p = is->buf;
+      /* break input into lines and call the callback function on each
+       * line 
+       */
+      while (p < is->unused) 
+       {
+         q = memchr(p, '\n', is->unused - p);
+         if (q == NULL) break;
+         q++;
+         (is->func)(is, is->closure, p, q - p, 0);
+         p = q;
        }
-       q = is->buf;
-       while (p < is->unused) {
-           *q++ = *p++;
+      /* remember not yet used part of the buffer */
+      q = is->buf;
+      while (p < is->unused) 
+       {
+         *q++ = *p++;
        }
-       is->unused = q;
-    } else {
-       count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
-       if (count == -1)
-         error = errno;
-       else
-         error = 0;
-       (is->func)(is, is->closure, is->buf, count, error);
+      is->unused = q;
+    }
+  else 
+    {
+      /* read maximum length of input buffer and send the whole buffer
+       * to the callback function 
+       */
+      count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
+      if (count == -1)
+       error = errno;
+      else
+       error = 0;
+      (is->func)(is, is->closure, is->buf, count, error);
     }
+  
+  return;
 }
 
 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
@@ -7139,6 +7229,7 @@ InputSourceRef AddInputSource(pr, lineByLine, func, closure)
      VOIDSTAR closure;
 {
     InputSource *is;
+    GIOChannel *channel;
     ChildProc *cp = (ChildProc *) pr;
 
     is = (InputSource *) calloc(1, sizeof(InputSource));
@@ -7151,14 +7242,23 @@ InputSourceRef AddInputSource(pr, lineByLine, func, closure)
        is->kind = cp->kind;
        is->fd = cp->fdFrom;
     }
-    if (lineByLine) {
-       is->unused = is->buf;
-    }
+    if (lineByLine) 
+      is->unused = is->buf;
+    else
+      is->unused = NULL;
 
-    is->xid = XtAppAddInput(appContext, is->fd,
-                           (XtPointer) (XtInputReadMask),
-                           (XtInputCallbackProc) DoInputCallback,
-                           (XtPointer) is);
+//    is->xid = XtAppAddInput(appContext, is->fd,
+//                         (XtPointer) (XtInputReadMask),
+//                         (XtInputCallbackProc) DoInputCallback,
+//                         (XtPointer) is);
+//
+
+    /* TODO: will this work on windows?*/
+    printf("DEBUG: fd=%d %d\n",is->fd,is);
+
+    channel = g_io_channel_unix_new(is->fd);
+    g_io_channel_set_close_on_unref (channel, TRUE);
+    is->sid = g_io_add_watch(channel, G_IO_IN,(GIOFunc) DoInputCallback, is);
     is->closure = closure;
     return (InputSourceRef) is;
 }
@@ -7169,9 +7269,10 @@ RemoveInputSource(isr)
 {
     InputSource *is = (InputSource *) isr;
 
-    if (is->xid == 0) return;
-    XtRemoveInput(is->xid);
-    is->xid = 0;
+    if (is->sid == 0) return;
+    g_source_remove(is->sid);
+    is->sid = 0;
+    return;
 }
 
 int OutputToProcess(pr, message, count, outError)