new developer release
[xboard.git] / xboard.c
index d7ea5a7..1cf2ef2 100644 (file)
--- a/xboard.c
+++ b/xboard.c
@@ -5,7 +5,7 @@
  * Massachusetts. 
  *
  * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
- * 2007, 2008, 2009 Free Software Foundation, Inc.
+ * 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
  *
  * The following terms apply to Digital Equipment Corporation's copyright
  * interest in XBoard:
@@ -49,6 +49,8 @@
  *------------------------------------------------------------------------
  ** See the file ChangeLog for a revision history.  */
 
+#define HIGHDRAG 1
+
 #include "config.h"
 
 #include <stdio.h>
@@ -200,7 +202,9 @@ extern char *getenv();
 // must be moved to xengineoutput.h
 
 void EngineOutputProc P((Widget w, XEvent *event,
- String *prms, Cardinal *nprms));
+                        String *prms, Cardinal *nprms));
+void EvalGraphProc P((Widget w, XEvent *event,
+                     String *prms, Cardinal *nprms));
 
 
 #ifdef __EMX__
@@ -229,6 +233,8 @@ typedef struct {
 } Menu;
 
 int main P((int argc, char **argv));
+FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
+               char *init_path, char *mode, int (*show_entry)(), char **name_return));
 RETSIGTYPE CmailSigHandler P((int sig));
 RETSIGTYPE IntSigHandler P((int sig));
 RETSIGTYPE TermSizeSigHandler P((int sig));
@@ -254,6 +260,8 @@ void HandleUserMove P((Widget w, XEvent *event,
                     String *prms, Cardinal *nprms));
 void AnimateUserMove P((Widget w, XEvent * event,
                     String * params, Cardinal * nParams));
+void HandlePV P((Widget w, XEvent * event,
+                    String * params, Cardinal * nParams));
 void WhiteClock P((Widget w, XEvent *event,
                   String *prms, Cardinal *nprms));
 void BlackClock P((Widget w, XEvent *event,
@@ -349,15 +357,19 @@ void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
+void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
+void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
 void StopObservingProc P((Widget w, XEvent *event, String *prms,
                          Cardinal *nprms));
 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
                          Cardinal *nprms));
+void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
+void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
                         Cardinal *nprms));
 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
@@ -438,6 +450,8 @@ void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms))
 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
+void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
+void GameListOptionsPopDown P(());
 void ShufflePopDown P(());
 void EnginePopDown P(());
 void UciPopDown P(());
@@ -446,6 +460,7 @@ void NewVariantPopDown P(());
 void SettingsPopDown P(());
 void update_ics_width P(());
 int get_term_width P(());
+int CopyMemoProc P(());
 /*
 * XBoard depends on Xt R4 or higher
 */
@@ -466,6 +481,7 @@ Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
   commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
   menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
   ICSInputShell, fileNameShell, askQuestionShell;
+Widget historyShell, evalGraphShell, gameListShell;
 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
 Font clockFontID, coordFontID, countFontID;
