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