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