Move clock-click code to back-end
[xboard.git] / xboard.c
index 3a769e3..76c3b77 100644 (file)
--- a/xboard.c
+++ b/xboard.c
@@ -60,6 +60,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <pwd.h>
+#include <math.h>
 
 #if !OMIT_SOCKETS
 # if HAVE_SYS_SOCKET_H
@@ -409,10 +410,11 @@ void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
                              Cardinal *nprms));
 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
                              Cardinal *nprms));
+void HighlightArrowProc P((Widget w, XEvent *event, String *prms,
+                             Cardinal *nprms));
 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
-void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
-                        Cardinal *nprms));
+void OneClickProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
                         Cardinal *nprms));
 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
@@ -471,6 +473,9 @@ void SettingsPopDown P(());
 void update_ics_width P(());
 int get_term_width P(());
 int CopyMemoProc P(());
+void DrawArrowHighlight P((int fromX, int fromY, int toX,int toY));
+Boolean IsDrawArrowEnabled P(());
+
 /*
 * XBoard depends on Xt R4 or higher
 */
@@ -592,60 +597,59 @@ static Pixmap xpmMask[BlackKing + 1];
 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
 
 MenuItem fileMenu[] = {
-    {N_("New Game"),             "New Game", ResetProc},
-    {N_("New Shuffle Game ..."), "New Shuffle Game", ShuffleMenuProc},
-    {N_("New Variant ..."),      "New Variant", NewVariantProc},      // [HGM] variant: not functional yet
+    {N_("New Game        Ctrl+N"),        "New Game", ResetProc},
+    {N_("New Shuffle Game ..."),          "New Shuffle Game", ShuffleMenuProc},
+    {N_("New Variant ...   Alt+Shift+V"), "New Variant", NewVariantProc},      // [HGM] variant: not functional yet
     {"----", NULL, NothingProc},
-    {N_("Load Game"),     "Load Game", LoadGameProc},
-    {N_("Load Position"), "Load Position", LoadPositionProc},
+    {N_("Load Game       Ctrl+O"),        "Load Game", LoadGameProc},
+    {N_("Load Position    Ctrl+Shift+O"), "Load Position", LoadPositionProc},
 //    {N_("Load Next Game"), "Load Next Game", LoadNextGameProc},
 //    {N_("Load Previous Game"), "Load Previous Game", LoadPrevGameProc},
 //    {N_("Reload Same Game"), "Reload Same Game", ReloadGameProc},
+    {N_("Next Position     Shift+PgDn"), "Load Next Position", LoadNextPositionProc},
+    {N_("Prev Position     Shift+PgUp"), "Load Previous Position", LoadPrevPositionProc},
     {"----", NULL, NothingProc},
-//    {N_("Load Next Position"), "Load Next Position", LoadNextPositionProc},
-//    {N_("Load Previous Position"), "Load Previous Position", LoadPrevPositionProc},
 //    {N_("Reload Same Position"), "Reload Same Position", ReloadPositionProc},
-    {N_("Save Game"),     "Save Game", SaveGameProc},
-    {N_("Save Position"), "Save Position", SavePositionProc},
+    {N_("Save Game       Ctrl+S"),        "Save Game", SaveGameProc},
+    {N_("Save Position    Ctrl+Shift+S"), "Save Position", SavePositionProc},
     {"----", NULL, NothingProc},
     {N_("Mail Move"),            "Mail Move", MailMoveProc},
     {N_("Reload CMail Message"), "Reload CMail Message", ReloadCmailMsgProc},
     {"----", NULL, NothingProc},
-    {N_("Exit"), "Exit", QuitProc},
+    {N_("Quit                 Ctr+Q"), "Exit", QuitProc},
     {NULL, NULL, NULL}
 };
 
 MenuItem editMenu[] = {
-    {N_("Copy Game"),      "Copy Game", CopyGameProc},
-    {N_("Copy Position"),  "Copy Position", CopyPositionProc},
+    {N_("Copy Game    Ctrl+C"),        "Copy Game", CopyGameProc},
+    {N_("Copy Position Ctrl+Shift+C"), "Copy Position", CopyPositionProc},
     {"----", NULL, NothingProc},
-    {N_("Paste Game"),     "Paste Game", PasteGameProc},
-    {N_("Paste Position"), "Paste Position", PastePositionProc},
+    {N_("Paste Game    Ctrl+V"),        "Paste Game", PasteGameProc},
+    {N_("Paste Position Ctrl+Shift+V"), "Paste Position", PastePositionProc},
     {"----", NULL, NothingProc},
-    {N_("Edit Game"),      "Edit Game", EditGameProc},
-    {N_("Edit Position"),  "Edit Position", EditPositionProc},
+    {N_("Edit Game      Ctrl+E"),        "Edit Game", EditGameProc},
+    {N_("Edit Position   Ctrl+Shift+E"), "Edit Position", EditPositionProc},
+    {N_("Edit Tags"),                    "Edit Tags", EditTagsProc},
+    {N_("Edit Comment"),                 "Edit Comment", EditCommentProc},
     {"----", NULL, NothingProc},
-    {N_("Edit Tags"),      "Edit Tags", EditTagsProc},
-    {N_("Edit Comment"),   "Edit Comment", EditCommentProc},
+    {N_("Revert              Home"), "Revert", RevertProc},
+    {N_("Annotate"),                 "Annotate", AnnotateProc},
+    {N_("Truncate Game  End"),       "Truncate Game", TruncateGameProc},
     {"----", NULL, NothingProc},
-    {N_("Revert"),         "Revert", RevertProc},
-    {N_("Annotate"),       "Annotate", AnnotateProc},
-    {N_("Truncate Game"),  "Truncate Game", TruncateGameProc},
-    {"----", NULL, NothingProc},
-    {N_("Backward"),       "Backward", BackwardProc},
-    {N_("Forward"),        "Forward", ForwardProc},
-    {N_("Back to Start"),  "Back to Start", ToStartProc},
-    {N_("Forward to End"), "Forward to End", ToEndProc},
+    {N_("Backward         Alt+Left"),   "Backward", BackwardProc},
+    {N_("Forward           Alt+Right"), "Forward", ForwardProc},
+    {N_("Back to Start     Alt+Home"),  "Back to Start", ToStartProc},
+    {N_("Forward to End Alt+End"),      "Forward to End", ToEndProc},
     {NULL, NULL, NULL}
 };
 
 MenuItem viewMenu[] = {
-    {N_("Flip View"),        "Flip View", FlipViewProc},
+    {N_("Flip View             F2"),         "Flip View", FlipViewProc},
     {"----", NULL, NothingProc},
-    {N_("Engine Output"),    "Show Engine Output", EngineOutputProc},
-    {N_("Evaluation Graph"), "Show Evaluation Graph", EvalGraphProc},
-    {N_("Game List"),        "Show Game List", ShowGameListProc},
-    {N_("Move History"),     "Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
+    {N_("Engine Output      Alt+Shift+O"),   "Show Engine Output", EngineOutputProc},
+    {N_("Move History       Alt+Shift+H"),   "Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
+    {N_("Evaluation Graph  Alt+Shift+E"),    "Show Evaluation Graph", EvalGraphProc},
+    {N_("Game List            Alt+Shift+G"), "Show Game List", ShowGameListProc},
     {"----", NULL, NothingProc},
     {N_("Tags"),             "Show Tags", EditTagsProc},
     {N_("Comments"),         "Show Comments", EditCommentProc},
@@ -654,33 +658,33 @@ MenuItem viewMenu[] = {
 };
 
 MenuItem modeMenu[] = {
-    {N_("Machine White"), "Machine White", MachineWhiteProc},
-    {N_("Machine Black"), "Machine Black", MachineBlackProc},
-    {N_("Two Machines"),  "Two Machines", TwoMachinesProc},
-    {N_("Analysis Mode"), "Analysis Mode", AnalyzeModeProc},
-    {N_("Analyze File"),  "Analyze File", AnalyzeFileProc },
-    {N_("Edit Game"),     "Edit Game", EditGameProc},
-    {N_("Edit Position"), "Edit Position", EditPositionProc},
+    {N_("Machine White  Ctrl+W"), "Machine White", MachineWhiteProc},
+    {N_("Machine Black  Ctrl+B"), "Machine Black", MachineBlackProc},
+    {N_("Two Machines   Ctrl+T"), "Two Machines", TwoMachinesProc},
+    {N_("Analysis Mode  Ctrl+A"), "Analysis Mode", AnalyzeModeProc},
+    {N_("Analyze File      Ctrl+F"), "Analyze File", AnalyzeFileProc },
+    {N_("Edit Game         Ctrl+E"), "Edit Game", EditGameProc},
+    {N_("Edit Position      Ctrl+Shift+E"), "Edit Position", EditPositionProc},
     {N_("Training"),      "Training", TrainingProc},
     {N_("ICS Client"),    "ICS Client", IcsClientProc},
     {"----", NULL, NothingProc},
-    {N_("Pause"),         "Pause", PauseProc},
+    {N_("Pause               Pause"),         "Pause", PauseProc},
     {NULL, NULL, NULL}
 };
 
 MenuItem actionMenu[] = {
-    {N_("Accept"),    "Accept", AcceptProc},
-    {N_("Decline"),   "Decline", DeclineProc},
-    {N_("Rematch"),   "Rematch", RematchProc},
+    {N_("Accept             F3"), "Accept", AcceptProc},
+    {N_("Decline            F4"), "Decline", DeclineProc},
+    {N_("Rematch           F12"), "Rematch", RematchProc},
     {"----", NULL, NothingProc},
-    {N_("Call Flag"), "Call Flag", CallFlagProc},
-    {N_("Draw"),      "Draw", DrawProc},
-    {N_("Adjourn"),   "Adjourn", AdjournProc},
-    {N_("Abort"),     "Abort", AbortProc},
-    {N_("Resign"),    "Resign", ResignProc},
+    {N_("Call Flag          F5"), "Call Flag", CallFlagProc},
+    {N_("Draw                F6"), "Draw", DrawProc},
+    {N_("Adjourn            F7"),  "Adjourn", AdjournProc},
+    {N_("Abort                F8"),"Abort", AbortProc},
+    {N_("Resign              F9"), "Resign", ResignProc},
     {"----", NULL, NothingProc},
-    {N_("Stop Observing"),      "Stop Observing", StopObservingProc},
-    {N_("Stop Examining"),      "Stop Examining", StopExaminingProc},
+    {N_("Stop Observing  F10"), "Stop Observing", StopObservingProc},
+    {N_("Stop Examining  F11"), "Stop Examining", StopExaminingProc},
     {N_("Upload to Examine"),   "Upload to Examine", UploadProc},
     {"----", NULL, NothingProc},
     {N_("Adjudicate to White"), "Adjudicate to White", AdjuWhiteProc},
@@ -693,22 +697,25 @@ MenuItem engineMenu[] = {
     {N_("Engine #1 Settings ..."), "Engine #1 Settings", FirstSettingsProc},
     {N_("Engine #2 Settings ..."), "Engine #2 Settings", SecondSettingsProc},
     {"----", NULL, NothingProc},
-    {N_("Move Now"),     "Move Now", MoveNowProc},
-    {N_("Retract Move"), "Retract Move", RetractMoveProc},
+    {N_("Hint"), "Hint", HintProc},
+    {N_("Book"), "Book", BookProc},
+    {"----", NULL, NothingProc},
+    {N_("Move Now     Ctrl+M"),     "Move Now", MoveNowProc},
+    {N_("Retract Move  Ctrl+X"), "Retract Move", RetractMoveProc},
     {NULL, NULL, NULL}
 };
 
 MenuItem optionsMenu[] = {
-    {N_("Time Control ..."),  "Time Control", TimeControlProc},
-    {N_("Common Engine ..."), "Common Engine", UciMenuProc},
-    {N_("Adjudications ..."), "Adjudications", EngineMenuProc},
-    {N_("Game List ..."),     "Game List", GameListOptionsPopUp},
+    {N_("Time Control ...       Alt+Shift+T"), "Time Control", TimeControlProc},
+    {N_("Common Engine ...  Alt+Shift+U"),     "Common Engine", UciMenuProc},
+    {N_("Adjudications ...      Alt+Shift+J"), "Adjudications", EngineMenuProc},
+    {N_("Game List ..."),    "Game List", GameListOptionsPopUp},
     {"----", NULL, NothingProc},
-    {N_("Always Queen"),     "Always Queen", AlwaysQueenProc},
+    {N_("Always Queen        Ctrl+Shift+Q"),   "Always Queen", AlwaysQueenProc},
     {N_("Animate Dragging"), "Animate Dragging", AnimateDraggingProc},
-    {N_("Animate Moving"),   "Animate Moving", AnimateMovingProc},
+    {N_("Animate Moving      Ctrl+Shift+A"),   "Animate Moving", AnimateMovingProc},
     {N_("Auto Comment"),     "Auto Comment", AutocommProc},
-    {N_("Auto Flag"),        "Auto Flag", AutoflagProc},
+    {N_("Auto Flag               Ctrl+Shift+F"), "Auto Flag", AutoflagProc},
     {N_("Auto Flip View"),   "Auto Flip View", AutoflipProc},
     {N_("Auto Observe"),     "Auto Observe", AutobsProc},
     {N_("Auto Raise Board"), "Auto Raise Board", AutoraiseProc},
@@ -720,18 +727,19 @@ MenuItem optionsMenu[] = {
     {N_("Highlight Dragging"),    "Highlight Dragging", HighlightDraggingProc},
 #endif
     {N_("Highlight Last Move"),   "Highlight Last Move", HighlightLastMoveProc},
+    {N_("Highlight With Arrow"),  "Arrow", HighlightArrowProc},
     {N_("Move Sound"),            "Move Sound", MoveSoundProc},
     {N_("ICS Alarm"),             "ICS Alarm", IcsAlarmProc},
-    {N_("Old Save Style"),        "Old Save Style", OldSaveStyleProc},
+    {N_("One-Click Moving"),      "OneClick", OneClickProc},
     {N_("Periodic Updates"),      "Periodic Updates", PeriodicUpdatesProc},
-    {N_("Ponder Next Move"),      "Ponder Next Move", PonderNextMoveProc},
+    {N_("Ponder Next Move  Ctrl+Shift+P"), "Ponder Next Move", PonderNextMoveProc},
     {N_("Popup Exit Message"),    "Popup Exit Message", PopupExitMessageProc},
     {N_("Popup Move Errors"),     "Popup Move Errors", PopupMoveErrorsProc},
     {N_("Premove"),               "Premove", PremoveProc},
     {N_("Quiet Play"),            "Quiet Play", QuietPlayProc},
     {N_("Show Coords"),           "Show Coords", ShowCoordsProc},
-    {N_("Hide Thinking"),         "Hide Thinking", HideThinkingProc},
-    {N_("Test Legality"),         "Test Legality", TestLegalityProc},
+    {N_("Hide Thinking        Ctrl+Shift+H"),   "Hide Thinking", HideThinkingProc},
+    {N_("Test Legality          Ctrl+Shift+L"), "Test Legality", TestLegalityProc},
     {"----", NULL, NothingProc},
     {N_("Save Settings Now"),     "Save Settings Now", SaveSettingsProc},
     {N_("Save Settings on Exit"), "Save Settings on Exit", SaveOnExitProc},
@@ -739,11 +747,8 @@ MenuItem optionsMenu[] = {
 };
 
 MenuItem helpMenu[] = {
-    {N_("Info XBoard"), "Info XBoard", InfoProc},
-    {N_("Man XBoard"),  "Man XBoard", ManProc},
-    {"----", NULL, NothingProc},
-    {N_("Hint"), "Hint", HintProc},
-    {N_("Book"), "Book", BookProc},
+    {N_("Info XBoard"),     "Info XBoard", InfoProc},
+    {N_("Man XBoard   F1"), "Man XBoard", ManProc},
     {"----", NULL, NothingProc},
     {N_("About XBoard"), "About XBoard", AboutProc},
     {NULL, NULL, NULL}
@@ -973,7 +978,6 @@ XtActionsRec boardActions[] = {
     { "HighlightLastMoveProc", HighlightLastMoveProc },
     { "IcsAlarmProc", IcsAlarmProc },
     { "MoveSoundProc", MoveSoundProc },
-    { "OldSaveStyleProc", OldSaveStyleProc },
     { "PeriodicUpdatesProc", PeriodicUpdatesProc },
     { "PonderNextMoveProc", PonderNextMoveProc },
     { "PopupExitMessageProc", PopupExitMessageProc },
@@ -1028,8 +1032,8 @@ char globalTranslations[] =
    :Ctrl<Key>c: CopyGameProc() \n \
    :Ctrl<Key>v: PasteGameProc() \n \
    :Ctrl<Key>O: LoadPositionProc() \n \
-   :Shift Meta<Key>Next: LoadNextPositionProc() \n \
-   :Shift Meta<Key>Prior: LoadPrevPositionProc() \n \
+   :Shift<Key>Next: LoadNextPositionProc() \n \
+   :Shift<Key>Prior: LoadPrevPositionProc() \n \
    :Ctrl<Key>S: SavePositionProc() \n \
    :Ctrl<Key>C: CopyPositionProc() \n \
    :Ctrl<Key>V: PastePositionProc() \n \
@@ -1060,6 +1064,8 @@ char globalTranslations[] =
    :Meta<Key>Right: ForwardProc() \n \
    :Meta<Key>Home: ToStartProc() \n \
    :Meta<Key>Left: BackwardProc() \n \
+   :<Key>Home: RevertProc() \n \
+   :<Key>End: TruncateGameProc() \n \
    :Ctrl<Key>m: MoveNowProc() \n \
    :Ctrl<Key>x: RetractMoveProc() \n \
    :Meta<Key>J: EngineMenuProc() \n \
@@ -2460,6 +2466,11 @@ XBoard square size (hint): %d\n\
                                   "menuOptions.Highlight Last Move"),
                    args, 1);
     }
+    if (appData.highlightMoveWithArrow) {
+       XtSetValues(XtNameToWidget(menuBarWidget,
+                                  "menuOptions.Arrow"),
+                   args, 1);
+    }
     if (appData.icsAlarm) {
        XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
                    args, 1);
@@ -2468,9 +2479,9 @@ XBoard square size (hint): %d\n\
        XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
                    args, 1);
     }
-    if (appData.oldSaveStyle) {
+    if (appData.oneClick) {
        XtSetValues(XtNameToWidget(menuBarWidget,
-                                  "menuOptions.Old Save Style"), args, 1);
+                                  "menuOptions.OneClick"), args, 1);
     }
     if (appData.periodicUpdates) {
        XtSetValues(XtNameToWidget(menuBarWidget,
@@ -2768,8 +2779,8 @@ Enables icsEnables[] = {
     { "menuMode.Analyze File", False },
     { "menuMode.Two Machines", False },
 #ifndef ZIPPY
-    { "menuHelp.Hint", False },
-    { "menuHelp.Book", False },
+    { "menuEngine.Hint", False },
+    { "menuEngine.Book", False },
     { "menuEngine.Move Now", False },
     { "menuOptions.Periodic Updates", False },
     { "menuOptions.Hide Thinking", False },
@@ -2810,8 +2821,8 @@ Enables ncpEnables[] = {
     { "menuOptions.Hide Thinking", False },
     { "menuOptions.Periodic Updates", False },
     { "menuOptions.Ponder Next Move", False },
-    { "menuHelp.Hint", False },
-    { "menuHelp.Book", False },
+    { "menuEngine.Hint", False },
+    { "menuEngine.Book", False },
     { NULL, False }
 };
 
@@ -2988,50 +2999,50 @@ 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 HISTORY_SIZE 64
+static char *history[HISTORY_SIZE];
+int histIn = 0, histP = 0;
+
+void
+SaveInHistory(char *cmd)
+{
+  if (history[histIn] != NULL) {
+    free(history[histIn]);
+    history[histIn] = NULL;
+  }
+  if (*cmd == NULLCHAR) return;
+  history[histIn] = StrSave(cmd);
+  histIn = (histIn + 1) % HISTORY_SIZE;
+  if (history[histIn] != NULL) {
+    free(history[histIn]);
+    history[histIn] = NULL;
+  }
+  histP = histIn;
+}
+
+char *
+PrevInHistory(char *cmd)
+{
+  int newhp;
+  if (histP == histIn) {
+    if (history[histIn] != NULL) free(history[histIn]);
+    history[histIn] = StrSave(cmd);
+  }
+  newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
+  if (newhp == histIn || history[newhp] == NULL) return NULL;
+  histP = newhp;
+  return history[histP];
+}
+
+char *
+NextInHistory()
+{
+  if (histP == histIn) return NULL;
+  histP = (histP + 1) % HISTORY_SIZE;
+  return history[histP];   
+}
+// end of borrowed code
+
 #define Abs(n) ((n)<0 ? -(n) : (n))
 
 /*
@@ -3944,11 +3955,7 @@ void WhiteClock(w, event, prms, nprms)
      String *prms;
      Cardinal *nprms;
 {
-    if (gameMode == EditPosition || gameMode == IcsExamining) {
-       SetWhiteToPlayEvent();
-    } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
-       CallFlagEvent();
-    }
+    ClockClick(0);
 }
 
 void BlackClock(w, event, prms, nprms)
@@ -3957,11 +3964,7 @@ void BlackClock(w, event, prms, nprms)
      String *prms;
      Cardinal *nprms;
 {
-    if (gameMode == EditPosition || gameMode == IcsExamining) {
-       SetBlackToPlayEvent();
-    } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
-       CallFlagEvent();
-    }
+    ClockClick(1);
 }
 
 
@@ -3997,7 +4000,7 @@ static void drawHighlight(file, rank, gc)
 {
     int x, y;
 
-    if (lineGap == 0 || appData.blindfold) return;
+    if (lineGap == 0) return;
 
     if (flipView) {
        x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
@@ -4454,7 +4457,7 @@ void EventProc(widget, unused, event)
        }
        break;
       case MotionNotify:
-        if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;\r
+        if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
       default:
        return;
     }
@@ -4600,6 +4603,7 @@ void XDrawPosition(w, repaint, board)
      * but this causes a very distracting flicker.
      */
 
+    if ( lineGap && IsDrawArrowEnabled()) repaint = True;
     if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
 
        /* If too much changes (begin observing new game, etc.), don't
@@ -4664,6 +4668,7 @@ void XDrawPosition(w, repaint, board)
     if (hi2X >= 0 && hi2Y >= 0) {
       drawHighlight(hi2X, hi2Y, highlineGC);
     }
+    DrawArrowHighlight(hi1X, hi1Y, hi2X, hi2Y);
   }
     /* If piece being dragged around board, must redraw that too */
     DrawDragPiece();
@@ -5356,6 +5361,16 @@ void PromotionPopUp()
                                   layout, args, j);
 
   if(gameInfo.variant != VariantShogi) {
+   if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) {
+      XawDialogAddButton(dialog, _("Warlord"), PromotionCallback,
+                        (XtPointer) dialog);
+      XawDialogAddButton(dialog, _("General"), PromotionCallback,
+                        (XtPointer) dialog);
+      XawDialogAddButton(dialog, _("Lieutenant"), PromotionCallback,
+                        (XtPointer) dialog);
+      XawDialogAddButton(dialog, _("Captain"), PromotionCallback,
+                        (XtPointer) dialog);
+    } else {\r
     XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
                       (XtPointer) dialog);
     XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
@@ -5364,7 +5379,9 @@ void PromotionPopUp()
                       (XtPointer) dialog);
     XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
                       (XtPointer) dialog);
+    }
     if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
+        gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||\r
         gameInfo.variant == VariantGiveaway) {
       XawDialogAddButton(dialog, _("King"), PromotionCallback,
                         (XtPointer) dialog);
@@ -6784,6 +6801,25 @@ void HighlightLastMoveProc(w, event, prms, nprms)
                               "menuOptions.Highlight Last Move"), args, 1);
 }
 
