f0c7afa9adba4f18345575af26ee537f6c7f4c71
[xboard.git] / menus.c
1 /*
2  * menus.c -- platform-indendent menu handling code for XBoard
3  *
4  * Copyright 1991 by Digital Equipment Corporation, Maynard,
5  * Massachusetts.
6  *
7  * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
8  * 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
9  *
10  * The following terms apply to Digital Equipment Corporation's copyright
11  * interest in XBoard:
12  * ------------------------------------------------------------------------
13  * All Rights Reserved
14  *
15  * Permission to use, copy, modify, and distribute this software and its
16  * documentation for any purpose and without fee is hereby granted,
17  * provided that the above copyright notice appear in all copies and that
18  * both that copyright notice and this permission notice appear in
19  * supporting documentation, and that the name of Digital not be
20  * used in advertising or publicity pertaining to distribution of the
21  * software without specific, written prior permission.
22  *
23  * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25  * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26  * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
29  * SOFTWARE.
30  * ------------------------------------------------------------------------
31  *
32  * The following terms apply to the enhanced version of XBoard
33  * distributed by the Free Software Foundation:
34  * ------------------------------------------------------------------------
35  *
36  * GNU XBoard is free software: you can redistribute it and/or modify
37  * it under the terms of the GNU General Public License as published by
38  * the Free Software Foundation, either version 3 of the License, or (at
39  * your option) any later version.
40  *
41  * GNU XBoard is distributed in the hope that it will be useful, but
42  * WITHOUT ANY WARRANTY; without even the implied warranty of
43  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44  * General Public License for more details.
45  *
46  * You should have received a copy of the GNU General Public License
47  * along with this program. If not, see http://www.gnu.org/licenses/.  *
48  *
49  *------------------------------------------------------------------------
50  ** See the file ChangeLog for a revision history.  */
51
52 #define HIGHDRAG 1
53
54 #include "config.h"
55
56 #include <stdio.h>
57 #include <ctype.h>
58 #include <signal.h>
59 #include <errno.h>
60 #include <sys/types.h>
61 #include <sys/stat.h>
62 #include <pwd.h>
63 #include <math.h>
64
65 #if STDC_HEADERS
66 # include <stdlib.h>
67 # include <string.h>
68 #else /* not STDC_HEADERS */
69 extern char *getenv();
70 # if HAVE_STRING_H
71 #  include <string.h>
72 # else /* not HAVE_STRING_H */
73 #  include <strings.h>
74 # endif /* not HAVE_STRING_H */
75 #endif /* not STDC_HEADERS */
76
77 #if HAVE_UNISTD_H
78 # include <unistd.h>
79 #endif
80
81 #if ENABLE_NLS
82 #include <locale.h>
83 #endif
84
85 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
86 #include "common.h"
87
88 #include "frontend.h"
89 #include "backend.h"
90 #include "backendz.h"
91 #include "moves.h"
92 #include "xhistory.h"
93 #include "xedittags.h"
94 #include "menus.h"
95 #include "gettext.h"
96
97 #ifdef ENABLE_NLS
98 # define  _(s) gettext (s)
99 # define N_(s) gettext_noop (s)
100 #else
101 # define  _(s) (s)
102 # define N_(s)  s
103 #endif
104
105 /*
106  * Button/menu procedures
107  */
108
109 char  *gameCopyFilename, *gamePasteFilename;
110 Boolean saveSettingsOnExit;
111 char *settingsFileName;
112
113 static int
114 LoadGamePopUp (FILE *f, int gameNumber, char *title)
115 {
116     cmailMsgLoaded = FALSE;
117     if (gameNumber == 0) {
118         int error = GameListBuild(f);
119         if (error) {
120             DisplayError(_("Cannot build game list"), error);
121         } else if (!ListEmpty(&gameList) &&
122                    ((ListGame *) gameList.tailPred)->number > 1) {
123             GameListPopUp(f, title);
124             return TRUE;
125         }
126         GameListDestroy();
127         gameNumber = 1;
128     }
129     return LoadGame(f, gameNumber, title, FALSE);
130 }
131
132 void
133 LoadGameProc ()
134 {
135     if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
136         Reset(FALSE, TRUE);
137     }
138     FileNamePopUp(_("Load game file name?"), "", ".pgn .game", LoadGamePopUp, "rb");
139 }
140
141 void
142 LoadNextGameProc ()
143 {
144     ReloadGame(1);
145 }
146
147 void
148 LoadPrevGameProc ()
149 {
150     ReloadGame(-1);
151 }
152
153 void
154 ReloadGameProc ()
155 {
156     ReloadGame(0);
157 }
158
159 void
160 LoadNextPositionProc ()
161 {
162     ReloadPosition(1);
163 }
164
165 void
166 LoadPrevPositionProc ()
167 {
168     ReloadPosition(-1);
169 }
170
171 void
172 ReloadPositionProc ()
173 {
174     ReloadPosition(0);
175 }
176
177 void
178 LoadPositionProc() 
179 {
180     if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
181         Reset(FALSE, TRUE);
182     }
183     FileNamePopUp(_("Load position file name?"), "", ".fen .epd .pos", LoadPosition, "rb");
184 }
185
186 void
187 SaveGameProc ()
188 {
189     FileNamePopUp(_("Save game file name?"),
190                   DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
191                   appData.oldSaveStyle ? ".game" : ".pgn",
192                   SaveGame, "a");
193 }
194
195 void
196 SavePositionProc ()
197 {
198     FileNamePopUp(_("Save position file name?"),
199                   DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
200                   appData.oldSaveStyle ? ".pos" : ".fen",
201                   SavePosition, "a");
202 }
203
204 void
205 ReloadCmailMsgProc ()
206 {
207     ReloadCmailMsgEvent(FALSE);
208 }
209
210 void
211 CopyFENToClipboard ()
212 { // wrapper to make call from back-end possible
213   CopyPositionProc();
214 }
215
216 void
217 CopyPositionProc ()
218 {
219     static char *selected_fen_position=NULL;
220     if(gameMode == EditPosition) EditPositionDone(TRUE);
221     if (selected_fen_position) free(selected_fen_position);
222     selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
223     if (!selected_fen_position) return;
224     CopySomething(selected_fen_position);
225 }
226
227 void
228 CopyGameProc ()
229 {
230   int ret;
231
232   ret = SaveGameToFile(gameCopyFilename, FALSE);
233   if (!ret) return;
234
235   CopySomething(NULL);
236 }
237
238 void
239 CopyGameListProc ()
240 {
241   if(!SaveGameListAsText(fopen(gameCopyFilename, "w"))) return;
242   CopySomething(NULL);
243 }
244
245 void
246 AutoSaveGame ()
247 {
248     SaveGameProc();
249 }
250
251
252 void
253 QuitProc ()
254 {
255     ExitEvent(0);
256 }
257
258 void
259 AnalyzeModeProc ()
260 {
261     char buf[MSG_SIZ];
262
263     if (!first.analysisSupport) {
264       snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
265       DisplayError(buf, 0);
266       return;
267     }
268     /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
269     if (appData.icsActive) {
270         if (gameMode != IcsObserving) {
271           snprintf(buf, MSG_SIZ, _("You are not observing a game"));
272             DisplayError(buf, 0);
273             /* secure check */
274             if (appData.icsEngineAnalyze) {
275                 if (appData.debugMode)
276                     fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
277                 ExitAnalyzeMode();
278                 ModeHighlight();
279             }
280             return;
281         }
282         /* if enable, use want disable icsEngineAnalyze */
283         if (appData.icsEngineAnalyze) {
284                 ExitAnalyzeMode();
285                 ModeHighlight();
286                 return;
287         }
288         appData.icsEngineAnalyze = TRUE;
289         if (appData.debugMode)
290             fprintf(debugFP, _("ICS engine analyze starting... \n"));
291     }
292 #ifndef OPTIONSDIALOG
293     if (!appData.showThinking)
294       ShowThinkingProc();
295 #endif
296
297     AnalyzeModeEvent();
298 }
299
300 void
301 AnalyzeFileProc ()
302 {
303     if (!first.analysisSupport) {
304       char buf[MSG_SIZ];
305       snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
306       DisplayError(buf, 0);
307       return;
308     }
309 //    Reset(FALSE, TRUE);
310 #ifndef OPTIONSDIALOG
311     if (!appData.showThinking)
312       ShowThinkingProc();
313 #endif
314     AnalyzeFileEvent();
315 //    FileNamePopUp(_("File to analyze"), "", ".pgn .game", LoadGamePopUp, "rb");
316     AnalysisPeriodicEvent(1);
317 }
318
319 void
320 MatchProc ()
321 {
322     MatchEvent(2);
323 }
324
325 void
326 AdjuWhiteProc ()
327 {
328     UserAdjudicationEvent(+1);
329 }
330
331 void
332 AdjuBlackProc ()
333 {
334     UserAdjudicationEvent(-1);
335 }
336
337 void
338 AdjuDrawProc ()
339 {
340     UserAdjudicationEvent(0);
341 }
342
343 void
344 RevertProc ()
345 {
346     RevertEvent(False);
347 }
348
349 void
350 AnnotateProc ()
351 {
352     RevertEvent(True);
353 }
354
355 void
356 FlipViewProc ()
357 {
358     flipView = !flipView;
359     DrawPosition(True, NULL);
360 }
361
362 void
363 SaveOnExitProc ()
364 {
365     Arg args[16];
366
367     saveSettingsOnExit = !saveSettingsOnExit;
368
369     MarkMenuItem("Options.SaveSettingsonExit", saveSettingsOnExit);
370 }
371
372 void
373 SaveSettingsProc ()
374 {
375      SaveSettings(settingsFileName);
376 }
377
378 void
379 InfoProc ()
380 {
381     char buf[MSG_SIZ];
382     snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
383             INFODIR, INFOFILE);
384     system(buf);
385 }
386
387 void
388 ManProc ()
389 {   // called from menu
390     ManInner(NULL, NULL, NULL, NULL);
391 }
392
393 void
394 BugReportProc ()
395 {
396     char buf[MSG_SIZ];
397     snprintf(buf, MSG_SIZ, "%s mailto:bug-xboard@gnu.org", appData.sysOpen);
398     system(buf);
399 }
400
401 void
402 GuideProc ()
403 {
404     char buf[MSG_SIZ];
405     snprintf(buf, MSG_SIZ, "%s http://www.gnu.org/software/xboard/user_guide/UserGuide.html", appData.sysOpen);
406     system(buf);
407 }
408
409 void
410 HomePageProc ()
411 {
412     char buf[MSG_SIZ];
413     snprintf(buf, MSG_SIZ, "%s http://www.gnu.org/software/xboard/", appData.sysOpen);
414     system(buf);
415 }
416
417 void
418 NewsPageProc ()
419 {
420     char buf[MSG_SIZ];
421     snprintf(buf, MSG_SIZ, "%s http://www.gnu.org/software/xboard/whats_new/portal.html", appData.sysOpen);
422     system(buf);
423 }
424
425 void
426 AboutProc ()
427 {
428     char buf[2 * MSG_SIZ];
429 #if ZIPPY
430     char *zippy = _(" (with Zippy code)");
431 #else
432     char *zippy = "";
433 #endif
434     snprintf(buf, sizeof(buf), 
435 _("%s%s\n\n"
436 "Copyright 1991 Digital Equipment Corporation\n"
437 "Enhancements Copyright 1992-2012 Free Software Foundation\n"
438 "Enhancements Copyright 2005 Alessandro Scotti\n\n"
439 "%s is free software and carries NO WARRANTY;"
440 "see the file COPYING for more information.\n\n"
441 "Visit XBoard on the web at: http://www.gnu.org/software/xboard/\n"
442 "Check out the newest features at: http://www.gnu.org/software/xboard/whats_new.html\n\n"
443 "Report bugs via email at: <bug-xboard@gnu.org>\n\n"
444   ),
445             programVersion, zippy, PACKAGE);
446     ErrorPopUp(_("About XBoard"), buf, FALSE);
447 }
448
449 void
450 DebugProc ()
451 {
452     appData.debugMode = !appData.debugMode;
453     if(!strcmp(appData.nameOfDebugFile, "stderr")) return; // stderr is already open, and should never be closed
454     if(!appData.debugMode) fclose(debugFP);
455     else {
456         debugFP = fopen(appData.nameOfDebugFile, "w");
457         if(debugFP == NULL) debugFP = stderr;
458         else setbuf(debugFP, NULL);
459     }
460 }
461
462 void
463 NothingProc ()
464 {
465     return;
466 }
467
468 #ifdef OPTIONSDIALOG
469 #   define MARK_MENU_ITEM(X,Y)
470 #else
471 #   define MARK_MENU_ITEM(X,Y) MarkMenuItem(X, Y)
472 #endif
473
474 void
475 PonderNextMoveProc ()
476 {
477     Arg args[16];
478
479     PonderNextMoveEvent(!appData.ponderNextMove);
480     MARK_MENU_ITEM("Options.PonderNextMove", appData.ponderNextMove);
481 }
482
483 void
484 AlwaysQueenProc ()
485 {
486     appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
487     MARK_MENU_ITEM("Options.AlwaysQueen", appData.alwaysPromoteToQueen);
488 }
489
490 void
491 AnimateDraggingProc ()
492 {
493     appData.animateDragging = !appData.animateDragging;
494
495     if (appData.animateDragging) CreateAnimVars();
496     MARK_MENU_ITEM("Options.AnimateDragging", appData.animateDragging);
497 }
498
499 void
500 AnimateMovingProc ()
501 {
502     appData.animate = !appData.animate;
503     if (appData.animate) CreateAnimVars();
504     MARK_MENU_ITEM("Options.AnimateMoving", appData.animate);
505 }
506
507 void
508 AutoflagProc ()
509 {
510     appData.autoCallFlag = !appData.autoCallFlag;
511     MARK_MENU_ITEM("Options.AutoFlag", appData.autoCallFlag);
512 }
513
514 void
515 AutoflipProc ()
516 {
517     appData.autoFlipView = !appData.autoFlipView;
518     MARK_MENU_ITEM("Options.AutoFlipView", appData.autoFlipView);
519 }
520
521 void
522 BlindfoldProc ()
523 {
524     appData.blindfold = !appData.blindfold;
525     MARK_MENU_ITEM("Options.Blindfold", appData.blindfold);
526     DrawPosition(True, NULL);
527 }
528
529 void
530 TestLegalityProc ()
531 {
532     appData.testLegality = !appData.testLegality;
533     MARK_MENU_ITEM("Options.TestLegality", appData.testLegality);
534 }
535
536
537 void
538 FlashMovesProc ()
539 {
540     if (appData.flashCount == 0) {
541         appData.flashCount = 3;
542     } else {
543         appData.flashCount = -appData.flashCount;
544     }
545     MARK_MENU_ITEM("Options.FlashMoves", appData.flashCount > 0);
546 }
547
548 #if HIGHDRAG
549 void
550 HighlightDraggingProc ()
551 {
552     appData.highlightDragging = !appData.highlightDragging;
553     MARK_MENU_ITEM("Options.HighlightDragging", appData.highlightDragging);
554 }
555 #endif
556
557 void
558 HighlightLastMoveProc ()
559 {
560     appData.highlightLastMove = !appData.highlightLastMove;
561     MARK_MENU_ITEM("Options.HighlightLastMove", appData.highlightLastMove);
562 }
563
564 void
565 HighlightArrowProc ()
566 {
567     appData.highlightMoveWithArrow = !appData.highlightMoveWithArrow;
568     MARK_MENU_ITEM("Options.HighlightWithArrow", appData.highlightMoveWithArrow);
569 }
570
571 void
572 IcsAlarmProc ()
573 {
574     appData.icsAlarm = !appData.icsAlarm;
575 //    MARK_MENU_ITEM("Options.ICSAlarm", appData.icsAlarm);
576 }
577
578 void
579 MoveSoundProc ()
580 {
581     appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
582     MARK_MENU_ITEM("Options.MoveSound", appData.ringBellAfterMoves);
583 }
584
585 void
586 OneClickProc ()
587 {
588     appData.oneClick = !appData.oneClick;
589     MARK_MENU_ITEM("Options.OneClickMoving", appData.oneClick);
590 }
591
592 void
593 PeriodicUpdatesProc ()
594 {
595     PeriodicUpdatesEvent(!appData.periodicUpdates);
596     MARK_MENU_ITEM("Options.PeriodicUpdates", appData.periodicUpdates);
597 }
598
599 void
600 PopupExitMessageProc ()
601 {
602     appData.popupExitMessage = !appData.popupExitMessage;
603     MARK_MENU_ITEM("Options.PopupExitMessage", appData.popupExitMessage);
604 }
605
606 void
607 PopupMoveErrorsProc ()
608 {
609     appData.popupMoveErrors = !appData.popupMoveErrors;
610     MARK_MENU_ITEM("Options.PopupMoveErrors", appData.popupMoveErrors);
611 }
612
613 void
614 PremoveProc ()
615 {
616     appData.premove = !appData.premove;
617 //    MARK_MENU_ITEM("Options.Premove", appData.premove);
618 }
619
620 void
621 ShowCoordsProc ()
622 {
623     appData.showCoords = !appData.showCoords;
624     MARK_MENU_ITEM("Options.ShowCoords", appData.showCoords);
625     DrawPosition(True, NULL);
626 }
627
628 void
629 ShowThinkingProc ()
630 {
631     appData.showThinking = !appData.showThinking; // [HGM] thinking: taken out of ShowThinkingEvent
632     ShowThinkingEvent();
633 }
634
635 void
636 HideThinkingProc ()
637 {
638     Arg args[16];
639
640     appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: taken out of ShowThinkingEvent
641     ShowThinkingEvent();
642
643     MARK_MENU_ITEM("Options.HideThinking", appData.hideThinkingFromHuman);
644 }
645
646 /*
647  *  Menu definition tables
648  */
649
650 MenuItem fileMenu[] = {
651     {N_("New Game        Ctrl+N"),        "NewGame", ResetGameEvent},
652     {N_("New Shuffle Game ..."),          "NewShuffleGame", ShuffleMenuProc},
653     {N_("New Variant ...   Alt+Shift+V"), "NewVariant", NewVariantProc},      // [HGM] variant: not functional yet
654     {"----", NULL, NothingProc},
655     {N_("Load Game       Ctrl+O"),        "LoadGame", LoadGameProc},
656     {N_("Load Position    Ctrl+Shift+O"), "LoadPosition", LoadPositionProc},
657 //    {N_("Load Next Game"), "LoadNextGame", LoadNextGameProc},
658 //    {N_("Load Previous Game"), "LoadPreviousGame", LoadPrevGameProc},
659 //    {N_("Reload Same Game"), "ReloadSameGame", ReloadGameProc},
660     {N_("Next Position     Shift+PgDn"), "LoadNextPosition", LoadNextPositionProc},
661     {N_("Prev Position     Shift+PgUp"), "LoadPreviousPosition", LoadPrevPositionProc},
662     {"----", NULL, NothingProc},
663 //    {N_("Reload Same Position"), "Reload Same Position", ReloadPositionProc},
664     {N_("Save Game       Ctrl+S"),        "SaveGame", SaveGameProc},
665     {N_("Save Position    Ctrl+Shift+S"), "SavePosition", SavePositionProc},
666     {"----", NULL, NothingProc},
667     {N_("Mail Move"),            "MailMove", MailMoveEvent},
668     {N_("Reload CMail Message"), "ReloadCMailMessage", ReloadCmailMsgProc},
669     {"----", NULL, NothingProc},
670     {N_("Quit                 Ctr+Q"), "Quit", QuitProc},
671     {NULL, NULL, NULL}
672 };
673
674 MenuItem editMenu[] = {
675     {N_("Copy Game    Ctrl+C"),        "CopyGame", CopyGameProc},
676     {N_("Copy Position Ctrl+Shift+C"), "CopyPosition", CopyPositionProc},
677     {N_("Copy Game List"),        "CopyGameList", CopyGameListProc},
678     {"----", NULL, NothingProc},
679     {N_("Paste Game    Ctrl+V"),        "PasteGame", PasteGameProc},
680     {N_("Paste Position Ctrl+Shift+V"), "PastePosition", PastePositionProc},
681     {"----", NULL, NothingProc},
682     {N_("Edit Game      Ctrl+E"),        "EditGame", EditGameEvent},
683     {N_("Edit Position   Ctrl+Shift+E"), "EditPosition", EditPositionEvent},
684     {N_("Edit Tags"),                    "EditTags", EditTagsProc},
685     {N_("Edit Comment"),                 "EditComment", EditCommentProc},
686     {N_("Edit Book"),                    "EditBook", EditBookEvent},
687     {"----", NULL, NothingProc},
688     {N_("Revert              Home"), "Revert", RevertProc},
689     {N_("Annotate"),                 "Annotate", AnnotateProc},
690     {N_("Truncate Game  End"),       "TruncateGame", TruncateGameEvent},
691     {"----", NULL, NothingProc},
692     {N_("Backward         Alt+Left"),   "Backward", BackwardEvent},
693     {N_("Forward           Alt+Right"), "Forward", ForwardEvent},
694     {N_("Back to Start     Alt+Home"),  "BacktoStart", ToStartEvent},
695     {N_("Forward to End Alt+End"),      "ForwardtoEnd", ToEndEvent},
696     {NULL, NULL, NULL}
697 };
698
699 MenuItem viewMenu[] = {
700     {N_("Flip View             F2"),         "FlipView", FlipViewProc},
701     {"----", NULL, NothingProc},
702     {N_("Engine Output      Alt+Shift+O"),   "EngineOutput", EngineOutputProc},
703     {N_("Move History       Alt+Shift+H"),   "MoveHistory", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
704     {N_("Evaluation Graph  Alt+Shift+E"),    "EvaluationGraph", EvalGraphProc},
705     {N_("Game List            Alt+Shift+G"), "GameList", ShowGameListProc},
706     {N_("ICS text menu"), "ICStextmenu", IcsTextProc},
707     {"----", NULL, NothingProc},
708     {N_("Tags"),             "Tags", EditTagsProc},
709     {N_("Comments"),         "Comments", EditCommentProc},
710     {N_("ICS Input Box"),    "ICSInputBox", IcsInputBoxProc},
711     {"----", NULL, NothingProc},
712     {N_("Board..."),          "Board", BoardOptionsProc},
713     {N_("Game List Tags..."), "GameListTags", GameListOptionsProc},
714     {NULL, NULL, NULL}
715 };
716
717 MenuItem modeMenu[] = {
718     {N_("Machine White  Ctrl+W"), "MachineWhite", MachineWhiteEvent},
719     {N_("Machine Black  Ctrl+B"), "MachineBlack", MachineBlackEvent},
720     {N_("Two Machines   Ctrl+T"), "TwoMachines", TwoMachinesEvent},
721     {N_("Analysis Mode  Ctrl+A"), "AnalysisMode", AnalyzeModeProc},
722     {N_("Analyze Game   Ctrl+G"), "AnalyzeFile", AnalyzeFileProc },
723     {N_("Edit Game         Ctrl+E"), "EditGame", EditGameEvent},
724     {N_("Edit Position      Ctrl+Shift+E"), "EditPosition", EditPositionEvent},
725     {N_("Training"),      "Training", TrainingEvent},
726     {N_("ICS Client"),    "ICSClient", IcsClientEvent},
727     {"----", NULL, NothingProc},
728     {N_("Machine Match"),         "MachineMatch", MatchProc},
729     {N_("Pause               Pause"),         "Pause", PauseEvent},
730     {NULL, NULL, NULL}
731 };
732
733 MenuItem actionMenu[] = {
734     {N_("Accept             F3"), "Accept", AcceptEvent},
735     {N_("Decline            F4"), "Decline", DeclineEvent},
736     {N_("Rematch           F12"), "Rematch", RematchEvent},
737     {"----", NULL, NothingProc},
738     {N_("Call Flag          F5"), "CallFlag", CallFlagEvent},
739     {N_("Draw                F6"), "Draw", DrawEvent},
740     {N_("Adjourn            F7"),  "Adjourn", AdjournEvent},
741     {N_("Abort                F8"),"Abort", AbortEvent},
742     {N_("Resign              F9"), "Resign", ResignEvent},
743     {"----", NULL, NothingProc},
744     {N_("Stop Observing  F10"), "StopObserving", StopObservingEvent},
745     {N_("Stop Examining  F11"), "StopExamining", StopExaminingEvent},
746     {N_("Upload to Examine"),   "UploadtoExamine", UploadGameEvent},
747     {"----", NULL, NothingProc},
748     {N_("Adjudicate to White"), "AdjudicatetoWhite", AdjuWhiteProc},
749     {N_("Adjudicate to Black"), "AdjudicatetoBlack", AdjuBlackProc},
750     {N_("Adjudicate Draw"),     "AdjudicateDraw", AdjuDrawProc},
751     {NULL, NULL, NULL}
752 };
753
754 MenuItem engineMenu[] = {
755     {N_("Load New 1st Engine ..."), "LoadEngine", LoadEngine1Proc},
756     {N_("Load New 2nd Engine ..."), "LoadEngine", LoadEngine2Proc},
757     {"----", NULL, NothingProc},
758     {N_("Engine #1 Settings ..."), "Engine#1Settings", FirstSettingsProc},
759     {N_("Engine #2 Settings ..."), "Engine#2Settings", SecondSettingsProc},
760     {"----", NULL, NothingProc},
761     {N_("Hint"), "Hint", HintEvent},
762     {N_("Book"), "Book", BookEvent},
763     {"----", NULL, NothingProc},
764     {N_("Move Now     Ctrl+M"),     "MoveNow", MoveNowEvent},
765     {N_("Retract Move  Ctrl+X"), "RetractMove", RetractMoveEvent},
766     {NULL, NULL, NULL}
767 };
768
769 MenuItem optionsMenu[] = {
770 #ifdef OPTIONSDIALOG
771     {N_("General ..."), "General", OptionsProc},
772 #endif
773     {N_("Time Control ...       Alt+Shift+T"), "TimeControl", TimeControlProc},
774     {N_("Common Engine ...  Alt+Shift+U"),     "CommonEngine", UciMenuProc},
775     {N_("Adjudications ...      Alt+Shift+J"), "Adjudications", EngineMenuProc},
776     {N_("ICS ..."),    "ICS", IcsOptionsProc},
777     {N_("Match ..."), "Match", MatchOptionsProc},
778     {N_("Load Game ..."),    "LoadGame", LoadOptionsProc},
779     {N_("Save Game ..."),    "SaveGame", SaveOptionsProc},
780 //    {N_(" ..."),    "", OptionsProc},
781     {N_("Game List ..."),    "GameList", GameListOptionsProc},
782     {N_("Sounds ..."),    "Sounds", SoundOptionsProc},
783     {"----", NULL, NothingProc},
784 #ifndef OPTIONSDIALOG
785     {N_("Always Queen        Ctrl+Shift+Q"),   "AlwaysQueen", AlwaysQueenProc},
786     {N_("Animate Dragging"), "AnimateDragging", AnimateDraggingProc},
787     {N_("Animate Moving      Ctrl+Shift+A"),   "AnimateMoving", AnimateMovingProc},
788     {N_("Auto Flag               Ctrl+Shift+F"), "AutoFlag", AutoflagProc},
789     {N_("Auto Flip View"),   "AutoFlipView", AutoflipProc},
790     {N_("Blindfold"),        "Blindfold", BlindfoldProc},
791     {N_("Flash Moves"),      "FlashMoves", FlashMovesProc},
792 #if HIGHDRAG
793     {N_("Highlight Dragging"),    "HighlightDragging", HighlightDraggingProc},
794 #endif
795     {N_("Highlight Last Move"),   "HighlightLastMove", HighlightLastMoveProc},
796     {N_("Highlight With Arrow"),  "HighlightWithArrow", HighlightArrowProc},
797     {N_("Move Sound"),            "MoveSound", MoveSoundProc},
798 //    {N_("ICS Alarm"),             "ICSAlarm", IcsAlarmProc},
799     {N_("One-Click Moving"),      "OneClickMoving", OneClickProc},
800     {N_("Periodic Updates"),      "PeriodicUpdates", PeriodicUpdatesProc},
801     {N_("Ponder Next Move  Ctrl+Shift+P"), "PonderNextMove", PonderNextMoveProc},
802     {N_("Popup Exit Message"),    "PopupExitMessage", PopupExitMessageProc},
803     {N_("Popup Move Errors"),     "PopupMoveErrors", PopupMoveErrorsProc},
804 //    {N_("Premove"),               "Premove", PremoveProc},
805     {N_("Show Coords"),           "ShowCoords", ShowCoordsProc},
806     {N_("Hide Thinking        Ctrl+Shift+H"),   "HideThinking", HideThinkingProc},
807     {N_("Test Legality          Ctrl+Shift+L"), "TestLegality", TestLegalityProc},
808     {"----", NULL, NothingProc},
809 #endif
810     {N_("Save Settings Now"),     "SaveSettingsNow", SaveSettingsProc},
811     {N_("Save Settings on Exit"), "SaveSettingsonExit", SaveOnExitProc},
812     {NULL, NULL, NULL}
813 };
814
815 MenuItem helpMenu[] = {
816     {N_("Info XBoard"),     "InfoXBoard", InfoProc},
817     {N_("Man XBoard   F1"), "ManXBoard", ManProc},
818     {"----", NULL, NothingProc},
819     {N_("XBoard Home Page"), "XBoardHomePage", HomePageProc},
820     {N_("On-line User Guide"), "On-lineUserGuide", GuideProc},
821     {N_("Development News"), "DevelopmentNews", NewsPageProc},
822     {N_("e-Mail Bug Report"), "e-MailBugReport", BugReportProc},
823     {"----", NULL, NothingProc},
824     {N_("About XBoard"), "AboutXBoard", AboutProc},
825     {NULL, NULL, NULL}
826 };
827
828 MenuItem noMenu[] = {
829     { "", "LoadNextGame", LoadNextGameProc },
830     { "", "LoadPrevGame", LoadPrevGameProc },
831     { "", "ReloadGame", ReloadGameProc },
832     { "", "ReloadPosition", ReloadPositionProc },
833 #ifndef OPTIONSDIALOG
834     { "", "AlwaysQueen", AlwaysQueenProc },
835     { "", "AnimateDragging", AnimateDraggingProc },
836     { "", "AnimateMoving", AnimateMovingProc },
837     { "", "Autoflag", AutoflagProc },
838     { "", "Autoflip", AutoflipProc },
839     { "", "Blindfold", BlindfoldProc },
840     { "", "FlashMoves", FlashMovesProc },
841 #if HIGHDRAG
842     { "", "HighlightDragging", HighlightDraggingProc },
843 #endif
844     { "", "HighlightLastMove", HighlightLastMoveProc },
845 //    { "", "IcsAlarm", IcsAlarmProc },
846     { "", "MoveSound", MoveSoundProc },
847     { "", "PeriodicUpdates", PeriodicUpdatesProc },
848     { "", "PopupExitMessage", PopupExitMessageProc },
849     { "", "PopupMoveErrors", PopupMoveErrorsProc },
850 //    { "", "Premove", PremoveProc },
851     { "", "ShowCoords", ShowCoordsProc },
852     { "", "ShowThinking", ShowThinkingProc },
853     { "", "HideThinking", HideThinkingProc },
854     { "", "TestLegality", TestLegalityProc },
855 #endif
856     { "", "AboutGame", AboutGameEvent },
857     { "", "Debug", DebugProc },
858     { "", "Nothing", NothingProc },
859     {NULL, NULL, NULL}
860 };
861
862 Menu menuBar[] = {
863     {N_("File"),    "File", fileMenu},
864     {N_("Edit"),    "Edit", editMenu},
865     {N_("View"),    "View", viewMenu},
866     {N_("Mode"),    "Mode", modeMenu},
867     {N_("Action"),  "Action", actionMenu},
868     {N_("Engine"),  "Engine", engineMenu},
869     {N_("Options"), "Options", optionsMenu},
870     {N_("Help"),    "Help", helpMenu},
871     {NULL, NULL, NULL}
872 };
873
874 MenuItem *
875 MenuNameToItem (char *menuName)
876 {
877     int i;
878     char buf[MSG_SIZ], *p;
879     MenuItem *menuTab;
880     static MenuItem a = { NULL, NULL, NothingProc };
881     extern Option mainOptions[];
882     safeStrCpy(buf, menuName, MSG_SIZ);
883     p = strchr(buf, '.');
884     if(!p) menuTab = noMenu; else {
885         *p++ = NULLCHAR;
886         for(i=0; menuBar[i].name; i++)
887             if(!strcmp(buf, menuBar[i].name)) break;
888         if(!menuBar[i].name) return NULL; // main menu not found
889         menuTab = menuBar[i].mi;
890     }
891     if(*p == NULLCHAR) { a.handle = mainOptions[i+1].handle; return &a; } // main menu bar
892     for(i=0; menuTab[i].string; i++)
893         if(menuTab[i].ref && !strcmp(p, menuTab[i].ref)) return menuTab + i;
894     return NULL; // item not found
895 }
896
897 void
898 AppendEnginesToMenu (char *list)
899 {
900     int i=0;
901     char *p;
902     if(appData.icsActive || appData.recentEngines <= 0) return;
903     recentEngines = strdup(list);
904     while (*list) {
905         p = strchr(list, '\n'); if(p == NULL) break;
906         if(i == 0) AppendMenuItem("----", 0); // at least one valid item to add
907         *p = 0;
908         AppendMenuItem(list, i);
909         i++; *p = '\n'; list = p + 1;
910     }
911 }
912
913 Enables icsEnables[] = {
914     { "File.MailMove", False },
915     { "File.ReloadCMailMessage", False },
916     { "Mode.MachineBlack", False },
917     { "Mode.MachineWhite", False },
918     { "Mode.AnalysisMode", False },
919     { "Mode.AnalyzeFile", False },
920     { "Mode.TwoMachines", False },
921     { "Mode.MachineMatch", False },
922 #ifndef ZIPPY
923     { "Engine.Hint", False },
924     { "Engine.Book", False },
925     { "Engine.MoveNow", False },
926 #ifndef OPTIONSDIALOG
927     { "PeriodicUpdates", False },
928     { "HideThinking", False },
929     { "PonderNextMove", False },
930 #endif
931 #endif
932     { "Engine.Engine#1Settings", False },
933     { "Engine.Engine#2Settings", False },
934     { "Engine.LoadEngine", False },
935     { "Edit.Annotate", False },
936     { "Options.Match", False },
937     { NULL, False }
938 };
939
940 Enables ncpEnables[] = {
941     { "File.MailMove", False },
942     { "File.ReloadCMailMessage", False },
943     { "Mode.MachineWhite", False },
944     { "Mode.MachineBlack", False },
945     { "Mode.AnalysisMode", False },
946     { "Mode.AnalyzeFile", False },
947     { "Mode.TwoMachines", False },
948     { "Mode.MachineMatch", False },
949     { "Mode.ICSClient", False },
950     { "View.ICStextmenu", False },
951     { "View.ICSInputBox", False },
952     { "Action.", False },
953     { "Edit.Revert", False },
954     { "Edit.Annotate", False },
955     { "Engine.Engine#1Settings", False },
956     { "Engine.Engine#2Settings", False },
957     { "Engine.MoveNow", False },
958     { "Engine.RetractMove", False },
959     { "Options.ICS", False },
960 #ifndef OPTIONSDIALOG
961     { "Options.AutoFlag", False },
962     { "Options.AutoFlip View", False },
963 //    { "Options.ICSAlarm", False },
964     { "Options.MoveSound", False },
965     { "Options.HideThinking", False },
966     { "Options.PeriodicUpdates", False },
967     { "Options.PonderNextMove", False },
968 #endif
969     { "Engine.Hint", False },
970     { "Engine.Book", False },
971     { NULL, False }
972 };
973
974 Enables gnuEnables[] = {
975     { "Mode.ICSClient", False },
976     { "View.ICStextmenu", False },
977     { "View.ICSInputBox", False },
978     { "Action.Accept", False },
979     { "Action.Decline", False },
980     { "Action.Rematch", False },
981     { "Action.Adjourn", False },
982     { "Action.StopExamining", False },
983     { "Action.StopObserving", False },
984     { "Action.UploadtoExamine", False },
985     { "Edit.Revert", False },
986     { "Edit.Annotate", False },
987     { "Options.ICS", False },
988
989     /* The next two options rely on SetCmailMode being called *after*    */
990     /* SetGNUMode so that when GNU is being used to give hints these     */
991     /* menu options are still available                                  */
992
993     { "File.MailMove", False },
994     { "File.ReloadCMailMessage", False },
995     // [HGM] The following have been added to make a switch from ncp to GNU mode possible
996     { "Mode.MachineWhite", True },
997     { "Mode.MachineBlack", True },
998     { "Mode.AnalysisMode", True },
999     { "Mode.AnalyzeFile", True },
1000     { "Mode.TwoMachines", True },
1001     { "Mode.MachineMatch", True },
1002     { "Engine.Engine#1Settings", True },
1003     { "Engine.Engine#2Settings", True },
1004     { "Engine.Hint", True },
1005     { "Engine.Book", True },
1006     { "Engine.MoveNow", True },
1007     { "Engine.RetractMove", True },
1008     { "Action.", True },
1009     { NULL, False }
1010 };
1011
1012 Enables cmailEnables[] = {
1013     { "Action.", True },
1014     { "Action.CallFlag", False },
1015     { "Action.Draw", True },
1016     { "Action.Adjourn", False },
1017     { "Action.Abort", False },
1018     { "Action.StopObserving", False },
1019     { "Action.StopExamining", False },
1020     { "File.MailMove", True },
1021     { "File.ReloadCMailMessage", True },
1022     { NULL, False }
1023 };
1024
1025 Enables trainingOnEnables[] = {
1026   { "Edit.EditComment", False },
1027   { "Mode.Pause", False },
1028   { "Edit.Forward", False },
1029   { "Edit.Backward", False },
1030   { "Edit.ForwardtoEnd", False },
1031   { "Edit.BacktoStart", False },
1032   { "Engine.MoveNow", False },
1033   { "Edit.TruncateGame", False },
1034   { NULL, False }
1035 };
1036
1037 Enables trainingOffEnables[] = {
1038   { "Edit.EditComment", True },
1039   { "Mode.Pause", True },
1040   { "Edit.Forward", True },
1041   { "Edit.Backward", True },
1042   { "Edit.ForwardtoEnd", True },
1043   { "Edit.BacktoStart", True },
1044   { "Engine.MoveNow", True },
1045   { "Engine.TruncateGame", True },
1046   { NULL, False }
1047 };
1048
1049 Enables machineThinkingEnables[] = {
1050   { "File.LoadGame", False },
1051 //  { "LoadNextGame", False },
1052 //  { "LoadPreviousGame", False },
1053 //  { "ReloadSameGame", False },
1054   { "Edit.PasteGame", False },
1055   { "File.LoadPosition", False },
1056 //  { "LoadNextPosition", False },
1057 //  { "LoadPreviousPosition", False },
1058 //  { "ReloadSamePosition", False },
1059   { "Edit.PastePosition", False },
1060   { "Mode.MachineWhite", False },
1061   { "Mode.MachineBlack", False },
1062   { "Mode.TwoMachines", False },
1063 //  { "MachineMatch", False },
1064   { "Engine.RetractMove", False },
1065   { NULL, False }
1066 };
1067
1068 Enables userThinkingEnables[] = {
1069   { "File.LoadGame", True },
1070 //  { "LoadNextGame", True },
1071 //  { "LoadPreviousGame", True },
1072 //  { "ReloadSameGame", True },
1073   { "Edit.PasteGame", True },
1074   { "File.LoadPosition", True },
1075 //  { "LoadNextPosition", True },
1076 //  { "LoadPreviousPosition", True },
1077 //  { "ReloadSamePosition", True },
1078   { "Edit.PastePosition", True },
1079   { "Mode.MachineWhite", True },
1080   { "Mode.MachineBlack", True },
1081   { "Mode.TwoMachines", True },
1082 //  { "MachineMatch", True },
1083   { "Engine.RetractMove", True },
1084   { NULL, False }
1085 };
1086
1087 void
1088 SetICSMode ()
1089 {
1090   SetMenuEnables(icsEnables);
1091
1092 #if ZIPPY
1093   if (appData.zippyPlay && !appData.noChessProgram) { /* [DM] icsEngineAnalyze */
1094      EnableMenuItem("Analysis Mode", True);
1095      EnableMenuItem("Engine #1 Settings", True);
1096   }
1097 #endif
1098 }
1099
1100 void
1101 SetNCPMode ()
1102 {
1103   SetMenuEnables(ncpEnables);
1104 }
1105
1106 void
1107 SetGNUMode ()
1108 {
1109   SetMenuEnables(gnuEnables);
1110 }
1111
1112 void
1113 SetCmailMode ()
1114 {
1115   SetMenuEnables(cmailEnables);
1116 }
1117
1118 void
1119 SetTrainingModeOn ()
1120 {
1121   SetMenuEnables(trainingOnEnables);
1122   if (appData.showButtonBar) {
1123     EnableButtonBar(False);
1124   }
1125   CommentPopDown();
1126 }
1127
1128 void
1129 SetTrainingModeOff ()
1130 {
1131   SetMenuEnables(trainingOffEnables);
1132   if (appData.showButtonBar) {
1133     EnableButtonBar(True);
1134   }
1135 }
1136
1137 void
1138 SetUserThinkingEnables ()
1139 {
1140   if (appData.noChessProgram) return;
1141   SetMenuEnables(userThinkingEnables);
1142 }
1143
1144 void
1145 SetMachineThinkingEnables ()
1146 {
1147   if (appData.noChessProgram) return;
1148   SetMenuEnables(machineThinkingEnables);
1149   switch (gameMode) {
1150   case MachinePlaysBlack:
1151   case MachinePlaysWhite:
1152   case TwoMachinesPlay:
1153     EnableMenuItem(ModeToWidgetName(gameMode), True);
1154     break;
1155   default:
1156     break;
1157   }
1158 }
1159
1160 void
1161 GreyRevert (Boolean grey)
1162 {
1163     MarkMenuItem("Edit.Revert", !grey);
1164     MarkMenuItem("Edit.Annotate", !grey);
1165 }
1166
1167 char *
1168 ModeToWidgetName (GameMode mode)
1169 {
1170     switch (mode) {
1171       case BeginningOfGame:
1172         if (appData.icsActive)
1173           return "Mode.ICSClient";
1174         else if (appData.noChessProgram ||
1175                  *appData.cmailGameName != NULLCHAR)
1176           return "Mode.EditGame";
1177         else
1178           return "Mode.MachineBlack";
1179       case MachinePlaysBlack:
1180         return "Mode.MachineBlack";
1181       case MachinePlaysWhite:
1182         return "Mode.MachineWhite";
1183       case AnalyzeMode:
1184         return "Mode.AnalysisMode";
1185       case AnalyzeFile:
1186         return "Mode.AnalyzeFile";
1187       case TwoMachinesPlay:
1188         return "Mode.TwoMachines";
1189       case EditGame:
1190         return "Mode.EditGame";
1191       case PlayFromGameFile:
1192         return "File.LoadGame";
1193       case EditPosition:
1194         return "Mode.EditPosition";
1195       case Training:
1196         return "Mode.Training";
1197       case IcsPlayingWhite:
1198       case IcsPlayingBlack:
1199       case IcsObserving:
1200       case IcsIdle:
1201       case IcsExamining:
1202         return "Mode.ICSClient";
1203       default:
1204       case EndOfGame:
1205         return NULL;
1206     }
1207 }
1208
1209 void
1210 InitMenuMarkers()
1211 {
1212 #ifndef OPTIONSDIALOG
1213     if (appData.alwaysPromoteToQueen) {
1214         MarkMenuItem("Options.Always Queen", True);
1215     }
1216     if (appData.animateDragging) {
1217         MarkMenuItem("Options.Animate Dragging", True);
1218     }
1219     if (appData.animate) {
1220         MarkMenuItem("Options.Animate Moving", True);
1221     }
1222     if (appData.autoCallFlag) {
1223         MarkMenuItem("Options.Auto Flag", True);
1224     }
1225     if (appData.autoFlipView) {
1226         XtSetValues(XtNameToWidget(menuBarWidget,"Options.Auto Flip View", True);
1227     }
1228     if (appData.blindfold) {
1229         MarkMenuItem("Options.Blindfold", True);
1230     }
1231     if (appData.flashCount > 0) {
1232         MarkMenuItem("Options.Flash Moves", True);
1233     }
1234 #if HIGHDRAG
1235     if (appData.highlightDragging) {
1236         MarkMenuItem("Options.Highlight Dragging", True);
1237     }
1238 #endif
1239     if (appData.highlightLastMove) {
1240         MarkMenuItem("Options.Highlight Last Move", True);
1241     }
1242     if (appData.highlightMoveWithArrow) {
1243         MarkMenuItem("Options.Arrow", True);
1244     }
1245 //    if (appData.icsAlarm) {
1246 //      MarkMenuItem("Options.ICS Alarm", True);
1247 //    }
1248     if (appData.ringBellAfterMoves) {
1249         MarkMenuItem("Options.Move Sound", True);
1250     }
1251     if (appData.oneClick) {
1252         MarkMenuItem("Options.OneClick", True);
1253     }
1254     if (appData.periodicUpdates) {
1255         MarkMenuItem("Options.Periodic Updates", True);
1256     }
1257     if (appData.ponderNextMove) {
1258         MarkMenuItem("Options.Ponder Next Move", True);
1259     }
1260     if (appData.popupExitMessage) {
1261         MarkMenuItem("Options.Popup Exit Message", True);
1262     }
1263     if (appData.popupMoveErrors) {
1264         MarkMenuItem("Options.Popup Move Errors", True);
1265     }
1266 //    if (appData.premove) {
1267 //      MarkMenuItem("Options.Premove", True);
1268 //    }
1269     if (appData.showCoords) {
1270         MarkMenuItem("Options.Show Coords", True);
1271     }
1272     if (appData.hideThinkingFromHuman) {
1273         MarkMenuItem("Options.Hide Thinking", True);
1274     }
1275     if (appData.testLegality) {
1276         MarkMenuItem("Options.Test Legality", True);
1277     }
1278 #endif
1279     if (saveSettingsOnExit) {
1280         MarkMenuItem("Options.SaveSettingsonExit", True);
1281     }
1282 }
1283
1284