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