+void HighlightArrowProc(w, event, prms, nprms)
+     Widget w;
+     XEvent *event;
+     String *prms;
+     Cardinal *nprms;
+{
+    Arg args[16];
+
+    appData.highlightMoveWithArrow = !appData.highlightMoveWithArrow;
+
+    if (appData.highlightMoveWithArrow) {
+       XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
+    } else {
+       XtSetArg(args[0], XtNleftBitmap, None);
+    }
+    XtSetValues(XtNameToWidget(menuBarWidget,
+                              "menuOptions.Arrow"), args, 1);
+}
+
 void IcsAlarmProc(w, event, prms, nprms)
      Widget w;
      XEvent *event;
@@ -6822,8 +6858,7 @@ void MoveSoundProc(w, event, prms, nprms)
                args, 1);
 }
 
-
-void OldSaveStyleProc(w, event, prms, nprms)
+void OneClickProc(w, event, prms, nprms)
      Widget w;
      XEvent *event;
      String *prms;
@@ -6831,14 +6866,14 @@ void OldSaveStyleProc(w, event, prms, nprms)
 {
     Arg args[16];
 
-    appData.oldSaveStyle = !appData.oldSaveStyle;
+    appData.oneClick = !appData.oneClick;
 
-    if (appData.oldSaveStyle) {
+    if (appData.oneClick) {
        XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
     } else {
        XtSetArg(args[0], XtNleftBitmap, None);
     }
-    XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
+    XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.OneClick"),
                args, 1);
 }
 
