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