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