@@ -604,9 +620,9 @@ MenuItem modeMenu[] = {
     {N_("Training"), TrainingProc},
     {"----", NothingProc},
     {N_("Show Engine Output"), EngineOutputProc},
-    {N_("Show Evaluation Graph"), NothingProc}, // [HGM] evalgr: not functional yet
+    {N_("Show Evaluation Graph"), EvalGraphProc},
     {N_("Show Game List"), ShowGameListProc},
-    {"Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
+    {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
     {"----", NothingProc},
     {N_("Edit Tags"), EditTagsProc},
     {N_("Edit Comment"), EditCommentProc},
@@ -628,6 +644,7 @@ MenuItem actionMenu[] = {
     {"----", NothingProc},
     {N_("Stop Observing"), StopObservingProc},
     {N_("Stop Examining"), StopExaminingProc},
+    {N_("Upload to Examine"), UploadProc},
     {"----", NothingProc},
     {N_("Adjudicate to White"), AdjuWhiteProc},
     {N_("Adjudicate to Black"), AdjuBlackProc},
@@ -641,6 +658,7 @@ MenuItem stepMenu[] = {
     {N_("Back to Start"), ToStartProc},
     {N_("Forward to End"), ToEndProc},
     {N_("Revert"), RevertProc},
+    {N_("Annotate"), AnnotateProc},
     {N_("Truncate Game"), TruncateGameProc},
     {"----", NothingProc},
     {N_("Move Now"), MoveNowProc},
@@ -656,6 +674,7 @@ MenuItem optionsMenu[] = {
     {N_("Engine #1 Settings ..."), FirstSettingsProc},
     {N_("Engine #2 Settings ..."), SecondSettingsProc},
     {N_("Time Control ..."), TimeControlProc},
+    {N_("Game List ..."), GameListOptionsPopUp},
     {"----", NothingProc},
     {N_("Always Queen"), AlwaysQueenProc},
     {N_("Animate Dragging"), AnimateDraggingProc},
@@ -828,6 +847,8 @@ XtActionsRec boardActions[] = {
     { "DrawPosition", DrawPositionProc },
     { "HandleUserMove", HandleUserMove },
     { "AnimateUserMove", AnimateUserMove },
+    { "HandlePV", HandlePV },
+    { "UnLoadPV", UnLoadPV },
     { "FileNameAction", FileNameAction },
     { "AskQuestionProc", AskQuestionProc },
     { "AskQuestionReplyAction", AskQuestionReplyAction },
@@ -840,6 +861,7 @@ XtActionsRec boardActions[] = {
     { "LoadNextGameProc", LoadNextGameProc },
     { "LoadPrevGameProc", LoadPrevGameProc },
     { "LoadSelectedProc", LoadSelectedProc },
+    { "SetFilterProc", SetFilterProc },
     { "ReloadGameProc", ReloadGameProc },
     { "LoadPositionProc", LoadPositionProc },
     { "LoadNextPositionProc", LoadNextPositionProc },
@@ -864,6 +886,7 @@ XtActionsRec boardActions[] = {
     { "EditPositionProc", EditPositionProc },
     { "TrainingProc", EditPositionProc },
     { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
+    { "EvalGraphProc", EvalGraphProc},       // [HGM] Winboard_x avaluation graph window
     { "ShowGameListProc", ShowGameListProc },
     { "ShowMoveListProc", HistoryShowProc},
     { "EditTagsProc", EditCommentProc },
@@ -883,13 +906,17 @@ XtActionsRec boardActions[] = {
     { "AdjuBlackProc", AdjuBlackProc },
     { "AdjuDrawProc", AdjuDrawProc },
     { "EnterKeyProc", EnterKeyProc },
+    { "UpKeyProc", UpKeyProc },
+    { "DownKeyProc", DownKeyProc },
     { "StopObservingProc", StopObservingProc },
     { "StopExaminingProc", StopExaminingProc },
+    { "UploadProc", UploadProc },
     { "BackwardProc", BackwardProc },
     { "ForwardProc", ForwardProc },
     { "ToStartProc", ToStartProc },
     { "ToEndProc", ToEndProc },
     { "RevertProc", RevertProc },
+    { "AnnotateProc", AnnotateProc },
     { "TruncateGameProc", TruncateGameProc },
     { "MoveNowProc", MoveNowProc },
     { "RetractMoveProc", RetractMoveProc },
@@ -940,15 +967,18 @@ XtActionsRec boardActions[] = {
     { "FileNamePopDown", (XtActionProc) FileNamePopDown },
     { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
     { "GameListPopDown", (XtActionProc) GameListPopDown },
+    { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
     { "PromotionPopDown", (XtActionProc) PromotionPopDown },
     { "HistoryPopDown", (XtActionProc) HistoryPopDown },
     { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
+    { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
     { "ShufflePopDown", (XtActionProc) ShufflePopDown },
     { "EnginePopDown", (XtActionProc) EnginePopDown },
     { "UciPopDown", (XtActionProc) UciPopDown },
     { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
     { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
     { "SettingsPopDown", (XtActionProc) SettingsPopDown },
+    { "CopyMemoProc", (XtActionProc) CopyMemoProc },
 };
 
 char globalTranslations[] =
@@ -981,6 +1011,8 @@ char boardTranslations[] =
    "<Btn1Down>: HandleUserMove() \n \
    <Btn1Up>: HandleUserMove() \n \
    <Btn1Motion>: AnimateUserMove() \n \
+   <Btn3Motion>: HandlePV() \n \
+   <Btn3Up>: PieceMenuPopup(menuB) \n \
    Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
                  PieceMenuPopup(menuB) \n \
    Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
@@ -994,6 +1026,8 @@ char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
 
 char ICSInputTranslations[] =
+    "<Key>Up: UpKeyProc() \n "
+    "<Key>Down: DownKeyProc() \n "
     "<Key>Return: EnterKeyProc() \n";
 
 String xboardResources[] = {
@@ -1244,12 +1278,14 @@ BoardToTop()
 #define JAWS_ARGS
 #define CW_USEDEFAULT (1<<31)
 #define ICS_TEXT_MENU_SIZE 90
+#define DEBUG_FILE "xboard.debug"
 #define SetCurrentDirectory chdir
 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
+#define OPTCHAR "-"
+#define SEPCHAR " "
 
 // these two must some day move to frontend.h, when they are implemented
-Boolean EvalGraphIsUp();
-Boolean MoveHistoryIsUp();
+Boolean GameListIsUp();
 
 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
 #include "args.h"
@@ -1257,6 +1293,8 @@ Boolean MoveHistoryIsUp();
 // front-end part of option handling
 
 // [HGM] This platform-dependent table provides the location for storing the color info
+extern char *crWhite, * crBlack;
+
 void *
 colorVariable[] = {
   &appData.whitePieceColor, 
@@ -1265,20 +1303,36 @@ colorVariable[] = {
   &appData.darkSquareColor, 
   &appData.highlightSquareColor,
   &appData.premoveHighlightColor,
+  &appData.lowTimeWarningColor,
   NULL,
   NULL,
   NULL,
   NULL,
   NULL,
-  NULL,
-  NULL,
-  NULL,
+  &crWhite,
+  &crBlack,
   NULL
 };
 
+// [HGM] font: keep a font for each square size, even non-stndard ones
+#define NUM_SIZES 18
+#define MAX_SIZE 130
+Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
+char *fontTable[NUM_FONTS][MAX_SIZE];
+
 void
 ParseFont(char *name, int number)
 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
+  int size;
+  if(sscanf(name, "size%d:", &size)) {
+    // [HGM] font: font is meant for specific boardSize (likely from settings file);
+    //       defer processing it until we know if it matches our board size
+    if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
+       fontTable[number][size] = strdup(strchr(name, ':')+1);
+       fontValid[number][size] = True;
+    }
+    return;
+  }
   switch(number) {
     case 0: // CLOCK_FONT
        appData.clockFont = strdup(name);
@@ -1292,6 +1346,7 @@ ParseFont(char *name, int number)
     default:
       return;
   }
+  fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
 }
 
 void
@@ -1339,8 +1394,9 @@ SetCommPortDefaults()
 void
 SaveFontArg(FILE *f, ArgDescriptor *ad)
 {
-  char *name;
-  switch((int)ad->argLoc) {
+  char *name, buf[MSG_SIZ];
+  int i, n = (int)ad->argLoc;
+  switch(n) {
     case 0: // CLOCK_FONT
        name = appData.clockFont;
       break;
@@ -1353,7 +1409,14 @@ SaveFontArg(FILE *f, ArgDescriptor *ad)
     default:
       return;
   }
-  fprintf(f, "/%s=%s\n", ad->argName, name);
+  for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
+    if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
+       fontTable[n][squareSize] = strdup(name);
+       fontValid[n][squareSize] = True;
+       break;
+  }
+  for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
+    fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]); 
 }
 
 void
@@ -1364,20 +1427,20 @@ ExportSounds()
 void
 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
 {      // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
-       fprintf(f, "/%s=%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
+       fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
 }
 
 void
 SaveColor(FILE *f, ArgDescriptor *ad)
 {      // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
        if(colorVariable[(int)ad->argLoc])
-       fprintf(f, "/%s=%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
+       fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
 }
 
 void
 SaveBoardSize(FILE *f, char *name, void *addr)
 { // wrapper to shield back-end from BoardSize & sizeInfo
-  fprintf(f, "/%s=%s\n", name, appData.boardSize);
+  fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
 }
 
 void
@@ -1385,20 +1448,43 @@ ParseCommPortSettings(char *s)
 { // no such option in XBoard (yet)
 }
 
+extern Widget engineOutputShell;
+extern Widget tagsShell, editTagsShell;
+void
+GetActualPlacement(Widget wg, WindowPlacement *wp)
+{
+  Arg args[16];
+  Dimension w, h;
+  Position x, y;
+  int i;
+
+  if(!wg) return;
+  
+    i = 0;
+    XtSetArg(args[i], XtNx, &x); i++;
+    XtSetArg(args[i], XtNy, &y); i++;
+    XtSetArg(args[i], XtNwidth, &w); i++;
+    XtSetArg(args[i], XtNheight, &h); i++;
+    XtGetValues(wg, args, i);
+    wp->x = x - 4;
+    wp->y = y - 23;
+    wp->height = h;
+    wp->width = w;
+}
+
 void
 GetWindowCoords()
 { // wrapper to shield use of window handles from back-end (make addressible by number?)
-#if 0
   // In XBoard this will have to wait until awareness of window parameters is implemented
-  GetActualPlacement(hwndMain, &wpMain);
-  GetActualPlacement(hwndConsole, &wpConsole);
-  GetActualPlacement(commentDialog, &wpComment);
-  GetActualPlacement(editTagsDialog, &wpTags);
-  GetActualPlacement(gameListDialog, &wpGameList);
-  GetActualPlacement(moveHistoryDialog, &wpMoveHistory);
-  GetActualPlacement(evalGraphDialog, &wpEvalGraph);
-  GetActualPlacement(engineOutputDialog, &wpEngineOutput);
-#endif
+  GetActualPlacement(shellWidget, &wpMain);
+  if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
+  if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
+  if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
+  if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
+  if(commentShell) GetActualPlacement(commentShell, &wpComment);
+  else             GetActualPlacement(editShell,    &wpComment);
+  if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
+  else      GetActualPlacement(editTagsShell, &wpTags);
 }
 
 void
@@ -1430,18 +1516,6 @@ EnsureOnScreen(int *x, int *y, int minX, int minY)
   return;
 }
 
-Boolean
-MoveHistoryIsUp()
-{
-  return True; // still have to fix this *****************************************************************************
-}
-
-Boolean
-EvalGraphIsUp()
-{
-  return False;
-}
-
 int
 MainWindowUp()
 { // [HGM] args: allows testing if main window is realized from back-end
@@ -1635,49 +1709,18 @@ main(argc, argv)
     char *p;
     XrmDatabase xdb;
     int forceMono = False;
-//define INDIRECTION
-#ifdef INDIRECTION
-    // [HGM] before anything else, expand any indirection files amongst options
-    char *argvCopy[1000]; // 1000 seems enough
-    char newArgs[10000];  // holds actual characters
-    int k = 0;
 
     srandom(time(0)); // [HGM] book: make random truly random
 
-    j = 0;
-    for(i=0; i<argc; i++) {
-       if(j >= 1000-2) { printf(_("too many arguments\n")); exit(-1); }
-//fprintf(stderr, "arg %s\n", argv[i]);
-       if(argv[i][0] != '@') argvCopy[j++] = argv[i]; else {
-           char c;
-           FILE *f = fopen(argv[i]+1, "rb");
-           if(f == NULL) { fprintf(stderr, _("ignore %s\n"), argv[i]); continue; } // do not expand non-existing
-           argvCopy[j++] = newArgs + k; // get ready for first argument from file
-           while((c = fgetc(f)) != EOF) { // each line of file inserts 1 argument in the list
-               if(c == '\n') {
-                   if(j >= 1000-2) { printf(_("too many arguments\n")); exit(-1); }
-                   newArgs[k++] = 0;  // terminate current arg
-                   if(k >= 10000-1) { printf(_("too long arguments\n")); exit(-1); }
-                   argvCopy[j++] = newArgs + k; // get ready for next
-               } else {
-                   if(k >= 10000-1) { printf(_("too long arguments\n")); exit(-1); }
-                   newArgs[k++] = c;
-               }
-           }
-           newArgs[k] = 0;
-           j--;
-           fclose(f);
-       }
-    }
-    argvCopy[j] = NULL;
-    argv = argvCopy;
-    argc = j;
-#endif
-
     setbuf(stdout, NULL);
     setbuf(stderr, NULL);
     debugFP = stderr;
 
+    if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
+       printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
+       exit(0);
+    }
+
     programName = strrchr(argv[0], '/');
     if (programName == NULL)
       programName = argv[0];
@@ -1814,7 +1857,14 @@ main(argc, argv)
        fontPxlSize = szd->fontPxlSize;
        smallLayout = szd->smallLayout;
        tinyLayout = szd->tinyLayout;
+       // [HGM] font: use defaults from settings file if available and not overruled
     }
+    if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
+       appData.clockFont = fontTable[CLOCK_FONT][squareSize];
+    if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
+       appData.font = fontTable[MESSAGE_FONT][squareSize];
+    if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
+       appData.coordFont = fontTable[COORD_FONT][squareSize];
 
     /* Now, using squareSize as a hint, find a good XPM/XIM set size */
     if (strlen(appData.pixmapDirectory) > 0) {
@@ -2166,6 +2216,12 @@ XBoard square size (hint): %d\n\
 
     XtRealizeWidget(shellWidget);
 
+    if(wpMain.x > 0) {
+      XtSetArg(args[0], XtNx, wpMain.x);
+      XtSetArg(args[1], XtNy, wpMain.y);
+      XtSetValues(shellWidget, args, 2);
+    }
+
     /*
      * Correct the width of the message and title widgets.
      * It is not known why some systems need the extra fudge term.
@@ -2427,10 +2483,24 @@ XBoard square size (hint): %d\n\
 
     /* Why is the following needed on some versions of X instead
      * of a translation? */
-    XtAddEventHandler(boardWidget, ExposureMask, False,
+    XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
                      (XtEventHandler) EventProc, NULL);
     /* end why */
 
+    /* [AS] Restore layout */
+    if( wpMoveHistory.visible ) {
+      HistoryPopUp();
+    }
+
+    if( wpEvalGraph.visible ) 
+      {
+       EvalGraphPopUp();
+      };
+    
+    if( wpEngineOutput.visible ) {
+      EngineOutputPopUp();
+    }
+
     InitBackEnd2();
 
     if (errorExitStatus == -1) {
@@ -2557,6 +2627,12 @@ GreyRevert(grey)
     } else {
       XtSetSensitive(w, !grey);
     }
+    w = XtNameToWidget(menuBarWidget, "menuStep.Annotate");
+    if (w == NULL) {
+      DisplayError("menuStep.Annotate", 0);
+    } else {
+      XtSetSensitive(w, !grey);
+    }
 }
 
 void
@@ -2592,6 +2668,7 @@ Enables icsEnables[] = {
     { "menuOptions.Hide Thinking", False },
     { "menuOptions.Ponder Next Move", False },
 #endif
+    { "menuStep.Annotate", False },
     { NULL, False }
 };
 
@@ -2607,6 +2684,7 @@ Enables ncpEnables[] = {
     { "menuMode.ICS Input Box", False },
     { "Action", False },
     { "menuStep.Revert", False },
+    { "menuStep.Annotate", False },
     { "menuStep.Move Now", False },
     { "menuStep.Retract Move", False },
     { "menuOptions.Auto Comment", False },
@@ -2635,7 +2713,9 @@ Enables gnuEnables[] = {
     { "menuAction.Adjourn", False },
     { "menuAction.Stop Examining", False },
     { "menuAction.Stop Observing", False },
+    { "menuAction.Upload to Examine", False },
     { "menuStep.Revert", False },
+    { "menuStep.Annotate", False },
     { "menuOptions.Auto Comment", False },
     { "menuOptions.Auto Observe", False },
     { "menuOptions.Auto Raise Board", False },
@@ -2796,6 +2876,51 @@ SetMachineThinkingEnables()
   }
 }
 
+// [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
+#define HISTORY_SIZE 64\r
+static char *history[HISTORY_SIZE];\r
+int histIn = 0, histP = 0;\r
+\r
+void\r
+SaveInHistory(char *cmd)\r
+{\r
+  if (history[histIn] != NULL) {\r
+    free(history[histIn]);\r
+    history[histIn] = NULL;\r
+  }\r
+  if (*cmd == NULLCHAR) return;\r
+  history[histIn] = StrSave(cmd);\r
+  histIn = (histIn + 1) % HISTORY_SIZE;\r
+  if (history[histIn] != NULL) {\r
+    free(history[histIn]);\r
+    history[histIn] = NULL;\r
+  }\r
+  histP = histIn;\r
+}\r
+\r
+char *\r
+PrevInHistory(char *cmd)\r
+{\r
+  int newhp;\r
+  if (histP == histIn) {\r
+    if (history[histIn] != NULL) free(history[histIn]);\r
+    history[histIn] = StrSave(cmd);\r
+  }\r
+  newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;\r
+  if (newhp == histIn || history[newhp] == NULL) return NULL;\r
+  histP = newhp;\r
+  return history[histP];\r
+}\r
+\r
+char *\r
+NextInHistory()\r
+{\r
+  if (histP == histIn) return NULL;\r
+  histP = (histP + 1) % HISTORY_SIZE;\r
+  return history[histP];   \r
+}
+// end of borrowed code\r
+\r
 #define Abs(n) ((n)<0 ? -(n) : (n))
 
 /*
@@ -3658,39 +3783,18 @@ void PieceMenuPopup(w, event, params, num_params)
      String *params;
      Cardinal *num_params;
 {
-    String whichMenu;
-    if (event->type != ButtonPress) return;
-    if (errorUp) ErrorPopDown();
-    switch (gameMode) {
-      case EditPosition:
-      case IcsExamining:
-       whichMenu = params[0];
-       break;
-      case IcsPlayingWhite:
-      case IcsPlayingBlack:
-      case EditGame:
-      case MachinePlaysWhite:
-      case MachinePlaysBlack:
-       if (appData.testLegality &&
-           gameInfo.variant != VariantBughouse &&
-           gameInfo.variant != VariantCrazyhouse) return;
-       SetupDropMenu();
-       whichMenu = "menuD";
-       break;
-      default:
-       return;
+    String whichMenu; int menuNr;
+    if (event->type == ButtonRelease)
+        menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY); 
+    else if (event->type == ButtonPress)
+        menuNr = RightClick(Press,   event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
+    switch(menuNr) {
+      case 0: whichMenu = params[0]; break;
+      case 1: SetupDropMenu(); whichMenu = "menuD"; break;
+      case 2:
+      case -1: if (errorUp) ErrorPopDown();
+      default: return;
     }
-
-    if (((pmFromX = EventToSquare(event->xbutton.x, BOARD_WIDTH)) < 0) ||
-       ((pmFromY = EventToSquare(event->xbutton.y, BOARD_HEIGHT)) < 0)) {
-       pmFromX = pmFromY = -1;
-       return;
-    }
-    if (flipView)
-      pmFromX = BOARD_WIDTH - 1 - pmFromX;
-    else
-      pmFromY = BOARD_HEIGHT - 1 - pmFromY;
-
     XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
 }
 
@@ -3798,14 +3902,18 @@ SetHighlights(fromX, fromY, toX, toY)
        if (hi1X >= 0 && hi1Y >= 0) {
            drawHighlight(hi1X, hi1Y, lineGC);
        }
+    } // [HGM] first erase both, then draw new!
+    if (hi2X != toX || hi2Y != toY) {
+       if (hi2X >= 0 && hi2Y >= 0) {
+           drawHighlight(hi2X, hi2Y, lineGC);
+       }
+    }
+    if (hi1X != fromX || hi1Y != fromY) {
        if (fromX >= 0 && fromY >= 0) {
            drawHighlight(fromX, fromY, highlineGC);
        }
     }
     if (hi2X != toX || hi2Y != toY) {
-       if (hi2X >= 0 && hi2Y >= 0) {
-           drawHighlight(hi2X, hi2Y, lineGC);
-       }
        if (toX >= 0 && toY >= 0) {
            drawHighlight(toX, toY, highlineGC);
        }
@@ -4163,6 +4271,10 @@ void DrawSquare(row, column, piece, do_flash)
                        x + 2, y + font_ascent + 1, string, 1);
        }
     }
+    if(marker[row][column]) {
+       XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC, 
+               x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
+    }
 }
 
 
@@ -4180,6 +4292,8 @@ void EventProc(widget, unused, event)
        if (event->xexpose.count > 0) return;  /* no clipping is done */
        XDrawPosition(widget, True, NULL);
        break;
+      case MotionNotify:
+        if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;\r
       default:
        return;
     }
@@ -4260,6 +4374,36 @@ static int check_castle_draw(newb, oldb, rrow, rcol)
     return 0;
 }
 
+// [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph 
+void DrawSeekAxis( int x, int y, int xTo, int yTo )
+{
+      XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
+}
+
+void DrawSeekBackground( int left, int top, int right, int bottom )
+{
+    XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
+}
+
+void DrawSeekText(char *buf, int x, int y)
+{
+    XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
+}
+
+void DrawSeekDot(int x, int y, int colorNr)
+{
+    int square = colorNr & 0x80;
+    GC color;
+    colorNr &= 0x7F;
+    color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
+    if(square)
+       XFillRectangle(xDisplay, xBoardWindow, color,
+               x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
+    else
+       XFillArc(xDisplay, xBoardWindow, color, 
+               x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
+}
+
 static int damage[BOARD_RANKS][BOARD_FILES];
 
 /*
@@ -4277,6 +4421,8 @@ void XDrawPosition(w, repaint, board)
     Arg args[16];
     int rrow, rcol;
 
+    if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
+
     if (board == NULL) {
        if (!lastBoardValid) return;
        board = lastBoard;
@@ -4416,6 +4562,12 @@ void AnimateUserMove (Widget w, XEvent * event,
     DragPieceMove(event->xmotion.x, event->xmotion.y);
 }
 
+void HandlePV (Widget w, XEvent * event,
+                     String * params, Cardinal * nParams)
+{   // [HGM] pv: walk PV
+    MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
+}
+
 Widget CommentCreate(name, text, mutable, callback, lines)
      char *name, *text;
      int /*Boolean*/ mutable;
@@ -4560,6 +4712,14 @@ Widget CommentCreate(name, text, mutable, callback, lines)
 #endif /*!NOTDEF*/
        if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
     }
+
+    if(wpComment.width > 0) {
+      commentX = wpComment.x;
+      commentY = wpComment.y;
+      commentW = wpComment.width;
+      commentH = wpComment.height;
+    }
+
     j = 0;
     XtSetArg(args[j], XtNheight, commentH);  j++;
     XtSetArg(args[j], XtNwidth, commentW);  j++;
@@ -4800,6 +4960,7 @@ void ICSInputSendText()
     j = 0;
     XtSetArg(args[j], XtNstring, &val); j++;
     XtGetValues(edit, args, j);
+    SaveInHistory(val);
     SendMultiLineToICS(val);
     XtCallActionProc(edit, "select-all", NULL, NULL, 0);
     XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
@@ -4902,45 +5063,14 @@ void FileNamePopUp(label, def, proc, openMode)
 
     fileProc = proc;           /* I can't see a way not */
     fileOpenMode = openMode;   /*   to use globals here */
-
-    i = 0;
-    XtSetArg(args[i], XtNresizable, True); i++;
-    XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
-    XtSetArg(args[i], XtNtitle, XtNewString(_("File name prompt"))); i++;
-    fileNameShell = popup =
-      XtCreatePopupShell("File name prompt", transientShellWidgetClass,
-                        shellWidget, args, i);
-
-    layout =
-      XtCreateManagedWidget(layoutName, formWidgetClass, popup,
-                           layoutArgs, XtNumber(layoutArgs));
-
-    i = 0;
-    XtSetArg(args[i], XtNlabel, label); i++;
-    XtSetArg(args[i], XtNvalue, def); i++;
-    XtSetArg(args[i], XtNborderWidth, 0); i++;
-    dialog = XtCreateManagedWidget("fileName", dialogWidgetClass,
-                                  layout, args, i);
-
-    XawDialogAddButton(dialog, _("ok"), FileNameCallback, (XtPointer) dialog);
-    XawDialogAddButton(dialog, _("cancel"), FileNameCallback,
-                      (XtPointer) dialog);
-
-    XtRealizeWidget(popup);
-    CatchDeleteWindow(popup, "FileNamePopDown");
-
-    XQueryPointer(xDisplay, xBoardWindow, &root, &child,
-                 &x, &y, &win_x, &win_y, &mask);
-
-    XtSetArg(args[0], XtNx, x - 10);
-    XtSetArg(args[1], XtNy, y - 30);
-    XtSetValues(popup, args, 2);
-
-    XtPopup(popup, XtGrabExclusive);
-    filenameUp = True;
-
-    edit = XtNameToWidget(dialog, "*value");
-    XtSetKeyboardFocus(popup, edit);
+    {   // [HGM] use file-selector dialog stolen from Ghostview
+       char *name;
+       int index; // this is not supported yet
+       FILE *f;
+       if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
+           NULL, openMode, NULL, &name))
+               (void) (*fileProc)(f, index=0, name);
+    }
 }
 
 void FileNamePopDown()
@@ -5500,9 +5630,9 @@ void MailMoveProc(w, event, prms, nprms)
 }
 
 /* this variable is shared between CopyPositionProc and SendPositionSelection */
-static char *selected_fen_position=NULL;
+char *selected_fen_position=NULL;
 
-static Boolean
+Boolean
 SendPositionSelection(Widget w, Atom *selection, Atom *target,
                 Atom *type_return, XtPointer *value_return,
                 unsigned long *length_return, int *format_return)
@@ -5554,6 +5684,7 @@ void CopyPositionProc(w, event, prms, nprms)
      * have a notion of a position that is selected but not copied.
      * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
      */
+    if(gameMode == EditPosition) EditPositionDone(TRUE);
     if (selected_fen_position) free(selected_fen_position);
     selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
     if (!selected_fen_position) return;
@@ -6008,6 +6139,55 @@ void EnterKeyProc(w, event, prms, nprms)
       ICSInputSendText();
 }
 
+void UpKeyProc(w, event, prms, nprms)
+     Widget w;
+     XEvent *event;
+     String *prms;
+     Cardinal *nprms;
+{   // [HGM] input: let up-arrow recall previous line from history
+    Widget edit;
+    int j;
+    Arg args[16];
+    String val;
+    XawTextBlock t;
+
+    if (!ICSInputBoxUp) return;
+    edit = XtNameToWidget(ICSInputShell, "*form.text");
+    j = 0;
+    XtSetArg(args[j], XtNstring, &val); j++;
+    XtGetValues(edit, args, j);
+    val = PrevInHistory(val);
+    XtCallActionProc(edit, "select-all", NULL, NULL, 0);
+    XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
+    if(val) {
+       t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
+       XawTextReplace(edit, 0, 0, &t);
+       XawTextSetInsertionPoint(edit, 9999);
+    }
+}
+
+void DownKeyProc(w, event, prms, nprms)
+     Widget w;
+     XEvent *event;
+     String *prms;
+     Cardinal *nprms;
+{   // [HGM] input: let down-arrow recall next line from history
+    Widget edit;
+    String val;
+    XawTextBlock t;
+
+    if (!ICSInputBoxUp) return;
+    edit = XtNameToWidget(ICSInputShell, "*form.text");
+    val = NextInHistory();
+    XtCallActionProc(edit, "select-all", NULL, NULL, 0);
+    XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
+    if(val) {
+       t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
+       XawTextReplace(edit, 0, 0, &t);
+       XawTextSetInsertionPoint(edit, 9999);
+    }
+}
+
 void StopObservingProc(w, event, prms, nprms)
      Widget w;
      XEvent *event;
@@ -6026,6 +6206,15 @@ void StopExaminingProc(w, event, prms, nprms)
     StopExaminingEvent();
 }
 
+void UploadProc(w, event, prms, nprms)
+     Widget w;
+     XEvent *event;
+     String *prms;
+     Cardinal *nprms;
+{
+    UploadGameEvent();
+}
+
 
 void ForwardProc(w, event, prms, nprms)
      Widget w;
@@ -6070,7 +6259,16 @@ void RevertProc(w, event, prms, nprms)
      String *prms;
      Cardinal *nprms;
 {
-    RevertEvent();
+    RevertEvent(False);
+}
+
+void AnnotateProc(w, event, prms, nprms)
+     Widget w;
+     XEvent *event;
+     String *prms;
+     Cardinal *nprms;
+{
+    RevertEvent(True);
 }
 
 void TruncateGameProc(w, event, prms, nprms)
@@ -7520,8 +7718,11 @@ int StartChildProcess(cmdLine, dir, pr)
     strcpy(buf, cmdLine);
     p = buf;
     for (;;) {
+       while(*p == ' ') p++;
        argv[i++] = p;
-       p = strchr(p, ' ');
+       if(*p == '"' || *p == '\'')
+            p = strchr(++argv[i-1], *p);
+       else p = strchr(p, ' ');
        if (p == NULL) break;
        *p++ = NULLCHAR;
     }
@@ -8580,7 +8781,7 @@ DragPieceMove(x, y)
     corner.x = x - player.mouseDelta.x;
     corner.y = y - player.mouseDelta.y;
     AnimationFrame(&player, &corner, player.dragPiece);
-#if HIGHDRAG
+#if HIGHDRAG*0
     if (appData.highlightDragging) {
        int boardX, boardY;
        BoardSquare(x, y, &boardX, &boardY);