@@ -9092,3 +9127,199 @@ void NotifyFrontendLogin()
 {
     update_ics_width();
 }
+
+/* [AS] Arrow highlighting support */
+
+static double A_WIDTH = 5; /* Width of arrow body */
+
+#define A_HEIGHT_FACTOR 6   /* Length of arrow "point", relative to body width */
+#define A_WIDTH_FACTOR  3   /* Width of arrow "point", relative to body width */
+
+static double Sqr( double x )
+{
+    return x*x;
+}
+
+static int Round( double x )
+{
+    return (int) (x + 0.5);
+}
+
+void SquareToPos(int rank, int file, int *x, int *y)
+{
+    if (flipView) {
+       *x = lineGap + ((BOARD_WIDTH-1)-file) * (squareSize + lineGap);
+       *y = lineGap + rank * (squareSize + lineGap);
+    } else {
+       *x = lineGap + file * (squareSize + lineGap);
+       *y = lineGap + ((BOARD_HEIGHT-1)-rank) * (squareSize + lineGap);
+    }
+}
+
+/* Draw an arrow between two points using current settings */
+void DrawArrowBetweenPoints( int s_x, int s_y, int d_x, int d_y )
+{
+    XPoint arrow[7];
+    double dx, dy, j, k, x, y;
+
+    if( d_x == s_x ) {
+        int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
+
+        arrow[0].x = s_x + A_WIDTH + 0.5;
+        arrow[0].y = s_y;
+
+        arrow[1].x = s_x + A_WIDTH + 0.5;
+        arrow[1].y = d_y - h;
+
+        arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
+        arrow[2].y = d_y - h;
+
+        arrow[3].x = d_x;
+        arrow[3].y = d_y;
+
+        arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
+        arrow[5].y = d_y - h;
+
+        arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
+        arrow[4].y = d_y - h;
+
+        arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
+        arrow[6].y = s_y;
+    }
+    else if( d_y == s_y ) {
+        int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
+
+        arrow[0].x = s_x;
+        arrow[0].y = s_y + A_WIDTH + 0.5;
+
+        arrow[1].x = d_x - w;
+        arrow[1].y = s_y + A_WIDTH + 0.5;
+
+        arrow[2].x = d_x - w;
+        arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
+
+        arrow[3].x = d_x;
+        arrow[3].y = d_y;
+
+        arrow[5].x = d_x - w;
+        arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
+
+        arrow[4].x = d_x - w;
+        arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
+
+        arrow[6].x = s_x;
+        arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
+    }
+    else {
+        /* [AS] Needed a lot of paper for this! :-) */
+        dy = (double) (d_y - s_y) / (double) (d_x - s_x);
+        dx = (double) (s_x - d_x) / (double) (s_y - d_y);
+
+        j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
+
+        k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
+
+        x = s_x;
+        y = s_y;
+
+        arrow[0].x = Round(x - j);
+        arrow[0].y = Round(y + j*dx);
+
+        arrow[1].x = Round(arrow[0].x + 2*j);   // [HGM] prevent width to be affected by rounding twice
+        arrow[1].y = Round(arrow[0].y - 2*j*dx);
+
+        if( d_x > s_x ) {
+            x = (double) d_x - k;
+            y = (double) d_y - k*dy;
+        }
+        else {
+            x = (double) d_x + k;
+            y = (double) d_y + k*dy;
+        }
+
+        x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
+
+        arrow[6].x = Round(x - j);
+        arrow[6].y = Round(y + j*dx);
+
+        arrow[2].x = Round(arrow[6].x + 2*j);
+        arrow[2].y = Round(arrow[6].y - 2*j*dx);
+
+        arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
+        arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
+
+        arrow[4].x = d_x;
+        arrow[4].y = d_y;
+
+        arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
+        arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
+    }
+
+    XFillPolygon(xDisplay, xBoardWindow, highlineGC, arrow, 7, Nonconvex, CoordModeOrigin);
+//    Polygon( hdc, arrow, 7 );
+}
+
+/* [AS] Draw an arrow between two squares */
+void DrawArrowBetweenSquares( int s_col, int s_row, int d_col, int d_row )
+{
+    int s_x, s_y, d_x, d_y, hor, vert, i;
+
+    if( s_col == d_col && s_row == d_row ) {
+        return;
+    }
+
+    /* Get source and destination points */
+    SquareToPos( s_row, s_col, &s_x, &s_y);
+    SquareToPos( d_row, d_col, &d_x, &d_y);
+
+    if( d_y > s_y ) {
+        d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
+    }
+    else if( d_y < s_y ) {
+        d_y += squareSize / 2 + squareSize / 4;
+    }
+    else {
+        d_y += squareSize / 2;
+    }
+
+    if( d_x > s_x ) {
+        d_x += squareSize / 2 - squareSize / 4;
+    }
+    else if( d_x < s_x ) {
+        d_x += squareSize / 2 + squareSize / 4;
+    }
+    else {
+        d_x += squareSize / 2;
+    }
+
+    s_x += squareSize / 2;
+    s_y += squareSize / 2;
+
+    /* Adjust width */
+    A_WIDTH = squareSize / 14.; //[HGM] make float
+
+    DrawArrowBetweenPoints( s_x, s_y, d_x, d_y );
+
+    if(lineGap == 0) {
+        // this is a good idea, but it only works when lineGap == 0, because 'damage' on grid lines is not repaired
+        hor = 64*s_col + 32; vert = 64*s_row + 32;
+        for(i=0; i<= 64; i++) {
+            damage[0][vert+6>>6][hor+6>>6] = True;
+            damage[0][vert-6>>6][hor+6>>6] = True;
+            damage[0][vert+6>>6][hor-6>>6] = True;
+            damage[0][vert-6>>6][hor-6>>6] = True;
+            hor += d_col - s_col; vert += d_row - s_row;
+        }
+    }
+}
+
+Boolean IsDrawArrowEnabled()
+{
+    return appData.highlightMoveWithArrow && squareSize >= 32;
+}
+
+void DrawArrowHighlight(int fromX, int fromY, int toX,int toY)
+{
+    if( IsDrawArrowEnabled() && fromX >= 0 && fromY >= 0 && toX >= 0 && toY >= 0)
+        DrawArrowBetweenSquares(fromX, fromY, toX, toY);
+}