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