removed my name from copyright message in help->about menu
[xboard.git] / xboard.c
1 /*
2  * xboard.c -- X front end for XBoard
3  * $Id: xboard.c,v 2.2 2003/11/06 07:22:14 mann Exp $
4  *
5  * Copyright 1991 by Digital Equipment Corporation, Maynard,
6  * Massachusetts.  Enhancements Copyright
7  * 1992-2001,2002,2003,2004,2005,2006,2007,2008,2009 Free Software
8  * 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 #include "config.h"
53
54 #include <stdio.h>
55 #include <ctype.h>
56 #include <signal.h>
57 #include <errno.h>
58 #include <sys/types.h>
59 #include <sys/stat.h>
60 #include <pwd.h>
61
62 #if !OMIT_SOCKETS
63 # if HAVE_SYS_SOCKET_H
64 #  include <sys/socket.h>
65 #  include <netinet/in.h>
66 #  include <netdb.h>
67 # else /* not HAVE_SYS_SOCKET_H */
68 #  if HAVE_LAN_SOCKET_H
69 #   include <lan/socket.h>
70 #   include <lan/in.h>
71 #   include <lan/netdb.h>
72 #  else /* not HAVE_LAN_SOCKET_H */
73 #   define OMIT_SOCKETS 1
74 #  endif /* not HAVE_LAN_SOCKET_H */
75 # endif /* not HAVE_SYS_SOCKET_H */
76 #endif /* !OMIT_SOCKETS */
77
78 #if STDC_HEADERS
79 # include <stdlib.h>
80 # include <string.h>
81 #else /* not STDC_HEADERS */
82 extern char *getenv();
83 # if HAVE_STRING_H
84 #  include <string.h>
85 # else /* not HAVE_STRING_H */
86 #  include <strings.h>
87 # endif /* not HAVE_STRING_H */
88 #endif /* not STDC_HEADERS */
89
90 #if HAVE_SYS_FCNTL_H
91 # include <sys/fcntl.h>
92 #else /* not HAVE_SYS_FCNTL_H */
93 # if HAVE_FCNTL_H
94 #  include <fcntl.h>
95 # endif /* HAVE_FCNTL_H */
96 #endif /* not HAVE_SYS_FCNTL_H */
97
98 #if HAVE_SYS_SYSTEMINFO_H
99 # include <sys/systeminfo.h>
100 #endif /* HAVE_SYS_SYSTEMINFO_H */
101
102 #if TIME_WITH_SYS_TIME
103 # include <sys/time.h>
104 # include <time.h>
105 #else
106 # if HAVE_SYS_TIME_H
107 #  include <sys/time.h>
108 # else
109 #  include <time.h>
110 # endif
111 #endif
112
113 #if HAVE_UNISTD_H
114 # include <unistd.h>
115 #endif
116
117 #if HAVE_SYS_WAIT_H
118 # include <sys/wait.h>
119 #endif
120
121 #if HAVE_DIRENT_H
122 # include <dirent.h>
123 # define NAMLEN(dirent) strlen((dirent)->d_name)
124 # define HAVE_DIR_STRUCT
125 #else
126 # define dirent direct
127 # define NAMLEN(dirent) (dirent)->d_namlen
128 # if HAVE_SYS_NDIR_H
129 #  include <sys/ndir.h>
130 #  define HAVE_DIR_STRUCT
131 # endif
132 # if HAVE_SYS_DIR_H
133 #  include <sys/dir.h>
134 #  define HAVE_DIR_STRUCT
135 # endif
136 # if HAVE_NDIR_H
137 #  include <ndir.h>
138 #  define HAVE_DIR_STRUCT
139 # endif
140 #endif
141
142 #include <X11/Intrinsic.h>
143 #include <X11/StringDefs.h>
144 #include <X11/Shell.h>
145 #include <X11/cursorfont.h>
146 #include <X11/Xatom.h>
147 #if USE_XAW3D
148 #include <X11/Xaw3d/Dialog.h>
149 #include <X11/Xaw3d/Form.h>
150 #include <X11/Xaw3d/List.h>
151 #include <X11/Xaw3d/Label.h>
152 #include <X11/Xaw3d/SimpleMenu.h>
153 #include <X11/Xaw3d/SmeBSB.h>
154 #include <X11/Xaw3d/SmeLine.h>
155 #include <X11/Xaw3d/Box.h>
156 #include <X11/Xaw3d/MenuButton.h>
157 #include <X11/Xaw3d/Text.h>
158 #include <X11/Xaw3d/AsciiText.h>
159 #else
160 #include <X11/Xaw/Dialog.h>
161 #include <X11/Xaw/Form.h>
162 #include <X11/Xaw/List.h>
163 #include <X11/Xaw/Label.h>
164 #include <X11/Xaw/SimpleMenu.h>
165 #include <X11/Xaw/SmeBSB.h>
166 #include <X11/Xaw/SmeLine.h>
167 #include <X11/Xaw/Box.h>
168 #include <X11/Xaw/MenuButton.h>
169 #include <X11/Xaw/Text.h>
170 #include <X11/Xaw/AsciiText.h>
171 #endif
172
173 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
174 #include "common.h"
175
176 #if HAVE_LIBXPM
177 #include <X11/xpm.h>
178 #include "pixmaps/pixmaps.h"
179 #define IMAGE_EXT "xpm"
180 #else
181 #define IMAGE_EXT "xim"
182 #include "bitmaps/bitmaps.h"
183 #endif
184
185 #include "bitmaps/icon_white.bm"
186 #include "bitmaps/icon_black.bm"
187 #include "bitmaps/checkmark.bm"
188
189 #include "frontend.h"
190 #include "backend.h"
191 #include "moves.h"
192 #include "xboard.h"
193 #include "childio.h"
194 #include "xgamelist.h"
195 #include "xhistory.h"
196 #include "xedittags.h"
197 #include "gettext.h"
198
199 // must be moved to xengineoutput.h
200
201 void EngineOutputProc P((Widget w, XEvent *event,
202  String *prms, Cardinal *nprms));
203
204 void EngineOutputPopDown();
205
206
207 #ifdef __EMX__
208 #ifndef HAVE_USLEEP
209 #define HAVE_USLEEP
210 #endif
211 #define usleep(t)   _sleep2(((t)+500)/1000)
212 #endif
213
214 #ifdef ENABLE_NLS
215 # define  _(s) gettext (s)
216 # define N_(s) gettext_noop (s)
217 #else
218 # define  _(s) (s)
219 # define N_(s)  s
220 #endif
221
222 typedef struct {
223     String string;
224     XtActionProc proc;
225 } MenuItem;
226
227 typedef struct {
228     String name;
229     MenuItem *mi;
230 } Menu;
231
232 int main P((int argc, char **argv));
233 RETSIGTYPE CmailSigHandler P((int sig));
234 RETSIGTYPE IntSigHandler P((int sig));
235 void CreateGCs P((void));
236 void CreateXIMPieces P((void));
237 void CreateXPMPieces P((void));
238 void CreatePieces P((void));
239 void CreatePieceMenus P((void));
240 Widget CreateMenuBar P((Menu *mb));
241 Widget CreateButtonBar P ((MenuItem *mi));
242 char *FindFont P((char *pattern, int targetPxlSize));
243 void PieceMenuPopup P((Widget w, XEvent *event,
244                        String *params, Cardinal *num_params));
245 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
246 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
247 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
248                    u_int wreq, u_int hreq));
249 void CreateGrid P((void));
250 int EventToSquare P((int x, int limit));
251 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
252 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
253 void HandleUserMove P((Widget w, XEvent *event,
254                      String *prms, Cardinal *nprms));
255 void AnimateUserMove P((Widget w, XEvent * event,
256                      String * params, Cardinal * nParams));
257 void WhiteClock P((Widget w, XEvent *event,
258                    String *prms, Cardinal *nprms));
259 void BlackClock P((Widget w, XEvent *event,
260                    String *prms, Cardinal *nprms));
261 void DrawPositionProc P((Widget w, XEvent *event,
262                      String *prms, Cardinal *nprms));
263 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
264                      Board board));
265 void CommentPopUp P((char *title, char *label));
266 void CommentPopDown P((void));
267 void CommentCallback P((Widget w, XtPointer client_data,
268                         XtPointer call_data));
269 void ICSInputBoxPopUp P((void));
270 void ICSInputBoxPopDown P((void));
271 void FileNamePopUp P((char *label, char *def,
272                       FileProc proc, char *openMode));
273 void FileNamePopDown P((void));
274 void FileNameCallback P((Widget w, XtPointer client_data,
275                          XtPointer call_data));
276 void FileNameAction P((Widget w, XEvent *event,
277                        String *prms, Cardinal *nprms));
278 void AskQuestionReplyAction P((Widget w, XEvent *event,
279                           String *prms, Cardinal *nprms));
280 void AskQuestionProc P((Widget w, XEvent *event,
281                           String *prms, Cardinal *nprms));
282 void AskQuestionPopDown P((void));
283 void PromotionPopUp P((void));
284 void PromotionPopDown P((void));
285 void PromotionCallback P((Widget w, XtPointer client_data,
286                           XtPointer call_data));
287 void EditCommentPopDown P((void));
288 void EditCommentCallback P((Widget w, XtPointer client_data,
289                             XtPointer call_data));
290 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
291 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
292 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
293 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
294                          Cardinal *nprms));
295 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
296                          Cardinal *nprms));
297 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
298                        Cardinal *nprms));
299 void LoadPositionProc P((Widget w, XEvent *event,
300                          String *prms, Cardinal *nprms));
301 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
302                          Cardinal *nprms));
303 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
304                          Cardinal *nprms));
305 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
306                        Cardinal *nprms));
307 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
308                          Cardinal *nprms));
309 void PastePositionProc P((Widget w, XEvent *event, String *prms,
310                           Cardinal *nprms));
311 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
312 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
313 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
314 void SavePositionProc P((Widget w, XEvent *event,
315                          String *prms, Cardinal *nprms));
316 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
317 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
318                             Cardinal *nprms));
319 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
320 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
321 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
322                          Cardinal *nprms));
323 void MachineWhiteProc P((Widget w, XEvent *event,
324                          String *prms, Cardinal *nprms));
325 void AnalyzeModeProc P((Widget w, XEvent *event,
326                          String *prms, Cardinal *nprms));
327 void AnalyzeFileProc P((Widget w, XEvent *event,
328                          String *prms, Cardinal *nprms));
329 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
330                         Cardinal *nprms));
331 void IcsClientProc P((Widget w, XEvent *event, String *prms,
332                       Cardinal *nprms));
333 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
334 void EditPositionProc P((Widget w, XEvent *event,
335                          String *prms, Cardinal *nprms));
336 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
337 void EditCommentProc P((Widget w, XEvent *event,
338                         String *prms, Cardinal *nprms));
339 void IcsInputBoxProc P((Widget w, XEvent *event,
340                         String *prms, Cardinal *nprms));
341 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
342 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
343 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
344 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
345 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
346 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
347 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
348 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
349 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
350 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
351 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
352 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
353 void StopObservingProc P((Widget w, XEvent *event, String *prms,
354                           Cardinal *nprms));
355 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
356                           Cardinal *nprms));
357 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
358 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
359 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
363                          Cardinal *nprms));
364 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
365                         Cardinal *nprms));
366 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
368                         Cardinal *nprms));
369 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
370                          Cardinal *nprms));
371 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
372                          Cardinal *nprms));
373 void AutocommProc P((Widget w, XEvent *event, String *prms,
374                      Cardinal *nprms));
375 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
376 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
377 void AutobsProc P((Widget w, XEvent *event, String *prms,
378                         Cardinal *nprms));
379 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
380 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
383                        Cardinal *nprms));
384 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
385 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
386                         Cardinal *nprms));
387 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
388                               Cardinal *nprms));
389 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
390                               Cardinal *nprms));
391 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
392 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
393 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
394                          Cardinal *nprms));
395 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
396                          Cardinal *nprms));
397 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
398                            Cardinal *nprms));
399 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
400                         Cardinal *nprms));
401 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
402                              Cardinal *nprms));
403 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
404 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
405 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
406                        Cardinal *nprms));
407 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
408                          Cardinal *nprms));
409 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
410                          Cardinal *nprms));
411 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
412                           Cardinal *nprms));
413 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
414 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
415 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
416 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
417 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
418 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
419 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
420 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
421 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
422 void DisplayMove P((int moveNumber));
423 void DisplayTitle P((char *title));
424 void ICSInitScript P((void));
425 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
426 void ErrorPopUp P((char *title, char *text, int modal));
427 void ErrorPopDown P((void));
428 static char *ExpandPathName P((char *path));
429 static void CreateAnimVars P((void));
430 static void DragPieceBegin P((int x, int y));
431 static void DragPieceMove P((int x, int y));
432 static void DragPieceEnd P((int x, int y));
433 static void DrawDragPiece P((void));
434 char *ModeToWidgetName P((GameMode mode));
435 void EngineOutputUpdate( FrontEndProgramStats * stats );
436 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
437 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
442 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
443 void ShufflePopDown P(());
444 void EnginePopDown P(());
445 void UciPopDown P(());
446 void TimeControlPopDown P(());
447 void NewVariantPopDown P(());
448 void SettingsPopDown P(());
449 /*
450 * XBoard depends on Xt R4 or higher
451 */
452 int xtVersion = XtSpecificationRelease;
453
454 int xScreen;
455 Display *xDisplay;
456 Window xBoardWindow;
457 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
458   jailSquareColor, highlightSquareColor, premoveHighlightColor;
459 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
460   bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
461   wjPieceGC, bjPieceGC, prelineGC, countGC;
462 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
463 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
464   whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
465   commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
466   menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
467   ICSInputShell, fileNameShell, askQuestionShell;
468 XSegment gridSegments[(BOARD_SIZE + 1) * 2];
469 XSegment jailGridSegments[(BOARD_SIZE + 3) * 2];
470 Font clockFontID, coordFontID, countFontID;
471 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
472 XtAppContext appContext;
473 char *layoutName;
474 char *oldICSInteractionTitle;
475
476 FileProc fileProc;
477 char *fileOpenMode;
478 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
479
480 Position commentX = -1, commentY = -1;
481 Dimension commentW, commentH;
482
483 int squareSize, smallLayout = 0, tinyLayout = 0,
484   marginW, marginH, // [HGM] for run-time resizing
485   fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
486   ICSInputBoxUp = False, askQuestionUp = False,
487   filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
488   editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
489 Pixel timerForegroundPixel, timerBackgroundPixel;
490 Pixel buttonForegroundPixel, buttonBackgroundPixel;
491 char *chessDir, *programName, *programVersion,
492   *gameCopyFilename, *gamePasteFilename;
493
494 #define SOLID 0
495 #define OUTLINE 1
496 Pixmap pieceBitmap[2][(int)BlackPawn];
497 Pixmap xpmPieceBitmap[4][(int)BlackPawn];       /* LL, LD, DL, DD */
498 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
499 int useImages, useImageSqs;
500 XImage *ximPieceBitmap[4][(int)BlackPawn];      /* LL, LD, DL, DD */
501 Pixmap ximMaskPm[(int)BlackPawn];            /* clipmasks, used for XIM pieces */
502 XImage *ximLightSquare, *ximDarkSquare;
503 XImage *xim_Cross;
504
505 #define pieceToSolid(piece) &pieceBitmap[SOLID][((int)(piece)) % (int)BlackPawn]
506 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][((int)(piece)) % (int)BlackPawn]
507
508 #define White(piece) ((int)(piece) < (int)BlackPawn)
509
510 /* Variables for doing smooth animation. This whole thing
511    would be much easier if the board was double-buffered,
512    but that would require a fairly major rewrite.       */
513
514 typedef struct {
515         Pixmap  saveBuf;
516         Pixmap  newBuf;
517         GC      blitGC, pieceGC, outlineGC;
518         XPoint  startSquare, prevFrame, mouseDelta;
519         int     startColor;
520         int     dragPiece;
521         Boolean dragActive;
522         int     startBoardX, startBoardY;
523     } AnimState;
524
525 /* There can be two pieces being animated at once: a player
526    can begin dragging a piece before the remote opponent has moved. */
527
528 static AnimState game, player;
529
530 /* Bitmaps for use as masks when drawing XPM pieces.
531    Need one for each black and white piece.             */
532 static Pixmap xpmMask[BlackKing + 1];
533
534 /* This magic number is the number of intermediate frames used
535    in each half of the animation. For short moves it's reduced
536    by 1. The total number of frames will be factor * 2 + 1.  */
537 #define kFactor    4
538
539 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
540
541 MenuItem fileMenu[] = {
542     {N_("New Game"), ResetProc},
543     {N_("New Shuffle Game ..."), ShuffleMenuProc},
544     {N_("New Variant ..."), NewVariantProc},      // [HGM] variant: not functional yet
545     {"----", NothingProc},
546     {N_("Load Game"), LoadGameProc},
547     {N_("Load Next Game"), LoadNextGameProc},
548     {N_("Load Previous Game"), LoadPrevGameProc},
549     {N_("Reload Same Game"), ReloadGameProc},
550     {N_("Save Game"), SaveGameProc},
551     {"----", NothingProc},
552     {N_("Copy Game"), CopyGameProc},
553     {N_("Paste Game"), PasteGameProc},
554     {"----", NothingProc},
555     {N_("Load Position"), LoadPositionProc},
556     {N_("Load Next Position"), LoadNextPositionProc},
557     {N_("Load Previous Position"), LoadPrevPositionProc},
558     {N_("Reload Same Position"), ReloadPositionProc},
559     {N_("Save Position"), SavePositionProc},
560     {"----", NothingProc},
561     {N_("Copy Position"), CopyPositionProc},
562     {N_("Paste Position"), PastePositionProc},
563     {"----", NothingProc},
564     {N_("Mail Move"), MailMoveProc},
565     {N_("Reload CMail Message"), ReloadCmailMsgProc},
566     {"----", NothingProc},
567     {N_("Exit"), QuitProc},
568     {NULL, NULL}
569 };
570
571 MenuItem modeMenu[] = {
572     {N_("Machine White"), MachineWhiteProc},
573     {N_("Machine Black"), MachineBlackProc},
574     {N_("Two Machines"), TwoMachinesProc},
575     {N_("Analysis Mode"), AnalyzeModeProc},
576     {N_("Analyze File"), AnalyzeFileProc },
577     {N_("ICS Client"), IcsClientProc},
578     {N_("Edit Game"), EditGameProc},
579     {N_("Edit Position"), EditPositionProc},
580     {N_("Training"), TrainingProc},
581     {"----", NothingProc},
582     {N_("Show Engine Output"), EngineOutputProc},
583     {N_("Show Evaluation Graph"), NothingProc}, // [HGM] evalgr: not functional yet
584     {N_("Show Game List"), ShowGameListProc},
585     {"Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
586     {"----", NothingProc},
587     {N_("Edit Tags"), EditTagsProc},
588     {N_("Edit Comment"), EditCommentProc},
589     {N_("ICS Input Box"), IcsInputBoxProc},
590     {N_("Pause"), PauseProc},
591     {NULL, NULL}
592 };
593
594 MenuItem actionMenu[] = {
595     {N_("Accept"), AcceptProc},
596     {N_("Decline"), DeclineProc},
597     {N_("Rematch"), RematchProc},
598     {"----", NothingProc},
599     {N_("Call Flag"), CallFlagProc},
600     {N_("Draw"), DrawProc},
601     {N_("Adjourn"), AdjournProc},
602     {N_("Abort"), AbortProc},
603     {N_("Resign"), ResignProc},
604     {"----", NothingProc},
605     {N_("Stop Observing"), StopObservingProc},
606     {N_("Stop Examining"), StopExaminingProc},
607     {"----", NothingProc},
608     {N_("Adjudicate to White"), AdjuWhiteProc},
609     {N_("Adjudicate to Black"), AdjuBlackProc},
610     {N_("Adjudicate Draw"), AdjuDrawProc},
611     {NULL, NULL}
612 };
613
614 MenuItem stepMenu[] = {
615     {N_("Backward"), BackwardProc},
616     {N_("Forward"), ForwardProc},
617     {N_("Back to Start"), ToStartProc},
618     {N_("Forward to End"), ToEndProc},
619     {N_("Revert"), RevertProc},
620     {N_("Truncate Game"), TruncateGameProc},
621     {"----", NothingProc},
622     {N_("Move Now"), MoveNowProc},
623     {N_("Retract Move"), RetractMoveProc},
624     {NULL, NULL}
625 };
626
627 MenuItem optionsMenu[] = {
628     {N_("Flip View"), FlipViewProc},
629     {"----", NothingProc},
630     {N_("Adjudications ..."), EngineMenuProc},
631     {N_("General Settings ..."), UciMenuProc},
632     {N_("Engine #1 Settings ..."), FirstSettingsProc},
633     {N_("Engine #2 Settings ..."), SecondSettingsProc},
634     {N_("Time Control ..."), TimeControlProc},
635     {"----", NothingProc},
636     {N_("Always Queen"), AlwaysQueenProc},
637     {N_("Animate Dragging"), AnimateDraggingProc},
638     {N_("Animate Moving"), AnimateMovingProc},
639     {N_("Auto Comment"), AutocommProc},
640     {N_("Auto Flag"), AutoflagProc},
641     {N_("Auto Flip View"), AutoflipProc},
642     {N_("Auto Observe"), AutobsProc},
643     {N_("Auto Raise Board"), AutoraiseProc},
644     {N_("Auto Save"), AutosaveProc},
645     {N_("Blindfold"), BlindfoldProc},
646     {N_("Flash Moves"), FlashMovesProc},
647     {N_("Get Move List"), GetMoveListProc},
648 #if HIGHDRAG
649     {N_("Highlight Dragging"), HighlightDraggingProc},
650 #endif
651     {N_("Highlight Last Move"), HighlightLastMoveProc},
652     {N_("Move Sound"), MoveSoundProc},
653     {N_("ICS Alarm"), IcsAlarmProc},
654     {N_("Old Save Style"), OldSaveStyleProc},
655     {N_("Periodic Updates"), PeriodicUpdatesProc},
656     {N_("Ponder Next Move"), PonderNextMoveProc},
657     {N_("Popup Exit Message"), PopupExitMessageProc},
658     {N_("Popup Move Errors"), PopupMoveErrorsProc},
659     {N_("Premove"), PremoveProc},
660     {N_("Quiet Play"), QuietPlayProc},
661     {N_("Show Coords"), ShowCoordsProc},
662     {N_("Hide Thinking"), HideThinkingProc},
663     {N_("Test Legality"), TestLegalityProc},
664     {NULL, NULL}
665 };
666
667 MenuItem helpMenu[] = {
668     {N_("Info XBoard"), InfoProc},
669     {N_("Man XBoard"), ManProc},
670     {"----", NothingProc},
671     {N_("Hint"), HintProc},
672     {N_("Book"), BookProc},
673     {"----", NothingProc},
674     {N_("About XBoard"), AboutProc},
675     {NULL, NULL}
676 };
677
678 Menu menuBar[] = {
679     {N_("File"), fileMenu},
680     {N_("Mode"), modeMenu},
681     {N_("Action"), actionMenu},
682     {N_("Step"), stepMenu},
683     {N_("Options"), optionsMenu},
684     {N_("Help"), helpMenu},
685     {NULL, NULL}
686 };
687
688 #define PAUSE_BUTTON N_("P")
689 MenuItem buttonBar[] = {
690     {"<<", ToStartProc},
691     {"<", BackwardProc},
692     {PAUSE_BUTTON, PauseProc},
693     {">", ForwardProc},
694     {">>", ToEndProc},
695     {NULL, NULL}
696 };
697
698 #define PIECE_MENU_SIZE 11
699 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
700     { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
701       N_("Queen"), N_("King"), "----", N_("Empty square"), N_("Clear board") },
702     { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
703       N_("Queen"), N_("King"), "----", N_("Empty square"), N_("Clear board") },
704 };
705 /* must be in same order as PieceMenuStrings! */
706 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
707     { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
708         WhiteRook, WhiteQueen, WhiteKing,
709         (ChessSquare) 0, EmptySquare, ClearBoard },
710     { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
711         BlackRook, BlackQueen, BlackKing,
712         (ChessSquare) 0, EmptySquare, ClearBoard },
713 };
714
715 #define DROP_MENU_SIZE 6
716 String dropMenuStrings[DROP_MENU_SIZE] = {
717     "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
718   };
719 /* must be in same order as PieceMenuStrings! */
720 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
721     (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
722     WhiteRook, WhiteQueen
723 };
724
725 typedef struct {
726     char piece;
727     char* widget;
728 } DropMenuEnables;
729
730 DropMenuEnables dmEnables[] = {
731     { 'P', "Pawn" },
732     { 'N', "Knight" },
733     { 'B', "Bishop" },
734     { 'R', "Rook" },
735     { 'Q', "Queen" }
736 };
737
738 Arg shellArgs[] = {
739     { XtNwidth, 0 },
740     { XtNheight, 0 },
741     { XtNminWidth, 0 },
742     { XtNminHeight, 0 },
743     { XtNmaxWidth, 0 },
744     { XtNmaxHeight, 0 }
745 };
746
747 Arg layoutArgs[] = {
748     { XtNborderWidth, 0 },
749     { XtNdefaultDistance, 0 },
750 };
751
752 Arg formArgs[] = {
753     { XtNborderWidth, 0 },
754     { XtNresizable, (XtArgVal) True },
755 };
756
757 Arg boardArgs[] = {
758     { XtNborderWidth, 0 },
759     { XtNwidth, 0 },
760     { XtNheight, 0 }
761 };
762
763 Arg titleArgs[] = {
764     { XtNjustify, (XtArgVal) XtJustifyRight },
765     { XtNlabel, (XtArgVal) "..." },
766     { XtNresizable, (XtArgVal) True },
767     { XtNresize, (XtArgVal) False }
768 };
769
770 Arg messageArgs[] = {
771     { XtNjustify, (XtArgVal) XtJustifyLeft },
772     { XtNlabel, (XtArgVal) "..." },
773     { XtNresizable, (XtArgVal) True },
774     { XtNresize, (XtArgVal) False }
775 };
776
777 Arg timerArgs[] = {
778     { XtNborderWidth, 0 },
779     { XtNjustify, (XtArgVal) XtJustifyLeft }
780 };
781
782 XtResource clientResources[] = {
783     { "whitePieceColor", "whitePieceColor", XtRString, sizeof(String),
784         XtOffset(AppDataPtr, whitePieceColor), XtRString,
785         WHITE_PIECE_COLOR },
786     { "blackPieceColor", "blackPieceColor", XtRString, sizeof(String),
787         XtOffset(AppDataPtr, blackPieceColor), XtRString,
788         BLACK_PIECE_COLOR },
789     { "lightSquareColor", "lightSquareColor", XtRString,
790         sizeof(String), XtOffset(AppDataPtr, lightSquareColor),
791         XtRString, LIGHT_SQUARE_COLOR },
792     { "darkSquareColor", "darkSquareColor", XtRString, sizeof(String),
793         XtOffset(AppDataPtr, darkSquareColor), XtRString,
794         DARK_SQUARE_COLOR },
795     { "highlightSquareColor", "highlightSquareColor", XtRString,
796         sizeof(String), XtOffset(AppDataPtr, highlightSquareColor),
797         XtRString, HIGHLIGHT_SQUARE_COLOR },
798     { "premoveHighlightColor", "premoveHighlightColor", XtRString,
799         sizeof(String), XtOffset(AppDataPtr, premoveHighlightColor),
800         XtRString, PREMOVE_HIGHLIGHT_COLOR },
801     { "movesPerSession", "movesPerSession", XtRInt, sizeof(int),
802         XtOffset(AppDataPtr, movesPerSession), XtRImmediate,
803         (XtPointer) MOVES_PER_SESSION },
804     { "timeIncrement", "timeIncrement", XtRInt, sizeof(int),
805         XtOffset(AppDataPtr, timeIncrement), XtRImmediate,
806         (XtPointer) TIME_INCREMENT },
807     { "initString", "initString", XtRString, sizeof(String),
808         XtOffset(AppDataPtr, initString), XtRString, INIT_STRING },
809     { "secondInitString", "secondInitString", XtRString, sizeof(String),
810         XtOffset(AppDataPtr, secondInitString), XtRString, INIT_STRING },
811     { "firstComputerString", "firstComputerString", XtRString,
812         sizeof(String), XtOffset(AppDataPtr, firstComputerString), XtRString,
813       COMPUTER_STRING },
814     { "secondComputerString", "secondComputerString", XtRString,
815         sizeof(String), XtOffset(AppDataPtr, secondComputerString), XtRString,
816       COMPUTER_STRING },
817     { "firstChessProgram", "firstChessProgram", XtRString,
818         sizeof(String), XtOffset(AppDataPtr, firstChessProgram),
819         XtRString, FIRST_CHESS_PROGRAM },
820     { "secondChessProgram", "secondChessProgram", XtRString,
821         sizeof(String), XtOffset(AppDataPtr, secondChessProgram),
822         XtRString, SECOND_CHESS_PROGRAM },
823     { "firstPlaysBlack", "firstPlaysBlack", XtRBoolean,
824         sizeof(Boolean), XtOffset(AppDataPtr, firstPlaysBlack),
825         XtRImmediate, (XtPointer) False },
826     { "noChessProgram", "noChessProgram", XtRBoolean,
827         sizeof(Boolean), XtOffset(AppDataPtr, noChessProgram),
828         XtRImmediate, (XtPointer) False },
829     { "firstHost", "firstHost", XtRString, sizeof(String),
830         XtOffset(AppDataPtr, firstHost), XtRString, FIRST_HOST },
831     { "secondHost", "secondHost", XtRString, sizeof(String),
832         XtOffset(AppDataPtr, secondHost), XtRString, SECOND_HOST },
833     { "firstDirectory", "firstDirectory", XtRString, sizeof(String),
834         XtOffset(AppDataPtr, firstDirectory), XtRString, "." },
835     { "secondDirectory", "secondDirectory", XtRString, sizeof(String),
836         XtOffset(AppDataPtr, secondDirectory), XtRString, "." },
837     { "bitmapDirectory", "bitmapDirectory", XtRString,
838         sizeof(String), XtOffset(AppDataPtr, bitmapDirectory),
839         XtRString, "" },
840     { "remoteShell", "remoteShell", XtRString, sizeof(String),
841         XtOffset(AppDataPtr, remoteShell), XtRString, REMOTE_SHELL },
842     { "remoteUser", "remoteUser", XtRString, sizeof(String),
843         XtOffset(AppDataPtr, remoteUser), XtRString, "" },
844     { "timeDelay", "timeDelay", XtRFloat, sizeof(float),
845         XtOffset(AppDataPtr, timeDelay), XtRString,
846         (XtPointer) TIME_DELAY_QUOTE },
847     { "timeControl", "timeControl", XtRString, sizeof(String),
848         XtOffset(AppDataPtr, timeControl), XtRString,
849         (XtPointer) TIME_CONTROL },
850     { "internetChessServerMode", "internetChessServerMode",
851         XtRBoolean, sizeof(Boolean),
852         XtOffset(AppDataPtr, icsActive), XtRImmediate,
853         (XtPointer) False },
854     { "internetChessServerHost", "internetChessServerHost",
855         XtRString, sizeof(String),
856         XtOffset(AppDataPtr, icsHost),
857         XtRString, (XtPointer) ICS_HOST },
858     { "internetChessServerPort", "internetChessServerPort",
859         XtRString, sizeof(String),
860         XtOffset(AppDataPtr, icsPort), XtRString,
861         (XtPointer) ICS_PORT },
862     { "internetChessServerCommPort", "internetChessServerCommPort",
863         XtRString, sizeof(String),
864         XtOffset(AppDataPtr, icsCommPort), XtRString,
865         ICS_COMM_PORT },
866     { "internetChessServerLogonScript", "internetChessServerLogonScript",
867         XtRString, sizeof(String),
868         XtOffset(AppDataPtr, icsLogon), XtRString,
869         ICS_LOGON },
870     { "internetChessServerHelper", "internetChessServerHelper",
871         XtRString, sizeof(String),
872         XtOffset(AppDataPtr, icsHelper), XtRString, "" },
873     { "internetChessServerInputBox", "internetChessServerInputBox",
874         XtRBoolean, sizeof(Boolean),
875         XtOffset(AppDataPtr, icsInputBox), XtRImmediate,
876         (XtPointer) False },
877     { "icsAlarm", "icsAlarm",
878         XtRBoolean, sizeof(Boolean),
879         XtOffset(AppDataPtr, icsAlarm), XtRImmediate,
880         (XtPointer) True },
881     { "icsAlarmTime", "icsAlarmTime",
882         XtRInt, sizeof(int),
883         XtOffset(AppDataPtr, icsAlarmTime), XtRImmediate,
884         (XtPointer) 5000 },
885     { "useTelnet", "useTelnet", XtRBoolean, sizeof(Boolean),
886         XtOffset(AppDataPtr, useTelnet), XtRImmediate,
887         (XtPointer) False },
888     { "telnetProgram", "telnetProgram", XtRString, sizeof(String),
889         XtOffset(AppDataPtr, telnetProgram), XtRString, TELNET_PROGRAM },
890     { "gateway", "gateway", XtRString, sizeof(String),
891         XtOffset(AppDataPtr, gateway), XtRString, "" },
892     { "loadGameFile", "loadGameFile", XtRString, sizeof(String),
893         XtOffset(AppDataPtr, loadGameFile), XtRString, "" },
894     { "loadGameIndex", "loadGameIndex",
895         XtRInt, sizeof(int),
896         XtOffset(AppDataPtr, loadGameIndex), XtRImmediate,
897         (XtPointer) 0 },
898     { "saveGameFile", "saveGameFile", XtRString, sizeof(String),
899         XtOffset(AppDataPtr, saveGameFile), XtRString, "" },
900     { "autoRaiseBoard", "autoRaiseBoard", XtRBoolean,
901         sizeof(Boolean), XtOffset(AppDataPtr, autoRaiseBoard),
902         XtRImmediate, (XtPointer) True },
903     { "autoSaveGames", "autoSaveGames", XtRBoolean,
904         sizeof(Boolean), XtOffset(AppDataPtr, autoSaveGames),
905         XtRImmediate, (XtPointer) False },
906     { "blindfold", "blindfold", XtRBoolean,
907         sizeof(Boolean), XtOffset(AppDataPtr, blindfold),
908         XtRImmediate, (XtPointer) False },
909     { "loadPositionFile", "loadPositionFile", XtRString,
910         sizeof(String), XtOffset(AppDataPtr, loadPositionFile),
911         XtRString, "" },
912     { "loadPositionIndex", "loadPositionIndex",
913         XtRInt, sizeof(int),
914         XtOffset(AppDataPtr, loadPositionIndex), XtRImmediate,
915         (XtPointer) 1 },
916     { "savePositionFile", "savePositionFile", XtRString,
917         sizeof(String), XtOffset(AppDataPtr, savePositionFile),
918         XtRString, "" },
919     { "matchMode", "matchMode", XtRBoolean, sizeof(Boolean),
920         XtOffset(AppDataPtr, matchMode), XtRImmediate, (XtPointer) False },
921     { "matchGames", "matchGames", XtRInt, sizeof(int),
922         XtOffset(AppDataPtr, matchGames), XtRImmediate,
923         (XtPointer) 0 },
924     { "monoMode", "monoMode", XtRBoolean, sizeof(Boolean),
925         XtOffset(AppDataPtr, monoMode), XtRImmediate,
926         (XtPointer) False },
927     { "debugMode", "debugMode", XtRBoolean, sizeof(Boolean),
928         XtOffset(AppDataPtr, debugMode), XtRImmediate,
929         (XtPointer) False },
930     { "clockMode", "clockMode", XtRBoolean, sizeof(Boolean),
931         XtOffset(AppDataPtr, clockMode), XtRImmediate,
932         (XtPointer) True },
933     { "boardSize", "boardSize", XtRString, sizeof(String),
934         XtOffset(AppDataPtr, boardSize), XtRString, "" },
935     { "searchTime", "searchTime", XtRString, sizeof(String),
936         XtOffset(AppDataPtr, searchTime), XtRString,
937         (XtPointer) "" },
938     { "searchDepth", "searchDepth", XtRInt, sizeof(int),
939         XtOffset(AppDataPtr, searchDepth), XtRImmediate,
940         (XtPointer) 0 },
941     { "showCoords", "showCoords", XtRBoolean, sizeof(Boolean),
942         XtOffset(AppDataPtr, showCoords), XtRImmediate,
943         (XtPointer) False },
944     { "showJail", "showJail", XtRInt, sizeof(int),
945         XtOffset(AppDataPtr, showJail), XtRImmediate,
946         (XtPointer) 0 },
947     { "showThinking", "showThinking", XtRBoolean, sizeof(Boolean),
948         XtOffset(AppDataPtr, showThinking), XtRImmediate,
949         (XtPointer) True },
950     { "ponderNextMove", "ponderNextMove", XtRBoolean, sizeof(Boolean),
951         XtOffset(AppDataPtr, ponderNextMove), XtRImmediate,
952         (XtPointer) True },
953     { "periodicUpdates", "periodicUpdates", XtRBoolean, sizeof(Boolean),
954         XtOffset(AppDataPtr, periodicUpdates), XtRImmediate,
955         (XtPointer) True },
956     { "clockFont", "clockFont", XtRString, sizeof(String),
957         XtOffset(AppDataPtr, clockFont), XtRString, CLOCK_FONT },
958     { "coordFont", "coordFont", XtRString, sizeof(String),
959         XtOffset(AppDataPtr, coordFont), XtRString, COORD_FONT },
960     { "font", "font", XtRString, sizeof(String),
961         XtOffset(AppDataPtr, font), XtRString, DEFAULT_FONT },
962     { "ringBellAfterMoves", "ringBellAfterMoves",
963         XtRBoolean, sizeof(Boolean),
964         XtOffset(AppDataPtr, ringBellAfterMoves),
965         XtRImmediate, (XtPointer) False },
966     { "autoCallFlag", "autoCallFlag", XtRBoolean,
967         sizeof(Boolean), XtOffset(AppDataPtr, autoCallFlag),
968         XtRImmediate, (XtPointer) False },
969     { "autoFlipView", "autoFlipView", XtRBoolean,
970         sizeof(Boolean), XtOffset(AppDataPtr, autoFlipView),
971         XtRImmediate, (XtPointer) True },
972     { "autoObserve", "autoObserve", XtRBoolean,
973         sizeof(Boolean), XtOffset(AppDataPtr, autoObserve),
974         XtRImmediate, (XtPointer) False },
975     { "autoComment", "autoComment", XtRBoolean,
976         sizeof(Boolean), XtOffset(AppDataPtr, autoComment),
977         XtRImmediate, (XtPointer) False },
978     { "getMoveList", "getMoveList", XtRBoolean,
979         sizeof(Boolean), XtOffset(AppDataPtr, getMoveList),
980         XtRImmediate, (XtPointer) True },
981 #if HIGHDRAG
982     { "highlightDragging", "highlightDragging", XtRBoolean,
983         sizeof(Boolean), XtOffset(AppDataPtr, highlightDragging),
984         XtRImmediate, (XtPointer) False },
985 #endif
986     { "highlightLastMove", "highlightLastMove", XtRBoolean,
987         sizeof(Boolean), XtOffset(AppDataPtr, highlightLastMove),
988         XtRImmediate, (XtPointer) False },
989     { "premove", "premove", XtRBoolean,
990         sizeof(Boolean), XtOffset(AppDataPtr, premove),
991         XtRImmediate, (XtPointer) True },
992     { "testLegality", "testLegality", XtRBoolean,
993         sizeof(Boolean), XtOffset(AppDataPtr, testLegality),
994         XtRImmediate, (XtPointer) True },
995     { "flipView", "flipView", XtRBoolean,
996         sizeof(Boolean), XtOffset(AppDataPtr, flipView),
997         XtRImmediate, (XtPointer) False },
998     { "cmail", "cmailGameName", XtRString, sizeof(String),
999         XtOffset(AppDataPtr, cmailGameName), XtRString, "" },
1000     { "alwaysPromoteToQueen", "alwaysPromoteToQueen", XtRBoolean,
1001         sizeof(Boolean), XtOffset(AppDataPtr, alwaysPromoteToQueen),
1002         XtRImmediate, (XtPointer) False },
1003     { "oldSaveStyle", "oldSaveStyle", XtRBoolean,
1004         sizeof(Boolean), XtOffset(AppDataPtr, oldSaveStyle),
1005         XtRImmediate, (XtPointer) False },
1006     { "quietPlay", "quietPlay", XtRBoolean,
1007         sizeof(Boolean), XtOffset(AppDataPtr, quietPlay),
1008         XtRImmediate, (XtPointer) False },
1009     { "titleInWindow", "titleInWindow", XtRBoolean,
1010         sizeof(Boolean), XtOffset(AppDataPtr, titleInWindow),
1011         XtRImmediate, (XtPointer) False },
1012     { "localLineEditing", "localLineEditing", XtRBoolean,
1013         sizeof(Boolean), XtOffset(AppDataPtr, localLineEditing),
1014         XtRImmediate, (XtPointer) True }, /* not implemented, must be True */
1015 #ifdef ZIPPY
1016     { "zippyTalk", "zippyTalk", XtRBoolean,
1017         sizeof(Boolean), XtOffset(AppDataPtr, zippyTalk),
1018         XtRImmediate, (XtPointer) ZIPPY_TALK },
1019     { "zippyPlay", "zippyPlay", XtRBoolean,
1020         sizeof(Boolean), XtOffset(AppDataPtr, zippyPlay),
1021         XtRImmediate, (XtPointer) ZIPPY_PLAY },
1022     { "zippyLines", "zippyLines", XtRString, sizeof(String),
1023         XtOffset(AppDataPtr, zippyLines), XtRString, ZIPPY_LINES },
1024     { "zippyPinhead", "zippyPinhead", XtRString, sizeof(String),
1025         XtOffset(AppDataPtr, zippyPinhead), XtRString, ZIPPY_PINHEAD },
1026     { "zippyPassword", "zippyPassword", XtRString, sizeof(String),
1027         XtOffset(AppDataPtr, zippyPassword), XtRString, ZIPPY_PASSWORD },
1028     { "zippyPassword2", "zippyPassword2", XtRString, sizeof(String),
1029         XtOffset(AppDataPtr, zippyPassword2), XtRString, ZIPPY_PASSWORD2 },
1030     { "zippyWrongPassword", "zippyWrongPassword", XtRString, sizeof(String),
1031         XtOffset(AppDataPtr, zippyWrongPassword), XtRString,
1032         ZIPPY_WRONG_PASSWORD },
1033     { "zippyAcceptOnly", "zippyAcceptOnly", XtRString, sizeof(String),
1034         XtOffset(AppDataPtr, zippyAcceptOnly), XtRString, ZIPPY_ACCEPT_ONLY },
1035     { "zippyUseI", "zippyUseI", XtRBoolean,
1036         sizeof(Boolean), XtOffset(AppDataPtr, zippyUseI),
1037         XtRImmediate, (XtPointer) ZIPPY_USE_I },
1038     { "zippyBughouse", "zippyBughouse", XtRInt,
1039         sizeof(int), XtOffset(AppDataPtr, zippyBughouse),
1040         XtRImmediate, (XtPointer) ZIPPY_BUGHOUSE },
1041     { "zippyNoplayCrafty", "zippyNoplayCrafty", XtRBoolean,
1042         sizeof(Boolean), XtOffset(AppDataPtr, zippyNoplayCrafty),
1043         XtRImmediate, (XtPointer) ZIPPY_NOPLAY_CRAFTY },
1044     { "zippyGameEnd", "zippyGameEnd", XtRString, sizeof(String),
1045         XtOffset(AppDataPtr, zippyGameEnd), XtRString, ZIPPY_GAME_END },
1046     { "zippyGameStart", "zippyGameStart", XtRString, sizeof(String),
1047         XtOffset(AppDataPtr, zippyGameStart), XtRString, ZIPPY_GAME_START },
1048     { "zippyAdjourn", "zippyAdjourn", XtRBoolean,
1049         sizeof(Boolean), XtOffset(AppDataPtr, zippyAdjourn),
1050         XtRImmediate, (XtPointer) ZIPPY_ADJOURN },
1051     { "zippyAbort", "zippyAbort", XtRBoolean,
1052         sizeof(Boolean), XtOffset(AppDataPtr, zippyAbort),
1053         XtRImmediate, (XtPointer) ZIPPY_ABORT },
1054     { "zippyVariants", "zippyVariants", XtRString, sizeof(String),
1055         XtOffset(AppDataPtr, zippyVariants), XtRString, ZIPPY_VARIANTS },
1056     { "zippyMaxGames", "zippyMaxGames", XtRInt, sizeof(int),
1057         XtOffset(AppDataPtr, zippyMaxGames), XtRImmediate,
1058         (XtPointer) ZIPPY_MAX_GAMES },
1059     { "zippyReplayTimeout", "zippyReplayTimeout", XtRInt, sizeof(int),
1060         XtOffset(AppDataPtr, zippyReplayTimeout), XtRImmediate,
1061         (XtPointer) ZIPPY_REPLAY_TIMEOUT },
1062 #endif
1063     { "flashCount", "flashCount", XtRInt, sizeof(int),
1064         XtOffset(AppDataPtr, flashCount), XtRImmediate,
1065         (XtPointer) FLASH_COUNT  },
1066     { "flashRate", "flashRate", XtRInt, sizeof(int),
1067         XtOffset(AppDataPtr, flashRate), XtRImmediate,
1068         (XtPointer) FLASH_RATE },
1069     { "pixmapDirectory", "pixmapDirectory", XtRString,
1070         sizeof(String), XtOffset(AppDataPtr, pixmapDirectory),
1071         XtRString, "" },
1072     { "msLoginDelay", "msLoginDelay", XtRInt, sizeof(int),
1073         XtOffset(AppDataPtr, msLoginDelay), XtRImmediate,
1074         (XtPointer) MS_LOGIN_DELAY },
1075     { "colorizeMessages", "colorizeMessages", XtRBoolean,
1076         sizeof(Boolean), XtOffset(AppDataPtr, colorize),
1077         XtRImmediate, (XtPointer) False },
1078     { "colorShout", "colorShout", XtRString,
1079         sizeof(String), XtOffset(AppDataPtr, colorShout),
1080         XtRString, COLOR_SHOUT },
1081     { "colorSShout", "colorSShout", XtRString,
1082         sizeof(String), XtOffset(AppDataPtr, colorSShout),
1083         XtRString, COLOR_SSHOUT },
1084     { "colorChannel1", "colorChannel1", XtRString,
1085         sizeof(String), XtOffset(AppDataPtr, colorChannel1),
1086         XtRString, COLOR_CHANNEL1 },
1087     { "colorChannel", "colorChannel", XtRString,
1088         sizeof(String), XtOffset(AppDataPtr, colorChannel),
1089         XtRString, COLOR_CHANNEL },
1090     { "colorKibitz", "colorKibitz", XtRString,
1091         sizeof(String), XtOffset(AppDataPtr, colorKibitz),
1092         XtRString, COLOR_KIBITZ },
1093     { "colorTell", "colorTell", XtRString,
1094         sizeof(String), XtOffset(AppDataPtr, colorTell),
1095         XtRString, COLOR_TELL },
1096     { "colorChallenge", "colorChallenge", XtRString,
1097         sizeof(String), XtOffset(AppDataPtr, colorChallenge),
1098         XtRString, COLOR_CHALLENGE },
1099     { "colorRequest", "colorRequest", XtRString,
1100         sizeof(String), XtOffset(AppDataPtr, colorRequest),
1101         XtRString, COLOR_REQUEST },
1102     { "colorSeek", "colorSeek", XtRString,
1103         sizeof(String), XtOffset(AppDataPtr, colorSeek),
1104         XtRString, COLOR_SEEK },
1105     { "colorNormal", "colorNormal", XtRString,
1106         sizeof(String), XtOffset(AppDataPtr, colorNormal),
1107         XtRString, COLOR_NORMAL },
1108     { "soundProgram", "soundProgram", XtRString,
1109       sizeof(String), XtOffset(AppDataPtr, soundProgram),
1110       XtRString, "play" },
1111     { "soundShout", "soundShout", XtRString,
1112       sizeof(String), XtOffset(AppDataPtr, soundShout),
1113       XtRString, "" },
1114     { "soundSShout", "soundSShout", XtRString,
1115       sizeof(String), XtOffset(AppDataPtr, soundSShout),
1116       XtRString, "" },
1117     { "soundChannel1", "soundChannel1", XtRString,
1118       sizeof(String), XtOffset(AppDataPtr, soundChannel1),
1119       XtRString, "" },
1120     { "soundChannel", "soundChannel", XtRString,
1121       sizeof(String), XtOffset(AppDataPtr, soundChannel),
1122       XtRString, "" },
1123     { "soundKibitz", "soundKibitz", XtRString,
1124       sizeof(String), XtOffset(AppDataPtr, soundKibitz),
1125       XtRString, "" },
1126     { "soundTell", "soundTell", XtRString,
1127       sizeof(String), XtOffset(AppDataPtr, soundTell),
1128       XtRString, "" },
1129     { "soundChallenge", "soundChallenge", XtRString,
1130       sizeof(String), XtOffset(AppDataPtr, soundChallenge),
1131       XtRString, "" },
1132     { "soundRequest", "soundRequest", XtRString,
1133       sizeof(String), XtOffset(AppDataPtr, soundRequest),
1134       XtRString, "" },
1135     { "soundSeek", "soundSeek", XtRString,
1136       sizeof(String), XtOffset(AppDataPtr, soundSeek),
1137       XtRString, "" },
1138     { "soundMove", "soundMove", XtRString,
1139       sizeof(String), XtOffset(AppDataPtr, soundMove),
1140       XtRString, "$" },
1141     { "soundIcsWin", "soundIcsWin", XtRString,
1142       sizeof(String), XtOffset(AppDataPtr, soundIcsWin),
1143       XtRString, "" },
1144     { "soundIcsLoss", "soundIcsLoss", XtRString,
1145       sizeof(String), XtOffset(AppDataPtr, soundIcsLoss),
1146       XtRString, "" },
1147     { "soundIcsDraw", "soundIcsDraw", XtRString,
1148       sizeof(String), XtOffset(AppDataPtr, soundIcsDraw),
1149       XtRString, "" },
1150     { "soundIcsUnfinished", "soundIcsUnfinished", XtRString,
1151       sizeof(String), XtOffset(AppDataPtr, soundIcsUnfinished),
1152       XtRString, "" },
1153     { "soundIcsAlarm", "soundIcsAlarm", XtRString,
1154       sizeof(String), XtOffset(AppDataPtr, soundIcsAlarm),
1155       XtRString, "$" },
1156     { "reuseFirst", "reuseFirst", XtRBoolean,
1157         sizeof(Boolean), XtOffset(AppDataPtr, reuseFirst),
1158         XtRImmediate, (XtPointer) True },
1159     { "reuseSecond", "reuseSecond", XtRBoolean,
1160         sizeof(Boolean), XtOffset(AppDataPtr, reuseSecond),
1161         XtRImmediate, (XtPointer) True },
1162     { "animateDragging", "animateDragging", XtRBoolean,
1163         sizeof(Boolean), XtOffset(AppDataPtr, animateDragging),
1164         XtRImmediate, (XtPointer) True },
1165     { "animateMoving", "animateMoving", XtRBoolean,
1166         sizeof(Boolean), XtOffset(AppDataPtr, animate),
1167         XtRImmediate, (XtPointer) True },
1168     { "animateSpeed", "animateSpeed", XtRInt,
1169         sizeof(int), XtOffset(AppDataPtr, animSpeed),
1170         XtRImmediate, (XtPointer)10 },
1171     { "popupExitMessage", "popupExitMessage", XtRBoolean,
1172         sizeof(Boolean), XtOffset(AppDataPtr, popupExitMessage),
1173         XtRImmediate, (XtPointer) True },
1174     { "popupMoveErrors", "popupMoveErrors", XtRBoolean,
1175         sizeof(Boolean), XtOffset(AppDataPtr, popupMoveErrors),
1176         XtRImmediate, (XtPointer) False },
1177     { "fontSizeTolerance", "fontSizeTolerance", XtRInt,
1178         sizeof(int), XtOffset(AppDataPtr, fontSizeTolerance),
1179         XtRImmediate, (XtPointer)4 },
1180     { "initialMode", "initialMode", XtRString,
1181         sizeof(String), XtOffset(AppDataPtr, initialMode),
1182         XtRImmediate, (XtPointer) "" },
1183     { "variant", "variant", XtRString,
1184         sizeof(String), XtOffset(AppDataPtr, variant),
1185         XtRImmediate, (XtPointer) "normal" },
1186     { "firstProtocolVersion", "firstProtocolVersion", XtRInt,
1187         sizeof(int), XtOffset(AppDataPtr, firstProtocolVersion),
1188         XtRImmediate, (XtPointer)PROTOVER },
1189     { "secondProtocolVersion", "secondProtocolVersion", XtRInt,
1190         sizeof(int), XtOffset(AppDataPtr, secondProtocolVersion),
1191         XtRImmediate, (XtPointer)PROTOVER },
1192     { "showButtonBar", "showButtonBar", XtRBoolean,
1193         sizeof(Boolean), XtOffset(AppDataPtr, showButtonBar),
1194         XtRImmediate, (XtPointer) True },
1195     {"icsEngineAnalyze", "icsEngineAnalyze", XtRBoolean,        /* [DM] icsEngineAnalyze */
1196         sizeof(Boolean), XtOffset(AppDataPtr, icsEngineAnalyze),
1197         XtRImmediate, (XtPointer) False },
1198     { "firstScoreAbs", "firstScoreAbs", XtRBoolean,
1199         sizeof(Boolean), XtOffset(AppDataPtr, firstScoreIsAbsolute),
1200         XtRImmediate, (XtPointer) False },
1201     { "secondScoreAbs", "secondScoreAbs", XtRBoolean,
1202         sizeof(Boolean), XtOffset(AppDataPtr, secondScoreIsAbsolute),
1203         XtRImmediate, (XtPointer) False },
1204     { "pgnExtendedInfo", "pgnExtendedInfo", XtRBoolean,
1205         sizeof(Boolean), XtOffset(AppDataPtr, saveExtendedInfoInPGN),
1206         XtRImmediate, (XtPointer) False },
1207     { "hideThinkingFromHuman", "hideThinkingFromHuman", XtRBoolean,
1208         sizeof(Boolean), XtOffset(AppDataPtr, hideThinkingFromHuman),
1209         XtRImmediate, (XtPointer) True },
1210     { "adjudicateLossThreshold", "adjudicateLossThreshold", XtRInt,
1211         sizeof(int), XtOffset(AppDataPtr, adjudicateLossThreshold),
1212         XtRImmediate, (XtPointer) 0},
1213     { "pgnEventHeader", "pgnEventHeader", XtRString,
1214         sizeof(String), XtOffset(AppDataPtr, pgnEventHeader),
1215         XtRImmediate, (XtPointer) "Computer Chess Game" },
1216     { "defaultFrcPosition", "defaultFrcPositon", XtRInt,
1217         sizeof(int), XtOffset(AppDataPtr, defaultFrcPosition),
1218         XtRImmediate, (XtPointer) -1},
1219     { "gameListTags", "gameListTags", XtRString,
1220         sizeof(String), XtOffset(AppDataPtr, gameListTags),
1221         XtRImmediate, (XtPointer) GLT_DEFAULT_TAGS },
1222
1223     // [HGM] 4.3.xx options
1224     { "boardWidth", "boardWidth", XtRInt,
1225         sizeof(int), XtOffset(AppDataPtr, NrFiles),
1226         XtRImmediate, (XtPointer) -1},
1227     { "boardHeight", "boardHeight", XtRInt,
1228         sizeof(int), XtOffset(AppDataPtr, NrRanks),
1229         XtRImmediate, (XtPointer) -1},
1230     { "matchPause", "matchPause", XtRInt,
1231         sizeof(int), XtOffset(AppDataPtr, matchPause),
1232         XtRImmediate, (XtPointer) 10000},
1233     { "holdingsSize", "holdingsSize", XtRInt,
1234         sizeof(int), XtOffset(AppDataPtr, holdingsSize),
1235         XtRImmediate, (XtPointer) -1},
1236     { "flipBlack", "flipBlack", XtRBoolean,
1237         sizeof(Boolean), XtOffset(AppDataPtr, upsideDown),
1238         XtRImmediate, (XtPointer) False},
1239     { "allWhite", "allWhite", XtRBoolean,
1240         sizeof(Boolean), XtOffset(AppDataPtr, allWhite),
1241         XtRImmediate, (XtPointer) False},
1242     { "pieceToCharTable", "pieceToCharTable", XtRString,
1243         sizeof(String), XtOffset(AppDataPtr, pieceToCharTable),
1244         XtRImmediate, (XtPointer) 0},
1245     { "alphaRank", "alphaRank", XtRBoolean,
1246         sizeof(Boolean), XtOffset(AppDataPtr, alphaRank),
1247         XtRImmediate, (XtPointer) False},
1248     { "testClaims", "testClaims", XtRBoolean,
1249         sizeof(Boolean), XtOffset(AppDataPtr, testClaims),
1250         XtRImmediate, (XtPointer) True},
1251     { "checkMates", "checkMates", XtRBoolean,
1252         sizeof(Boolean), XtOffset(AppDataPtr, checkMates),
1253         XtRImmediate, (XtPointer) True},
1254     { "materialDraws", "materialDraws", XtRBoolean,
1255         sizeof(Boolean), XtOffset(AppDataPtr, materialDraws),
1256         XtRImmediate, (XtPointer) True},
1257     { "trivialDraws", "trivialDraws", XtRBoolean,
1258         sizeof(Boolean), XtOffset(AppDataPtr, trivialDraws),
1259         XtRImmediate, (XtPointer) False},
1260     { "ruleMoves", "ruleMoves", XtRInt,
1261         sizeof(int), XtOffset(AppDataPtr, ruleMoves),
1262         XtRImmediate, (XtPointer) 51},
1263     { "repeatsToDraw", "repeatsToDraw", XtRInt,
1264         sizeof(int), XtOffset(AppDataPtr, drawRepeats),
1265         XtRImmediate, (XtPointer) 6},
1266     { "engineDebugOutput", "engineDebugOutput", XtRInt,
1267         sizeof(int), XtOffset(AppDataPtr, engineComments),
1268         XtRImmediate, (XtPointer) 1},
1269     { "userName", "userName", XtRString,
1270         sizeof(int), XtOffset(AppDataPtr, userName),
1271         XtRImmediate, (XtPointer) 0},
1272     { "autoKibitz", "autoKibitz", XtRBoolean,
1273         sizeof(Boolean), XtOffset(AppDataPtr, autoKibitz),
1274         XtRImmediate, (XtPointer) False},
1275     { "firstTimeOdds", "firstTimeOdds", XtRInt,
1276         sizeof(int), XtOffset(AppDataPtr, firstTimeOdds),
1277         XtRImmediate, (XtPointer) 1},
1278     { "secondTimeOdds", "secondTimeOdds", XtRInt,
1279         sizeof(int), XtOffset(AppDataPtr, secondTimeOdds),
1280         XtRImmediate, (XtPointer) 1},
1281     { "timeOddsMode", "timeOddsMode", XtRInt,
1282         sizeof(int), XtOffset(AppDataPtr, timeOddsMode),
1283         XtRImmediate, (XtPointer) 0},
1284     { "firstAccumulateTC", "firstAccumulateTC", XtRInt,
1285         sizeof(int), XtOffset(AppDataPtr, firstAccumulateTC),
1286         XtRImmediate, (XtPointer) 1},
1287     { "secondAccumulateTC", "secondAccumulateTC", XtRInt,
1288         sizeof(int), XtOffset(AppDataPtr, secondAccumulateTC),
1289         XtRImmediate, (XtPointer) 1},
1290     { "firstNPS", "firstNPS", XtRInt,
1291         sizeof(int), XtOffset(AppDataPtr, firstNPS),
1292         XtRImmediate, (XtPointer) -1},
1293     { "secondNPS", "secondNPS", XtRInt,
1294         sizeof(int), XtOffset(AppDataPtr, secondNPS),
1295         XtRImmediate, (XtPointer) -1},
1296     { "serverMoves", "serverMoves", XtRString,
1297         sizeof(String), XtOffset(AppDataPtr, serverMovesName),
1298         XtRImmediate, (XtPointer) 0},
1299     { "serverPause", "serverPause", XtRInt,
1300         sizeof(int), XtOffset(AppDataPtr, serverPause),
1301         XtRImmediate, (XtPointer) 0},
1302     { "suppressLoadMoves", "suppressLoadMoves", XtRBoolean,
1303         sizeof(Boolean), XtOffset(AppDataPtr, suppressLoadMoves),
1304         XtRImmediate, (XtPointer) False},
1305     { "userName", "userName", XtRString,
1306         sizeof(String), XtOffset(AppDataPtr, userName),
1307         XtRImmediate, (XtPointer) 0},
1308     { "egtFormats", "egtFormats", XtRString,
1309         sizeof(String), XtOffset(AppDataPtr, egtFormats),
1310         XtRImmediate, (XtPointer) 0},
1311     { "rewindIndex", "rewindIndex", XtRInt,
1312         sizeof(int), XtOffset(AppDataPtr, rewindIndex),
1313         XtRImmediate, (XtPointer) 0},
1314     { "sameColorGames", "sameColorGames", XtRInt,
1315         sizeof(int), XtOffset(AppDataPtr, sameColorGames),
1316         XtRImmediate, (XtPointer) 0},
1317     { "smpCores", "smpCores", XtRInt,
1318         sizeof(int), XtOffset(AppDataPtr, smpCores),
1319         XtRImmediate, (XtPointer) 1},
1320     { "niceEngines", "niceEngines", XtRInt,
1321         sizeof(int), XtOffset(AppDataPtr, niceEngines),
1322         XtRImmediate, (XtPointer) 0},
1323     { "nameOfDebugFile", "nameOfDebugFile", XtRString,
1324         sizeof(String), XtOffset(AppDataPtr, nameOfDebugFile),
1325         XtRImmediate, (XtPointer) "xboard.debug"},
1326     { "engineDebugOutput", "engineDebugOutput", XtRInt,
1327         sizeof(int), XtOffset(AppDataPtr, engineComments),
1328         XtRImmediate, (XtPointer) 0},
1329     { "noGUI", "noGUI", XtRBoolean,
1330         sizeof(Boolean), XtOffset(AppDataPtr, noGUI),
1331         XtRImmediate, (XtPointer) 0},
1332     { "firstOptions", "firstOptions", XtRString,
1333         sizeof(String), XtOffset(AppDataPtr, firstOptions),
1334         XtRImmediate, (XtPointer) "" },
1335     { "secondOptions", "secondOptions", XtRString,
1336         sizeof(String), XtOffset(AppDataPtr, secondOptions),
1337         XtRImmediate, (XtPointer) "" },
1338
1339     // [HGM] Winboard_x UCI options
1340     { "firstIsUCI", "firstIsUCI", XtRBoolean,
1341         sizeof(Boolean), XtOffset(AppDataPtr, firstIsUCI),
1342         XtRImmediate, (XtPointer) False},
1343     { "secondIsUCI", "secondIsUCI", XtRBoolean,
1344         sizeof(Boolean), XtOffset(AppDataPtr, secondIsUCI),
1345         XtRImmediate, (XtPointer) False},
1346     { "firstHasOwnBookUCI", "firstHasOwnBookUCI", XtRBoolean,
1347         sizeof(Boolean), XtOffset(AppDataPtr, firstHasOwnBookUCI),
1348         XtRImmediate, (XtPointer) True},
1349     { "secondHasOwnBookUCI", "secondHasOwnBookUCI", XtRBoolean,
1350         sizeof(Boolean), XtOffset(AppDataPtr, secondHasOwnBookUCI),
1351         XtRImmediate, (XtPointer) True},
1352     { "usePolyglotBook", "usePolyglotBook", XtRBoolean,
1353         sizeof(Boolean), XtOffset(AppDataPtr, usePolyglotBook),
1354         XtRImmediate, (XtPointer) False},
1355     { "defaultHashSize", "defaultHashSize", XtRInt,
1356         sizeof(int), XtOffset(AppDataPtr, defaultHashSize),
1357         XtRImmediate, (XtPointer) 64},
1358     { "defaultCacheSizeEGTB", "defaultCacheSizeEGTB", XtRInt,
1359         sizeof(int), XtOffset(AppDataPtr, defaultCacheSizeEGTB),
1360         XtRImmediate, (XtPointer) 4},
1361     { "polyglotDir", "polyglotDir", XtRString,
1362         sizeof(String), XtOffset(AppDataPtr, polyglotDir),
1363         XtRImmediate, (XtPointer) "." },
1364     { "polyglotBook", "polyglotBook", XtRString,
1365         sizeof(String), XtOffset(AppDataPtr, polyglotBook),
1366         XtRImmediate, (XtPointer) "" },
1367     { "defaultPathEGTB", "defaultPathEGTB", XtRString,
1368         sizeof(String), XtOffset(AppDataPtr, defaultPathEGTB),
1369         XtRImmediate, (XtPointer) "/usr/local/share/egtb"},
1370     { "delayBeforeQuit", "delayBeforeQuit", XtRInt,
1371         sizeof(int), XtOffset(AppDataPtr, delayBeforeQuit),
1372         XtRImmediate, (XtPointer) 0},
1373     { "delayAfterQuit", "delayAfterQuit", XtRInt,
1374         sizeof(int), XtOffset(AppDataPtr, delayAfterQuit),
1375         XtRImmediate, (XtPointer) 0},
1376 };
1377
1378 XrmOptionDescRec shellOptions[] = {
1379     { "-whitePieceColor", "whitePieceColor", XrmoptionSepArg, NULL },
1380     { "-blackPieceColor", "blackPieceColor", XrmoptionSepArg, NULL },
1381     { "-lightSquareColor", "lightSquareColor", XrmoptionSepArg, NULL },
1382     { "-darkSquareColor", "darkSquareColor", XrmoptionSepArg, NULL },
1383     { "-highlightSquareColor", "highlightSquareColor", XrmoptionSepArg, NULL },
1384     { "-premoveHighlightColor", "premoveHighlightColor", XrmoptionSepArg,NULL},
1385     { "-movesPerSession", "movesPerSession", XrmoptionSepArg, NULL },
1386     { "-mps", "movesPerSession", XrmoptionSepArg, NULL },
1387     { "-timeIncrement", "timeIncrement", XrmoptionSepArg, NULL },
1388     { "-inc", "timeIncrement", XrmoptionSepArg, NULL },
1389     { "-initString", "initString", XrmoptionSepArg, NULL },
1390     { "-firstInitString", "initString", XrmoptionSepArg, NULL },
1391     { "-secondInitString", "secondInitString", XrmoptionSepArg, NULL },
1392     { "-firstComputerString", "firstComputerString", XrmoptionSepArg, NULL },
1393     { "-secondComputerString", "secondComputerString", XrmoptionSepArg, NULL },
1394     { "-firstChessProgram", "firstChessProgram", XrmoptionSepArg, NULL },
1395     { "-fcp", "firstChessProgram", XrmoptionSepArg, NULL },
1396     { "-secondChessProgram", "secondChessProgram", XrmoptionSepArg, NULL },
1397     { "-scp", "secondChessProgram", XrmoptionSepArg, NULL },
1398     { "-firstPlaysBlack", "firstPlaysBlack", XrmoptionSepArg, NULL },
1399     { "-fb", "firstPlaysBlack", XrmoptionNoArg, "True" },
1400     { "-xfb", "firstPlaysBlack", XrmoptionNoArg, "False" },
1401     { "-noChessProgram", "noChessProgram", XrmoptionSepArg, NULL },
1402     { "-ncp", "noChessProgram", XrmoptionNoArg, "True" },
1403     { "-xncp", "noChessProgram", XrmoptionNoArg, "False" },
1404     { "-firstHost", "firstHost", XrmoptionSepArg, NULL },
1405     { "-fh", "firstHost", XrmoptionSepArg, NULL },
1406     { "-secondHost", "secondHost", XrmoptionSepArg, NULL },
1407     { "-sh", "secondHost", XrmoptionSepArg, NULL },
1408     { "-firstDirectory", "firstDirectory", XrmoptionSepArg, NULL },
1409     { "-fd", "firstDirectory", XrmoptionSepArg, NULL },
1410     { "-secondDirectory", "secondDirectory", XrmoptionSepArg, NULL },
1411     { "-sd", "secondDirectory", XrmoptionSepArg, NULL },
1412     { "-bitmapDirectory", "bitmapDirectory", XrmoptionSepArg, NULL },
1413     { "-bm", "bitmapDirectory", XrmoptionSepArg, NULL },
1414     { "-remoteShell", "remoteShell", XrmoptionSepArg, NULL },
1415     { "-rsh", "remoteShell", XrmoptionSepArg, NULL },
1416     { "-remoteUser", "remoteUser", XrmoptionSepArg, NULL },
1417     { "-ruser", "remoteUser", XrmoptionSepArg, NULL },
1418     { "-timeDelay", "timeDelay", XrmoptionSepArg, NULL },
1419     { "-td", "timeDelay", XrmoptionSepArg, NULL },
1420     { "-timeControl", "timeControl", XrmoptionSepArg, NULL },
1421     { "-tc", "timeControl", XrmoptionSepArg, NULL },
1422     { "-internetChessServerMode", "internetChessServerMode",
1423         XrmoptionSepArg, NULL },
1424     { "-ics", "internetChessServerMode", XrmoptionNoArg, "True" },
1425     { "-xics", "internetChessServerMode", XrmoptionNoArg, "False" },
1426     { "-internetChessServerHost", "internetChessServerHost",
1427         XrmoptionSepArg, NULL },
1428     { "-icshost", "internetChessServerHost", XrmoptionSepArg, NULL },
1429     { "-internetChessServerPort", "internetChessServerPort",
1430         XrmoptionSepArg, NULL },
1431     { "-icsport", "internetChessServerPort", XrmoptionSepArg, NULL },
1432     { "-internetChessServerCommPort", "internetChessServerCommPort",
1433         XrmoptionSepArg, NULL },
1434     { "-icscomm", "internetChessServerCommPort", XrmoptionSepArg, NULL },
1435     { "-internetChessServerLogonScript", "internetChessServerLogonScript",
1436         XrmoptionSepArg, NULL },
1437     { "-icslogon", "internetChessServerLogonScript", XrmoptionSepArg, NULL },
1438     { "-internetChessServerHelper", "internetChessServerHelper",
1439         XrmoptionSepArg, NULL },
1440     { "-icshelper", "internetChessServerHelper", XrmoptionSepArg, NULL },
1441     { "-internetChessServerInputBox", "internetChessServerInputBox",
1442         XrmoptionSepArg, NULL },
1443     { "-icsinput", "internetChessServerInputBox", XrmoptionNoArg, "True" },
1444     { "-xicsinput", "internetChessServerInputBox", XrmoptionNoArg, "False" },
1445     { "-icsAlarm", "icsAlarm", XrmoptionSepArg, NULL },
1446     { "-alarm", "icsAlarm", XrmoptionNoArg, "True" },
1447     { "-xalarm", "icsAlarm", XrmoptionNoArg, "False" },
1448     { "-icsAlarmTime", "icsAlarmTime", XrmoptionSepArg, NULL },
1449     { "-useTelnet", "useTelnet", XrmoptionSepArg, NULL },
1450     { "-telnet", "useTelnet", XrmoptionNoArg, "True" },
1451     { "-xtelnet", "useTelnet", XrmoptionNoArg, "False" },
1452     { "-telnetProgram", "telnetProgram", XrmoptionSepArg, NULL },
1453     { "-gateway", "gateway", XrmoptionSepArg, NULL },
1454     { "-loadGameFile", "loadGameFile", XrmoptionSepArg, NULL },
1455     { "-lgf", "loadGameFile", XrmoptionSepArg, NULL },
1456     { "-loadGameIndex", "loadGameIndex", XrmoptionSepArg, NULL },
1457     { "-lgi", "loadGameIndex", XrmoptionSepArg, NULL },
1458     { "-saveGameFile", "saveGameFile", XrmoptionSepArg, NULL },
1459     { "-sgf", "saveGameFile", XrmoptionSepArg, NULL },
1460     { "-autoSaveGames", "autoSaveGames", XrmoptionSepArg, NULL },
1461     { "-autosave", "autoSaveGames", XrmoptionNoArg, "True" },
1462     { "-xautosave", "autoSaveGames", XrmoptionNoArg, "False" },
1463     { "-autoRaiseBoard", "autoRaiseBoard", XrmoptionSepArg, NULL },
1464     { "-autoraise", "autoRaiseBoard", XrmoptionNoArg, "True" },
1465     { "-xautoraise", "autoRaiseBoard", XrmoptionNoArg, "False" },
1466     { "-blindfold", "blindfold", XrmoptionSepArg, NULL },
1467     { "-blind", "blindfold", XrmoptionNoArg, "True" },
1468     { "-xblind", "blindfold", XrmoptionNoArg, "False" },
1469     { "-loadPositionFile", "loadPositionFile", XrmoptionSepArg, NULL },
1470     { "-lpf", "loadPositionFile", XrmoptionSepArg, NULL },
1471     { "-loadPositionIndex", "loadPositionIndex", XrmoptionSepArg, NULL },
1472     { "-lpi", "loadPositionIndex", XrmoptionSepArg, NULL },
1473     { "-savePositionFile", "savePositionFile", XrmoptionSepArg, NULL },
1474     { "-spf", "savePositionFile", XrmoptionSepArg, NULL },
1475     { "-matchMode", "matchMode", XrmoptionSepArg, NULL },
1476     { "-mm", "matchMode", XrmoptionNoArg, "True" },
1477     { "-xmm", "matchMode", XrmoptionNoArg, "False" },
1478     { "-matchGames", "matchGames", XrmoptionSepArg, NULL },
1479     { "-mg", "matchGames", XrmoptionSepArg, NULL },
1480     { "-monoMode", "monoMode", XrmoptionSepArg, NULL },
1481     { "-mono", "monoMode", XrmoptionNoArg, "True" },
1482     { "-xmono", "monoMode", XrmoptionNoArg, "False" },
1483     { "-debugMode", "debugMode", XrmoptionSepArg, NULL },
1484     { "-debug", "debugMode", XrmoptionNoArg, "True" },
1485     { "-xdebug", "debugMode", XrmoptionNoArg, "False" },
1486     { "-clockMode", "clockMode", XrmoptionSepArg, NULL },
1487     { "-clock", "clockMode", XrmoptionNoArg, "True" },
1488     { "-xclock", "clockMode", XrmoptionNoArg, "False" },
1489     { "-boardSize", "boardSize", XrmoptionSepArg, NULL },
1490     { "-size", "boardSize", XrmoptionSepArg, NULL },
1491     { "-searchTime", "searchTime", XrmoptionSepArg, NULL },
1492     { "-st", "searchTime", XrmoptionSepArg, NULL },
1493     { "-searchDepth", "searchDepth", XrmoptionSepArg, NULL },
1494     { "-depth", "searchDepth", XrmoptionSepArg, NULL },
1495     { "-showCoords", "showCoords", XrmoptionSepArg, NULL },
1496     { "-coords", "showCoords", XrmoptionNoArg, "True" },
1497     { "-xcoords", "showCoords", XrmoptionNoArg, "False" },
1498 #if JAIL
1499     { "-showJail", "showJail", XrmoptionSepArg, NULL },
1500     { "-jail", "showJail", XrmoptionNoArg, "1" },
1501     { "-sidejail", "showJail", XrmoptionNoArg, "2" },
1502     { "-xjail", "showJail", XrmoptionNoArg, "0" },
1503 #endif
1504     { "-showThinking", "showThinking", XrmoptionSepArg, NULL },
1505     { "-thinking", "showThinking", XrmoptionNoArg, "True" },
1506     { "-xthinking", "showThinking", XrmoptionNoArg, "False" },
1507     { "-ponderNextMove", "ponderNextMove", XrmoptionSepArg, NULL },
1508     { "-ponder", "ponderNextMove", XrmoptionNoArg, "True" },
1509     { "-xponder", "ponderNextMove", XrmoptionNoArg, "False" },
1510     { "-periodicUpdates", "periodicUpdates", XrmoptionSepArg, NULL },
1511     { "-periodic", "periodicUpdates", XrmoptionNoArg, "True" },
1512     { "-xperiodic", "periodicUpdates", XrmoptionNoArg, "False" },
1513     { "-clockFont", "clockFont", XrmoptionSepArg, NULL },
1514     { "-coordFont", "coordFont", XrmoptionSepArg, NULL },
1515     { "-font", "font", XrmoptionSepArg, NULL },
1516     { "-ringBellAfterMoves", "ringBellAfterMoves", XrmoptionSepArg, NULL },
1517     { "-bell", "ringBellAfterMoves", XrmoptionNoArg, "True" },
1518     { "-xbell", "ringBellAfterMoves", XrmoptionNoArg, "False" },
1519     { "-movesound", "ringBellAfterMoves", XrmoptionNoArg, "True" },
1520     { "-xmovesound", "ringBellAfterMoves", XrmoptionNoArg, "False" },
1521     { "-autoCallFlag", "autoCallFlag", XrmoptionSepArg, NULL },
1522     { "-autoflag", "autoCallFlag", XrmoptionNoArg, "True" },
1523     { "-xautoflag", "autoCallFlag", XrmoptionNoArg, "False" },
1524     { "-autoFlipView", "autoFlipView", XrmoptionSepArg, NULL },
1525     { "-autoflip", "autoFlipView", XrmoptionNoArg, "True" },
1526     { "-xautoflip", "autoFlipView", XrmoptionNoArg, "False" },
1527     { "-autoObserve", "autoObserve", XrmoptionSepArg, NULL },
1528     { "-autobs", "autoObserve", XrmoptionNoArg, "True" },
1529     { "-xautobs", "autoObserve", XrmoptionNoArg, "False" },
1530     { "-autoComment", "autoComment", XrmoptionSepArg, NULL },
1531     { "-autocomm", "autoComment", XrmoptionNoArg, "True" },
1532     { "-xautocomm", "autoComment", XrmoptionNoArg, "False" },
1533     { "-getMoveList", "getMoveList", XrmoptionSepArg, NULL },
1534     { "-moves", "getMoveList", XrmoptionNoArg, "True" },
1535     { "-xmoves", "getMoveList", XrmoptionNoArg, "False" },
1536 #if HIGHDRAG
1537     { "-highlightDragging", "highlightDragging", XrmoptionSepArg, NULL },
1538     { "-highdrag", "highlightDragging", XrmoptionNoArg, "True" },
1539     { "-xhighdrag", "highlightDragging", XrmoptionNoArg, "False" },
1540 #endif
1541     { "-highlightLastMove", "highlightLastMove", XrmoptionSepArg, NULL },
1542     { "-highlight", "highlightLastMove", XrmoptionNoArg, "True" },
1543     { "-xhighlight", "highlightLastMove", XrmoptionNoArg, "False" },
1544     { "-premove", "premove", XrmoptionSepArg, NULL },
1545     { "-pre", "premove", XrmoptionNoArg, "True" },
1546     { "-xpre", "premove", XrmoptionNoArg, "False" },
1547     { "-testLegality", "testLegality", XrmoptionSepArg, NULL },
1548     { "-legal", "testLegality", XrmoptionNoArg, "True" },
1549     { "-xlegal", "testLegality", XrmoptionNoArg, "False" },
1550     { "-flipView", "flipView", XrmoptionSepArg, NULL },
1551     { "-flip", "flipView", XrmoptionNoArg, "True" },
1552     { "-xflip", "flipView", XrmoptionNoArg, "False" },
1553     { "-cmail", "cmailGameName", XrmoptionSepArg, NULL },
1554     { "-alwaysPromoteToQueen", "alwaysPromoteToQueen",
1555         XrmoptionSepArg, NULL },
1556     { "-queen", "alwaysPromoteToQueen", XrmoptionNoArg, "True" },
1557     { "-xqueen", "alwaysPromoteToQueen", XrmoptionNoArg, "False" },
1558     { "-oldSaveStyle", "oldSaveStyle", XrmoptionSepArg, NULL },
1559     { "-oldsave", "oldSaveStyle", XrmoptionNoArg, "True" },
1560     { "-xoldsave", "oldSaveStyle", XrmoptionNoArg, "False" },
1561     { "-quietPlay", "quietPlay", XrmoptionSepArg, NULL },
1562     { "-quiet", "quietPlay", XrmoptionNoArg, "True" },
1563     { "-xquiet", "quietPlay", XrmoptionNoArg, "False" },
1564     { "-titleInWindow", "titleInWindow", XrmoptionSepArg, NULL },
1565     { "-title", "titleInWindow", XrmoptionNoArg, "True" },
1566     { "-xtitle", "titleInWindow", XrmoptionNoArg, "False" },
1567 #ifdef ZIPPY
1568     { "-zippyTalk", "zippyTalk", XrmoptionSepArg, NULL },
1569     { "-zt", "zippyTalk", XrmoptionNoArg, "True" },
1570     { "-xzt", "zippyTalk", XrmoptionNoArg, "False" },
1571     { "-zippyPlay", "zippyPlay", XrmoptionSepArg, NULL },
1572     { "-zp", "zippyPlay", XrmoptionNoArg, "True" },
1573     { "-xzp", "zippyPlay", XrmoptionNoArg, "False" },
1574     { "-zippyLines", "zippyLines", XrmoptionSepArg, NULL },
1575     { "-zippyPinhead", "zippyPinhead", XrmoptionSepArg, NULL },
1576     { "-zippyPassword", "zippyPassword", XrmoptionSepArg, NULL },
1577     { "-zippyPassword2", "zippyPassword2", XrmoptionSepArg, NULL },
1578     { "-zippyWrongPassword", "zippyWrongPassword", XrmoptionSepArg, NULL },
1579     { "-zippyAcceptOnly", "zippyAcceptOnly", XrmoptionSepArg, NULL },
1580     { "-zippyUseI", "zippyUseI", XrmoptionSepArg, NULL },
1581     { "-zui", "zippyUseI", XrmoptionNoArg, "True" },
1582     { "-xzui", "zippyUseI", XrmoptionNoArg, "False" },
1583     { "-zippyBughouse", "zippyBughouse", XrmoptionSepArg, NULL },
1584     { "-zippyNoplayCrafty", "zippyNoplayCrafty", XrmoptionSepArg, NULL },
1585     { "-znc", "zippyNoplayCrafty", XrmoptionNoArg, "True" },
1586     { "-xznc", "zippyNoplayCrafty", XrmoptionNoArg, "False" },
1587     { "-zippyGameEnd", "zippyGameEnd", XrmoptionSepArg, NULL },
1588     { "-zippyGameStart", "zippyGameStart", XrmoptionSepArg, NULL },
1589     { "-zippyAdjourn", "zippyAdjourn", XrmoptionSepArg, NULL },
1590     { "-zadj", "zippyAdjourn", XrmoptionNoArg, "True" },
1591     { "-xzadj", "zippyAdjourn", XrmoptionNoArg, "False" },
1592     { "-zippyAbort", "zippyAbort", XrmoptionSepArg, NULL },
1593     { "-zab", "zippyAbort", XrmoptionNoArg, "True" },
1594     { "-xzab", "zippyAbort", XrmoptionNoArg, "False" },
1595     { "-zippyVariants", "zippyVariants", XrmoptionSepArg, NULL },
1596     { "-zippyMaxGames", "zippyMaxGames", XrmoptionSepArg, NULL },
1597     { "-zippyReplayTimeout", "zippyReplayTimeout", XrmoptionSepArg, NULL },
1598 #endif
1599     { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
1600     { "-flash", "flashCount", XrmoptionNoArg, "3" },
1601     { "-xflash", "flashCount", XrmoptionNoArg, "0" },
1602     { "-flashRate", "flashRate", XrmoptionSepArg, NULL },
1603     { "-pixmapDirectory", "pixmapDirectory", XrmoptionSepArg, NULL },
1604     { "-msLoginDelay", "msLoginDelay", XrmoptionSepArg, NULL },
1605     { "-pixmap", "pixmapDirectory", XrmoptionSepArg, NULL },
1606     { "-colorizeMessages", "colorizeMessages", XrmoptionSepArg, NULL },
1607     { "-colorize", "colorizeMessages", XrmoptionNoArg, "True" },
1608     { "-xcolorize", "colorizeMessages", XrmoptionNoArg, "False" },
1609     { "-colorShout", "colorShout", XrmoptionSepArg, NULL },
1610     { "-colorSShout", "colorSShout", XrmoptionSepArg, NULL },
1611     { "-colorCShout", "colorSShout", XrmoptionSepArg, NULL }, /*FICS name*/
1612     { "-colorChannel1", "colorChannel1", XrmoptionSepArg, NULL },
1613     { "-colorChannel", "colorChannel", XrmoptionSepArg, NULL },
1614     { "-colorKibitz", "colorKibitz", XrmoptionSepArg, NULL },
1615     { "-colorTell", "colorTell", XrmoptionSepArg, NULL },
1616     { "-colorChallenge", "colorChallenge", XrmoptionSepArg, NULL },
1617     { "-colorRequest", "colorRequest", XrmoptionSepArg, NULL },
1618     { "-colorSeek", "colorSeek", XrmoptionSepArg, NULL },
1619     { "-colorNormal", "colorNormal", XrmoptionSepArg, NULL },
1620     { "-soundProgram", "soundProgram", XrmoptionSepArg, NULL },
1621     { "-soundShout", "soundShout", XrmoptionSepArg, NULL },
1622     { "-soundSShout", "soundSShout", XrmoptionSepArg, NULL },
1623     { "-soundCShout", "soundSShout", XrmoptionSepArg, NULL }, /*FICS name*/
1624     { "-soundChannel1", "soundChannel1", XrmoptionSepArg, NULL },
1625     { "-soundChannel", "soundChannel", XrmoptionSepArg, NULL },
1626     { "-soundKibitz", "soundKibitz", XrmoptionSepArg, NULL },
1627     { "-soundTell", "soundTell", XrmoptionSepArg, NULL },
1628     { "-soundChallenge", "soundChallenge", XrmoptionSepArg, NULL },
1629     { "-soundRequest", "soundRequest", XrmoptionSepArg, NULL },
1630     { "-soundSeek", "soundSeek", XrmoptionSepArg, NULL },
1631     { "-soundMove", "soundMove", XrmoptionSepArg, NULL },
1632     { "-soundIcsWin", "soundIcsWin", XrmoptionSepArg, NULL },
1633     { "-soundIcsLoss", "soundIcsLoss", XrmoptionSepArg, NULL },
1634     { "-soundIcsDraw", "soundIcsDraw", XrmoptionSepArg, NULL },
1635     { "-soundIcsUnfinished", "soundIcsUnfinished", XrmoptionSepArg, NULL },
1636     { "-soundIcsAlarm", "soundIcsAlarm", XrmoptionSepArg, NULL },
1637     { "-reuseFirst", "reuseFirst", XrmoptionSepArg, NULL },
1638     { "-reuseChessPrograms", "reuseFirst", XrmoptionSepArg, NULL }, /*compat*/
1639     { "-reuse", "reuseFirst", XrmoptionNoArg, "True" },
1640     { "-xreuse", "reuseFirst", XrmoptionNoArg, "False" },
1641     { "-reuseSecond", "reuseSecond", XrmoptionSepArg, NULL },
1642     { "-reuse2", "reuseSecond", XrmoptionNoArg, "True" },
1643     { "-xreuse2", "reuseSecond", XrmoptionNoArg, "False" },
1644     { "-animateMoving", "animateMoving", XrmoptionSepArg, NULL },
1645     { "-animate", "animateMoving", XrmoptionNoArg, "True" },
1646     { "-xanimate", "animateMoving", XrmoptionNoArg, "False" },
1647     { "-animateDragging", "animateDragging", XrmoptionSepArg, NULL },
1648     { "-drag", "animateDragging", XrmoptionNoArg, "True" },
1649     { "-xdrag", "animateDragging", XrmoptionNoArg, "False" },
1650     { "-animateSpeed", "animateSpeed", XrmoptionSepArg, NULL },
1651     { "-popupExitMessage", "popupExitMessage", XrmoptionSepArg, NULL },
1652     { "-exit", "popupExitMessage", XrmoptionNoArg, "True" },
1653     { "-xexit", "popupExitMessage", XrmoptionNoArg, "False" },
1654     { "-popupMoveErrors", "popupMoveErrors", XrmoptionSepArg, NULL },
1655     { "-popup", "popupMoveErrors", XrmoptionNoArg, "True" },
1656     { "-xpopup", "popupMoveErrors", XrmoptionNoArg, "False" },
1657     { "-fontSizeTolerance", "fontSizeTolerance", XrmoptionSepArg, NULL },
1658     { "-initialMode", "initialMode", XrmoptionSepArg, NULL },
1659     { "-mode", "initialMode", XrmoptionSepArg, NULL },
1660     { "-variant", "variant", XrmoptionSepArg, NULL },
1661     { "-firstProtocolVersion", "firstProtocolVersion", XrmoptionSepArg, NULL },
1662     { "-secondProtocolVersion","secondProtocolVersion",XrmoptionSepArg, NULL },
1663     { "-showButtonBar", "showButtonBar", XrmoptionSepArg, NULL },
1664     { "-buttons", "showButtonBar", XrmoptionNoArg, "True" },
1665     { "-xbuttons", "showButtonBar", XrmoptionNoArg, "False" },
1666     /* [AS,HR] New features */
1667     { "-firstScoreAbs", "firstScoreAbs", XrmoptionSepArg, NULL },
1668     { "-secondScoreAbs", "secondScoreAbs", XrmoptionSepArg, NULL },
1669     { "-pgnExtendedInfo", "pgnExtendedInfo", XrmoptionSepArg, NULL },
1670     { "-hideThinkingFromHuman", "hideThinkingFromHuman", XrmoptionSepArg, NULL },
1671     { "-adjudicateLossThreshold", "adjudicateLossThreshold", XrmoptionSepArg, NULL },
1672     { "-pgnEventHeader", "pgnEventHeader", XrmoptionSepArg, NULL },
1673     { "-firstIsUCI", "firstIsUCI", XrmoptionSepArg, NULL },
1674     { "-secondIsUCI", "secondIsUCI", XrmoptionSepArg, NULL },
1675     { "-fUCI", "firstIsUCI", XrmoptionNoArg, "True" },
1676     { "-sUCI", "secondIsUCI", XrmoptionNoArg, "True" },
1677     { "-firstHasOwnBookUCI", "firstHasOwnBookUCI", XrmoptionSepArg, NULL },
1678     { "-secondHasOwnBookUCI", "secondHasOwnBookUCI", XrmoptionSepArg, NULL },
1679     { "-fNoOwnBookUCI", "firstHasOwnBookUCI", XrmoptionNoArg, "False" },
1680     { "-sNoOwnBookUCI", "secondHasOwnBookUCI", XrmoptionNoArg, "False" },
1681     { "-firstXBook", "firstHasOwnBookUCI", XrmoptionNoArg, "False" },
1682     { "-secondXBook", "secondHasOwnBookUCI", XrmoptionNoArg, "False" },
1683     { "-polyglotDir", "polyglotDir", XrmoptionSepArg, NULL },
1684     { "-usePolyglotBook", "usePolyglotBook", XrmoptionSepArg, NULL },
1685     { "-polyglotBook", "polyglotBook", XrmoptionSepArg, NULL },
1686     { "-defaultHashSize", "defaultHashSize", XrmoptionSepArg, NULL },
1687     { "-defaultCacheSizeEGTB", "defaultCacheSizeEGTB", XrmoptionSepArg, NULL },
1688     { "-defaultPathEGTB", "defaultPathEGTB", XrmoptionSepArg, NULL },
1689     { "-defaultFrcPosition", "defaultFrcPosition", XrmoptionSepArg, NULL },
1690     { "-gameListTags", "gameListTags", XrmoptionSepArg, NULL },
1691     // [HGM] I am sure AS added many more options, but we have to fish them out, from the list in winboard.c
1692
1693     /* [HGM,HR] User-selectable board size */
1694     { "-boardWidth", "boardWidth", XrmoptionSepArg, NULL },
1695     { "-boardHeight", "boardHeight", XrmoptionSepArg, NULL },
1696     { "-matchPause", "matchPause", XrmoptionSepArg, NULL },
1697
1698     /* [HGM] new arguments of 4.3.xx. All except first three are back-end options, which should work immediately */
1699     { "-holdingsSize", "holdingsSize", XrmoptionSepArg, NULL }, // requires extensive front-end changes to work
1700     { "-flipBlack", "flipBlack", XrmoptionSepArg, NULL },       // requires front-end changes to work
1701     { "-allWhite", "allWhite", XrmoptionSepArg, NULL },         // requires front-end changes to work
1702     { "-pieceToCharTable", "pieceToCharTable", XrmoptionSepArg, NULL },
1703     { "-alphaRank", "alphaRank", XrmoptionSepArg, NULL },
1704     { "-testClaims", "testClaims", XrmoptionSepArg, NULL },
1705     { "-checkMates", "checkMates", XrmoptionSepArg, NULL },
1706     { "-materialDraws", "materialDraws", XrmoptionSepArg, NULL },
1707     { "-trivialDraws", "trivialDraws", XrmoptionSepArg, NULL },
1708     { "-ruleMoves", "ruleMoves", XrmoptionSepArg, NULL },
1709     { "-repeatsToDraw", "repeatsToDraw", XrmoptionSepArg, NULL },
1710     { "-engineDebugOutput", "engineDebugOutput", XrmoptionSepArg, NULL },
1711     { "-userName", "userName", XrmoptionSepArg, NULL },
1712     { "-autoKibitz", "autoKibitz", XrmoptionNoArg, "True" },
1713     { "-firstTimeOdds", "firstTimeOdds", XrmoptionSepArg, NULL },
1714     { "-secondTimeOdds", "secondTimeOdds", XrmoptionSepArg, NULL },
1715     { "-timeOddsMode", "timeOddsMode", XrmoptionSepArg, NULL },
1716     { "-firstAccumulateTC", "firstAccumulateTC", XrmoptionSepArg, NULL },
1717     { "-secondAccumulateTC", "secondAccumulateTC", XrmoptionSepArg, NULL },
1718     { "-firstNPS", "firstNPS", XrmoptionSepArg, NULL },
1719     { "-secondNPS", "secondNPS", XrmoptionSepArg, NULL },
1720     { "-serverMoves", "serverMoves", XrmoptionSepArg, NULL },
1721     { "-serverPause", "serverPause", XrmoptionSepArg, NULL },
1722     { "-suppressLoadMoves", "suppressLoadMoves", XrmoptionSepArg, NULL },
1723     { "-egtFormats", "egtFormats", XrmoptionSepArg, NULL },
1724     { "-userName", "userName", XrmoptionSepArg, NULL },
1725     { "-smpCores", "smpCores", XrmoptionSepArg, NULL },
1726     { "-sameColorGames", "sameColorGames", XrmoptionSepArg, NULL },
1727     { "-rewindIndex", "rewindIndex", XrmoptionSepArg, NULL },
1728     { "-niceEngines", "niceEngines", XrmoptionSepArg, NULL },
1729     { "-delayBeforeQuit", "delayBeforeQuit", XrmoptionSepArg, NULL },
1730     { "-delayAfterQuit", "delayAfterQuit", XrmoptionSepArg, NULL },
1731     { "-nameOfDebugFile", "nameOfDebugFile", XrmoptionSepArg, NULL },
1732     { "-debugFile", "nameOfDebugFile", XrmoptionSepArg, NULL },
1733     { "-engineDebugOutput", "engineDebugOutput", XrmoptionSepArg, NULL },
1734     { "-noGUI", "noGUI", XrmoptionNoArg, "True" },
1735     { "-firstOptions", "firstOptions", XrmoptionSepArg, NULL },
1736     { "-secondOptions", "secondOptions", XrmoptionSepArg, NULL },
1737 };
1738
1739
1740 XtActionsRec boardActions[] = {
1741     { "DrawPosition", DrawPositionProc },
1742     { "HandleUserMove", HandleUserMove },
1743     { "AnimateUserMove", AnimateUserMove },
1744     { "FileNameAction", FileNameAction },
1745     { "AskQuestionProc", AskQuestionProc },
1746     { "AskQuestionReplyAction", AskQuestionReplyAction },
1747     { "PieceMenuPopup", PieceMenuPopup },
1748     { "WhiteClock", WhiteClock },
1749     { "BlackClock", BlackClock },
1750     { "Iconify", Iconify },
1751     { "ResetProc", ResetProc },
1752     { "LoadGameProc", LoadGameProc },
1753     { "LoadNextGameProc", LoadNextGameProc },
1754     { "LoadPrevGameProc", LoadPrevGameProc },
1755     { "LoadSelectedProc", LoadSelectedProc },
1756     { "ReloadGameProc", ReloadGameProc },
1757     { "LoadPositionProc", LoadPositionProc },
1758     { "LoadNextPositionProc", LoadNextPositionProc },
1759     { "LoadPrevPositionProc", LoadPrevPositionProc },
1760     { "ReloadPositionProc", ReloadPositionProc },
1761     { "CopyPositionProc", CopyPositionProc },
1762     { "PastePositionProc", PastePositionProc },
1763     { "CopyGameProc", CopyGameProc },
1764     { "PasteGameProc", PasteGameProc },
1765     { "SaveGameProc", SaveGameProc },
1766     { "SavePositionProc", SavePositionProc },
1767     { "MailMoveProc", MailMoveProc },
1768     { "ReloadCmailMsgProc", ReloadCmailMsgProc },
1769     { "QuitProc", QuitProc },
1770     { "MachineWhiteProc", MachineWhiteProc },
1771     { "MachineBlackProc", MachineBlackProc },
1772     { "AnalysisModeProc", AnalyzeModeProc },
1773     { "AnalyzeFileProc", AnalyzeFileProc },
1774     { "TwoMachinesProc", TwoMachinesProc },
1775     { "IcsClientProc", IcsClientProc },
1776     { "EditGameProc", EditGameProc },
1777     { "EditPositionProc", EditPositionProc },
1778     { "TrainingProc", EditPositionProc },
1779     { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
1780     { "ShowGameListProc", ShowGameListProc },
1781     { "ShowMoveListProc", HistoryShowProc},
1782     { "EditTagsProc", EditCommentProc },
1783     { "EditCommentProc", EditCommentProc },
1784     { "IcsAlarmProc", IcsAlarmProc },
1785     { "IcsInputBoxProc", IcsInputBoxProc },
1786     { "PauseProc", PauseProc },
1787     { "AcceptProc", AcceptProc },
1788     { "DeclineProc", DeclineProc },
1789     { "RematchProc", RematchProc },
1790     { "CallFlagProc", CallFlagProc },
1791     { "DrawProc", DrawProc },
1792     { "AdjournProc", AdjournProc },
1793     { "AbortProc", AbortProc },
1794     { "ResignProc", ResignProc },
1795     { "AdjuWhiteProc", AdjuWhiteProc },
1796     { "AdjuBlackProc", AdjuBlackProc },
1797     { "AdjuDrawProc", AdjuDrawProc },
1798     { "EnterKeyProc", EnterKeyProc },
1799     { "StopObservingProc", StopObservingProc },
1800     { "StopExaminingProc", StopExaminingProc },
1801     { "BackwardProc", BackwardProc },
1802     { "ForwardProc", ForwardProc },
1803     { "ToStartProc", ToStartProc },
1804     { "ToEndProc", ToEndProc },
1805     { "RevertProc", RevertProc },
1806     { "TruncateGameProc", TruncateGameProc },
1807     { "MoveNowProc", MoveNowProc },
1808     { "RetractMoveProc", RetractMoveProc },
1809     { "AlwaysQueenProc", AlwaysQueenProc },
1810     { "AnimateDraggingProc", AnimateDraggingProc },
1811     { "AnimateMovingProc", AnimateMovingProc },
1812     { "AutoflagProc", AutoflagProc },
1813     { "AutoflipProc", AutoflipProc },
1814     { "AutobsProc", AutobsProc },
1815     { "AutoraiseProc", AutoraiseProc },
1816     { "AutosaveProc", AutosaveProc },
1817     { "BlindfoldProc", BlindfoldProc },
1818     { "FlashMovesProc", FlashMovesProc },
1819     { "FlipViewProc", FlipViewProc },
1820     { "GetMoveListProc", GetMoveListProc },
1821 #if HIGHDRAG
1822     { "HighlightDraggingProc", HighlightDraggingProc },
1823 #endif
1824     { "HighlightLastMoveProc", HighlightLastMoveProc },
1825     { "IcsAlarmProc", IcsAlarmProc },
1826     { "MoveSoundProc", MoveSoundProc },
1827     { "OldSaveStyleProc", OldSaveStyleProc },
1828     { "PeriodicUpdatesProc", PeriodicUpdatesProc },
1829     { "PonderNextMoveProc", PonderNextMoveProc },
1830     { "PopupExitMessageProc", PopupExitMessageProc },
1831     { "PopupMoveErrorsProc", PopupMoveErrorsProc },
1832     { "PremoveProc", PremoveProc },
1833     { "QuietPlayProc", QuietPlayProc },
1834     { "ShowCoordsProc", ShowCoordsProc },
1835     { "ShowThinkingProc", ShowThinkingProc },
1836     { "HideThinkingProc", HideThinkingProc },
1837     { "TestLegalityProc", TestLegalityProc },
1838     { "InfoProc", InfoProc },
1839     { "ManProc", ManProc },
1840     { "HintProc", HintProc },
1841     { "BookProc", BookProc },
1842     { "AboutGameProc", AboutGameProc },
1843     { "AboutProc", AboutProc },
1844     { "DebugProc", DebugProc },
1845     { "NothingProc", NothingProc },
1846     { "CommentPopDown", (XtActionProc) CommentPopDown },
1847     { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
1848     { "TagsPopDown", (XtActionProc) TagsPopDown },
1849     { "ErrorPopDown", (XtActionProc) ErrorPopDown },
1850     { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
1851     { "AnalysisPopDown", (XtActionProc) AnalysisPopDown },
1852     { "FileNamePopDown", (XtActionProc) FileNamePopDown },
1853     { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
1854     { "GameListPopDown", (XtActionProc) GameListPopDown },
1855     { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1856     { "HistoryPopDown", (XtActionProc) HistoryPopDown },
1857     { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1858     { "ShufflePopDown", (XtActionProc) ShufflePopDown },
1859     { "EnginePopDown", (XtActionProc) EnginePopDown },
1860     { "UciPopDown", (XtActionProc) UciPopDown },
1861     { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
1862     { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
1863     { "SettingsPopDown", (XtActionProc) SettingsPopDown },
1864 };
1865
1866 char globalTranslations[] =
1867   ":<Key>R: ResignProc() \n \
1868    :<Key>r: ResetProc() \n \
1869    :<Key>g: LoadGameProc() \n \
1870    :<Key>N: LoadNextGameProc() \n \
1871    :<Key>P: LoadPrevGameProc() \n \
1872    :<Key>Q: QuitProc() \n \
1873    :<Key>F: ToEndProc() \n \
1874    :<Key>f: ForwardProc() \n \
1875    :<Key>B: ToStartProc() \n \
1876    :<Key>b: BackwardProc() \n \
1877    :<Key>p: PauseProc() \n \
1878    :<Key>d: DrawProc() \n \
1879    :<Key>t: CallFlagProc() \n \
1880    :<Key>i: Iconify() \n \
1881    :<Key>c: Iconify() \n \
1882    :<Key>v: FlipViewProc() \n \
1883    <KeyDown>Control_L: BackwardProc() \n \
1884    <KeyUp>Control_L: ForwardProc() \n \
1885    <KeyDown>Control_R: BackwardProc() \n \
1886    <KeyUp>Control_R: ForwardProc() \n \
1887    Shift<Key>1: AskQuestionProc(\"Direct command\",\
1888                                 \"Send to chess program:\",,1) \n \
1889    Shift<Key>2: AskQuestionProc(\"Direct command\",\
1890                                 \"Send to second chess program:\",,2) \n";
1891
1892 char boardTranslations[] =
1893    "<Btn1Down>: HandleUserMove() \n \
1894    <Btn1Up>: HandleUserMove() \n \
1895    <Btn1Motion>: AnimateUserMove() \n \
1896    Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1897                  PieceMenuPopup(menuB) \n \
1898    Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1899                  PieceMenuPopup(menuW) \n \
1900    Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1901                  PieceMenuPopup(menuW) \n \
1902    Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1903                  PieceMenuPopup(menuB) \n";
1904
1905 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1906 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1907
1908 char ICSInputTranslations[] =
1909     "<Key>Return: EnterKeyProc() \n";
1910
1911 String xboardResources[] = {
1912     "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1913     "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1914     "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1915     NULL
1916   };
1917
1918
1919 /* Max possible square size */
1920 #define MAXSQSIZE 256
1921
1922 static int xpm_avail[MAXSQSIZE];
1923
1924 #ifdef HAVE_DIR_STRUCT
1925
1926 /* Extract piece size from filename */
1927 static int
1928 xpm_getsize(name, len, ext)
1929      char *name;
1930      int len;
1931      char *ext;
1932 {
1933     char *p, *d;
1934     char buf[10];
1935
1936     if (len < 4)
1937       return 0;
1938
1939     if ((p=strchr(name, '.')) == NULL ||
1940         StrCaseCmp(p+1, ext) != 0)
1941       return 0;
1942
1943     p = name + 3;
1944     d = buf;
1945
1946     while (*p && isdigit(*p))
1947       *(d++) = *(p++);
1948
1949     *d = 0;
1950     return atoi(buf);
1951 }
1952
1953 /* Setup xpm_avail */
1954 static int
1955 xpm_getavail(dirname, ext)
1956      char *dirname;
1957      char *ext;
1958 {
1959     DIR *dir;
1960     struct dirent *ent;
1961     int  i;
1962
1963     for (i=0; i<MAXSQSIZE; ++i)
1964       xpm_avail[i] = 0;
1965
1966     if (appData.debugMode)
1967       fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1968
1969     dir = opendir(dirname);
1970     if (!dir)
1971       {
1972           fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1973                   programName, dirname);
1974           exit(1);
1975       }
1976
1977     while ((ent=readdir(dir)) != NULL) {
1978         i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1979         if (i > 0 && i < MAXSQSIZE)
1980           xpm_avail[i] = 1;
1981     }
1982
1983     closedir(dir);
1984
1985     return 0;
1986 }
1987
1988 void
1989 xpm_print_avail(fp, ext)
1990      FILE *fp;
1991      char *ext;
1992 {
1993     int i;
1994
1995     fprintf(fp, _("Available `%s' sizes:\n"), ext);
1996     for (i=1; i<MAXSQSIZE; ++i) {
1997         if (xpm_avail[i])
1998           printf("%d\n", i);
1999     }
2000 }
2001
2002 /* Return XPM piecesize closest to size */
2003 int
2004 xpm_closest_to(dirname, size, ext)
2005      char *dirname;
2006      int size;
2007      char *ext;
2008 {
2009     int i;
2010     int sm_diff = MAXSQSIZE;
2011     int sm_index = 0;
2012     int diff;
2013
2014     xpm_getavail(dirname, ext);
2015
2016     if (appData.debugMode)
2017       xpm_print_avail(stderr, ext);
2018
2019     for (i=1; i<MAXSQSIZE; ++i) {
2020         if (xpm_avail[i]) {
2021             diff = size - i;
2022             diff = (diff<0) ? -diff : diff;
2023             if (diff < sm_diff) {
2024                 sm_diff = diff;
2025                 sm_index = i;
2026             }
2027         }
2028     }
2029
2030     if (!sm_index) {
2031         fprintf(stderr, _("Error: No `%s' files!\n"), ext);
2032         exit(1);
2033     }
2034
2035     return sm_index;
2036 }
2037 #else   /* !HAVE_DIR_STRUCT */
2038 /* If we are on a system without a DIR struct, we can't
2039    read the directory, so we can't collect a list of
2040    filenames, etc., so we can't do any size-fitting. */
2041 int
2042 xpm_closest_to(dirname, size, ext)
2043      char *dirname;
2044      int size;
2045      char *ext;
2046 {
2047     fprintf(stderr, _("\
2048 Warning: No DIR structure found on this system --\n\
2049          Unable to autosize for XPM/XIM pieces.\n\
2050    Please report this error to frankm@hiwaay.net.\n\
2051    Include system type & operating system in message.\n"));
2052     return size;
2053 }
2054 #endif /* HAVE_DIR_STRUCT */
2055
2056 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
2057                              "magenta", "cyan", "white" };
2058 typedef struct {
2059     int attr, bg, fg;
2060 } TextColors;
2061 TextColors textColors[(int)NColorClasses];
2062
2063 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
2064 static int
2065 parse_color(str, which)
2066      char *str;
2067      int which;
2068 {
2069     char *p, buf[100], *d;
2070     int i;
2071
2072     if (strlen(str) > 99)       /* watch bounds on buf */
2073       return -1;
2074
2075     p = str;
2076     d = buf;
2077     for (i=0; i<which; ++i) {
2078         p = strchr(p, ',');
2079         if (!p)
2080           return -1;
2081         ++p;
2082     }
2083
2084     /* Could be looking at something like:
2085        black, , 1
2086        .. in which case we want to stop on a comma also */
2087     while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
2088       ++p;
2089
2090     if (*p == ',') {
2091         return -1;              /* Use default for empty field */
2092     }
2093
2094     if (which == 2 || isdigit(*p))
2095       return atoi(p);
2096
2097     while (*p && isalpha(*p))
2098       *(d++) = *(p++);
2099
2100     *d = 0;
2101
2102     for (i=0; i<8; ++i) {
2103         if (!StrCaseCmp(buf, cnames[i]))
2104           return which? (i+40) : (i+30);
2105     }
2106     if (!StrCaseCmp(buf, "default")) return -1;
2107
2108     fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
2109     return -2;
2110 }
2111
2112 static int
2113 parse_cpair(cc, str)
2114      ColorClass cc;
2115      char *str;
2116 {
2117     if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
2118         fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
2119                 programName, str);
2120         return -1;
2121     }
2122
2123     /* bg and attr are optional */
2124     textColors[(int)cc].bg = parse_color(str, 1);
2125     if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
2126         textColors[(int)cc].attr = 0;
2127     }
2128     return 0;
2129 }
2130
2131
2132 /* Arrange to catch delete-window events */
2133 Atom wm_delete_window;
2134 void
2135 CatchDeleteWindow(Widget w, String procname)
2136 {
2137   char buf[MSG_SIZ];
2138   XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
2139   sprintf(buf, "<Message>WM_PROTOCOLS: %s() \n", procname);
2140   XtAugmentTranslations(w, XtParseTranslationTable(buf));
2141 }
2142
2143 void
2144 BoardToTop()
2145 {
2146   Arg args[16];
2147   XtSetArg(args[0], XtNiconic, False);
2148   XtSetValues(shellWidget, args, 1);
2149
2150   XtPopup(shellWidget, XtGrabNone); /* Raise if lowered  */
2151 }
2152
2153 #ifdef IDSIZES
2154   // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
2155 #else
2156 #define BoardSize int
2157 void InitDrawingSizes(BoardSize boardSize, int flags)
2158 {   // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
2159     Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
2160     Arg args[16];
2161     XtGeometryResult gres;
2162     int i;
2163
2164     if(!formWidget) return;
2165
2166     /*
2167      * Enable shell resizing.
2168      */
2169     shellArgs[0].value = (XtArgVal) &w;
2170     shellArgs[1].value = (XtArgVal) &h;
2171     XtGetValues(shellWidget, shellArgs, 2);
2172
2173     shellArgs[4].value = 2*w; shellArgs[2].value = 10;
2174     shellArgs[5].value = 2*h; shellArgs[3].value = 10;
2175     XtSetValues(shellWidget, &shellArgs[2], 4);
2176
2177     XtSetArg(args[0], XtNdefaultDistance, &sep);
2178     XtGetValues(formWidget, args, 1);
2179
2180     boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
2181     boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
2182     CreateGrid();
2183
2184     XtSetArg(args[0], XtNwidth, boardWidth);
2185     XtSetArg(args[1], XtNheight, boardHeight);
2186     XtSetValues(boardWidget, args, 2);
2187
2188     timerWidth = (boardWidth - sep) / 2;
2189     XtSetArg(args[0], XtNwidth, timerWidth);
2190     XtSetValues(whiteTimerWidget, args, 1);
2191     XtSetValues(blackTimerWidget, args, 1);
2192
2193     XawFormDoLayout(formWidget, False);
2194
2195     if (appData.titleInWindow) {
2196         i = 0;
2197         XtSetArg(args[i], XtNborderWidth, &bor); i++;
2198         XtSetArg(args[i], XtNheight, &h);  i++;
2199         XtGetValues(titleWidget, args, i);
2200         if (smallLayout) {
2201             w = boardWidth - 2*bor;
2202         } else {
2203             XtSetArg(args[0], XtNwidth, &w);
2204             XtGetValues(menuBarWidget, args, 1);
2205             w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
2206         }
2207
2208         gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2209         if (gres != XtGeometryYes && appData.debugMode) {
2210             fprintf(stderr,
2211                     _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2212                     programName, gres, w, h, wr, hr);
2213         }
2214     }
2215
2216     XawFormDoLayout(formWidget, True);
2217
2218     /*
2219      * Inhibit shell resizing.
2220      */
2221     shellArgs[0].value = w = (XtArgVal) boardWidth + marginW;
2222     shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
2223     shellArgs[4].value = shellArgs[2].value = w;
2224     shellArgs[5].value = shellArgs[3].value = h;
2225     XtSetValues(shellWidget, &shellArgs[0], 6);
2226 }
2227 #endif
2228
2229 int
2230 main(argc, argv)
2231      int argc;
2232      char **argv;
2233 {
2234     int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
2235     XSetWindowAttributes window_attributes;
2236     Arg args[16];
2237     Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
2238     XrmValue vFrom, vTo;
2239     XtGeometryResult gres;
2240     char *p;
2241     XrmDatabase xdb;
2242     int forceMono = False;
2243 #define INDIRECTION
2244 #ifdef INDIRECTION
2245     // [HGM] before anything else, expand any indirection files amongst options
2246     char *argvCopy[1000]; // 1000 seems enough
2247     char newArgs[10000];  // holds actual characters
2248     int k = 0;
2249
2250     srandom(time(0)); // [HGM] book: make random truly random
2251
2252     j = 0;
2253     for(i=0; i<argc; i++) {
2254         if(j >= 1000-2) { printf(_("too many arguments\n")); exit(-1); }
2255 //fprintf(stderr, "arg %s\n", argv[i]);
2256         if(argv[i][0] != '@') argvCopy[j++] = argv[i]; else {
2257             char c;
2258             FILE *f = fopen(argv[i]+1, "rb");
2259             if(f == NULL) { fprintf(stderr, _("ignore %s\n"), argv[i]); continue; } // do not expand non-existing
2260             argvCopy[j++] = newArgs + k; // get ready for first argument from file
2261             while((c = fgetc(f)) != EOF) { // each line of file inserts 1 argument in the list
2262                 if(c == '\n') {
2263                     if(j >= 1000-2) { printf(_("too many arguments\n")); exit(-1); }
2264                     newArgs[k++] = 0;  // terminate current arg
2265                     if(k >= 10000-1) { printf(_("too long arguments\n")); exit(-1); }
2266                     argvCopy[j++] = newArgs + k; // get ready for next
2267                 } else {
2268                     if(k >= 10000-1) { printf(_("too long arguments\n")); exit(-1); }
2269                     newArgs[k++] = c;
2270                 }
2271             }
2272             newArgs[k] = 0;
2273             j--;
2274             fclose(f);
2275         }
2276     }
2277     argvCopy[j] = NULL;
2278     argv = argvCopy;
2279     argc = j;
2280 #if 0
2281     if(appData.debugMode,1) { // OK, appData is not initialized here yet...
2282         for(i=0; i<argc; i++) fprintf(stderr, "argv[%2d] = '%s'\n", i, argv[i]);
2283     }
2284 #endif
2285 #endif
2286
2287
2288     setbuf(stdout, NULL);
2289     setbuf(stderr, NULL);
2290     debugFP = stderr;
2291
2292     programName = strrchr(argv[0], '/');
2293     if (programName == NULL)
2294       programName = argv[0];
2295     else
2296       programName++;
2297
2298 #ifdef ENABLE_NLS
2299     XtSetLanguageProc(NULL, NULL, NULL);
2300     bindtextdomain(PRODUCT, LOCALEDIR);
2301     textdomain(PRODUCT);
2302 #endif
2303
2304     shellWidget =
2305       XtAppInitialize(&appContext, "XBoard", shellOptions,
2306                       XtNumber(shellOptions),
2307                       &argc, argv, xboardResources, NULL, 0);
2308     if (argc > 1) {
2309         fprintf(stderr, _("%s: unrecognized argument %s\n"),
2310                 programName, argv[1]);
2311         exit(2);
2312     }
2313
2314     if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
2315         chessDir = ".";
2316     } else {
2317         if (chdir(chessDir) != 0) {
2318             fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
2319             perror(chessDir);
2320             exit(1);
2321         }
2322     }
2323
2324     p = getenv("HOME");
2325     if (p == NULL) p = "/tmp";
2326     i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
2327     gameCopyFilename = (char*) malloc(i);
2328     gamePasteFilename = (char*) malloc(i);
2329     sprintf(gameCopyFilename, "%s/.xboard%05uc.pgn", p, getpid());
2330     sprintf(gamePasteFilename, "%s/.xboard%05up.pgn", p, getpid());
2331
2332     XtGetApplicationResources(shellWidget, (XtPointer) &appData,
2333                               clientResources, XtNumber(clientResources),
2334                               NULL, 0);
2335
2336     if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
2337         /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
2338         if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL)  {
2339            printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
2340            exit(errno);
2341         }
2342         setbuf(debugFP, NULL);
2343     }
2344
2345     /* [HGM,HR] make sure board size is acceptable */
2346     if(appData.NrFiles > BOARD_SIZE ||
2347        appData.NrRanks > BOARD_SIZE   )
2348          DisplayFatalError(_("Recompile with BOARD_SIZE > 12, to support this size"), 0, 2);
2349
2350 #if !HIGHDRAG
2351     /* This feature does not work; animation needs a rewrite */
2352     appData.highlightDragging = FALSE;
2353 #endif
2354     InitBackEnd1();
2355
2356     xDisplay = XtDisplay(shellWidget);
2357     xScreen = DefaultScreen(xDisplay);
2358     wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
2359
2360         gameInfo.variant = StringToVariant(appData.variant);
2361         InitPosition(FALSE);
2362 #if 0
2363     /*
2364      * Determine boardSize
2365      */
2366     gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] boardsize: make sure we start as 8x8
2367
2368 //#ifndef IDSIZE
2369     // [HGM] as long as we have not created the possibility to change size while running, start with requested size
2370     gameInfo.boardWidth    = appData.NrFiles > 0 ? appData.NrFiles : 8;
2371     gameInfo.boardHeight   = appData.NrRanks > 0 ? appData.NrRanks : 8;
2372     gameInfo.holdingsWidth = appData.holdingsSize > 0 ? 2 : 0;
2373 #endif
2374
2375
2376 #ifdef IDSIZE
2377     InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
2378 #else
2379     if (isdigit(appData.boardSize[0])) {
2380         i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
2381                    &lineGap, &clockFontPxlSize, &coordFontPxlSize,
2382                    &fontPxlSize, &smallLayout, &tinyLayout);
2383         if (i == 0) {
2384             fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
2385                     programName, appData.boardSize);
2386             exit(2);
2387         }
2388         if (i < 7) {
2389             /* Find some defaults; use the nearest known size */
2390             SizeDefaults *szd, *nearest;
2391             int distance = 99999;
2392             nearest = szd = sizeDefaults;
2393             while (szd->name != NULL) {
2394                 if (abs(szd->squareSize - squareSize) < distance) {
2395                     nearest = szd;
2396                     distance = abs(szd->squareSize - squareSize);
2397                     if (distance == 0) break;
2398                 }
2399                 szd++;
2400             }
2401             if (i < 2) lineGap = nearest->lineGap;
2402             if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
2403             if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
2404             if (i < 5) fontPxlSize = nearest->fontPxlSize;
2405             if (i < 6) smallLayout = nearest->smallLayout;
2406             if (i < 7) tinyLayout = nearest->tinyLayout;
2407         }
2408     } else {
2409         SizeDefaults *szd = sizeDefaults;
2410         if (*appData.boardSize == NULLCHAR) {
2411             while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
2412                    DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
2413               szd++;
2414             }
2415             if (szd->name == NULL) szd--;
2416         } else {
2417             while (szd->name != NULL &&
2418                    StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
2419             if (szd->name == NULL) {
2420                 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
2421                         programName, appData.boardSize);
2422                 exit(2);
2423             }
2424         }
2425         squareSize = szd->squareSize;
2426         lineGap = szd->lineGap;
2427         clockFontPxlSize = szd->clockFontPxlSize;
2428         coordFontPxlSize = szd->coordFontPxlSize;
2429         fontPxlSize = szd->fontPxlSize;
2430         smallLayout = szd->smallLayout;
2431         tinyLayout = szd->tinyLayout;
2432     }
2433
2434     /* Now, using squareSize as a hint, find a good XPM/XIM set size */
2435     if (strlen(appData.pixmapDirectory) > 0) {
2436         p = ExpandPathName(appData.pixmapDirectory);
2437         if (!p) {
2438             fprintf(stderr, _("Error expanding path name \"%s\"\n"),
2439                    appData.pixmapDirectory);
2440             exit(1);
2441         }
2442         if (appData.debugMode) {
2443           fprintf(stderr, _("\
2444 XBoard square size (hint): %d\n\
2445 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
2446         }
2447         squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
2448         if (appData.debugMode) {
2449             fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
2450         }
2451     }
2452
2453     /* [HR] height treated separately (hacked) */
2454     boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
2455     boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
2456     if (appData.showJail == 1) {
2457         /* Jail on top and bottom */
2458         XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2459         XtSetArg(boardArgs[2], XtNheight,
2460                  boardHeight + 2*(lineGap + squareSize));
2461     } else if (appData.showJail == 2) {
2462         /* Jail on sides */
2463         XtSetArg(boardArgs[1], XtNwidth,
2464                  boardWidth + 2*(lineGap + squareSize));
2465         XtSetArg(boardArgs[2], XtNheight, boardHeight);
2466     } else {
2467         /* No jail */
2468         XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2469         XtSetArg(boardArgs[2], XtNheight, boardHeight);
2470     }
2471
2472     /*
2473      * Determine what fonts to use.
2474      */
2475     appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2476     clockFontID = XLoadFont(xDisplay, appData.clockFont);
2477     clockFontStruct = XQueryFont(xDisplay, clockFontID);
2478     appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2479     coordFontID = XLoadFont(xDisplay, appData.coordFont);
2480     coordFontStruct = XQueryFont(xDisplay, coordFontID);
2481     appData.font = FindFont(appData.font, fontPxlSize);
2482     countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
2483     countFontStruct = XQueryFont(xDisplay, countFontID);
2484 //    appData.font = FindFont(appData.font, fontPxlSize);
2485
2486     xdb = XtDatabase(xDisplay);
2487     XrmPutStringResource(&xdb, "*font", appData.font);
2488
2489     /*
2490      * Detect if there are not enough colors available and adapt.
2491      */
2492     if (DefaultDepth(xDisplay, xScreen) <= 2) {
2493       appData.monoMode = True;
2494     }
2495
2496     if (!appData.monoMode) {
2497         vFrom.addr = (caddr_t) appData.lightSquareColor;
2498         vFrom.size = strlen(appData.lightSquareColor);
2499         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2500         if (vTo.addr == NULL) {
2501           appData.monoMode = True;
2502           forceMono = True;
2503         } else {
2504           lightSquareColor = *(Pixel *) vTo.addr;
2505         }
2506     }
2507     if (!appData.monoMode) {
2508         vFrom.addr = (caddr_t) appData.darkSquareColor;
2509         vFrom.size = strlen(appData.darkSquareColor);
2510         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2511         if (vTo.addr == NULL) {
2512           appData.monoMode = True;
2513           forceMono = True;
2514         } else {
2515           darkSquareColor = *(Pixel *) vTo.addr;
2516         }
2517     }
2518     if (!appData.monoMode) {
2519         vFrom.addr = (caddr_t) appData.whitePieceColor;
2520         vFrom.size = strlen(appData.whitePieceColor);
2521         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2522         if (vTo.addr == NULL) {
2523           appData.monoMode = True;
2524           forceMono = True;
2525         } else {
2526           whitePieceColor = *(Pixel *) vTo.addr;
2527         }
2528     }
2529     if (!appData.monoMode) {
2530         vFrom.addr = (caddr_t) appData.blackPieceColor;
2531         vFrom.size = strlen(appData.blackPieceColor);
2532         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2533         if (vTo.addr == NULL) {
2534           appData.monoMode = True;
2535           forceMono = True;
2536         } else {
2537           blackPieceColor = *(Pixel *) vTo.addr;
2538         }
2539     }
2540
2541     if (!appData.monoMode) {
2542         vFrom.addr = (caddr_t) appData.highlightSquareColor;
2543         vFrom.size = strlen(appData.highlightSquareColor);
2544         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2545         if (vTo.addr == NULL) {
2546           appData.monoMode = True;
2547           forceMono = True;
2548         } else {
2549           highlightSquareColor = *(Pixel *) vTo.addr;
2550         }
2551     }
2552
2553     if (!appData.monoMode) {
2554         vFrom.addr = (caddr_t) appData.premoveHighlightColor;
2555         vFrom.size = strlen(appData.premoveHighlightColor);
2556         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2557         if (vTo.addr == NULL) {
2558           appData.monoMode = True;
2559           forceMono = True;
2560         } else {
2561           premoveHighlightColor = *(Pixel *) vTo.addr;
2562         }
2563     }
2564
2565     if (forceMono) {
2566       fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2567               programName);
2568     }
2569
2570     if (appData.monoMode && appData.debugMode) {
2571         fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2572                 (unsigned long) XWhitePixel(xDisplay, xScreen),
2573                 (unsigned long) XBlackPixel(xDisplay, xScreen));
2574     }
2575
2576     if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2577         parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2578         parse_cpair(ColorChannel1, appData.colorChannel1) < 0  ||
2579         parse_cpair(ColorChannel, appData.colorChannel) < 0  ||
2580         parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2581         parse_cpair(ColorTell, appData.colorTell) < 0 ||
2582         parse_cpair(ColorChallenge, appData.colorChallenge) < 0  ||
2583         parse_cpair(ColorRequest, appData.colorRequest) < 0  ||
2584         parse_cpair(ColorSeek, appData.colorSeek) < 0  ||
2585         parse_cpair(ColorNormal, appData.colorNormal) < 0)
2586       {
2587           if (appData.colorize) {
2588               fprintf(stderr,
2589                       _("%s: can't parse color names; disabling colorization\n"),
2590                       programName);
2591           }
2592           appData.colorize = FALSE;
2593       }
2594     textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2595     textColors[ColorNone].attr = 0;
2596
2597     XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2598
2599     /*
2600      * widget hierarchy
2601      */
2602     if (tinyLayout) {
2603         layoutName = "tinyLayout";
2604     } else if (smallLayout) {
2605         layoutName = "smallLayout";
2606     } else {
2607         layoutName = "normalLayout";
2608     }
2609     /* Outer layoutWidget is there only to provide a name for use in
2610        resources that depend on the layout style */
2611     layoutWidget =
2612       XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2613                             layoutArgs, XtNumber(layoutArgs));
2614     formWidget =
2615       XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2616                             formArgs, XtNumber(formArgs));
2617     XtSetArg(args[0], XtNdefaultDistance, &sep);
2618     XtGetValues(formWidget, args, 1);
2619
2620     j = 0;
2621     widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2622     XtSetArg(args[0], XtNtop,    XtChainTop);
2623     XtSetArg(args[1], XtNbottom, XtChainTop);
2624     XtSetValues(menuBarWidget, args, 2);
2625
2626     widgetList[j++] = whiteTimerWidget =
2627       XtCreateWidget("whiteTime", labelWidgetClass,
2628                      formWidget, timerArgs, XtNumber(timerArgs));
2629     XtSetArg(args[0], XtNfont, clockFontStruct);
2630     XtSetArg(args[1], XtNtop,    XtChainTop);
2631     XtSetArg(args[2], XtNbottom, XtChainTop);
2632     XtSetValues(whiteTimerWidget, args, 3);
2633
2634     widgetList[j++] = blackTimerWidget =
2635       XtCreateWidget("blackTime", labelWidgetClass,
2636                      formWidget, timerArgs, XtNumber(timerArgs));
2637     XtSetArg(args[0], XtNfont, clockFontStruct);
2638     XtSetArg(args[1], XtNtop,    XtChainTop);
2639     XtSetArg(args[2], XtNbottom, XtChainTop);
2640     XtSetValues(blackTimerWidget, args, 3);
2641
2642     if (appData.titleInWindow) {
2643         widgetList[j++] = titleWidget =
2644           XtCreateWidget("title", labelWidgetClass, formWidget,
2645                          titleArgs, XtNumber(titleArgs));
2646         XtSetArg(args[0], XtNtop,    XtChainTop);
2647         XtSetArg(args[1], XtNbottom, XtChainTop);
2648         XtSetValues(titleWidget, args, 2);
2649     }
2650
2651     if (appData.showButtonBar) {
2652       widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2653       XtSetArg(args[0], XtNleft,  XtChainRight); // [HGM] glue to right window edge
2654       XtSetArg(args[1], XtNright, XtChainRight); //       for good run-time sizing
2655       XtSetArg(args[2], XtNtop,    XtChainTop);
2656       XtSetArg(args[3], XtNbottom, XtChainTop);
2657       XtSetValues(buttonBarWidget, args, 4);
2658     }
2659
2660     widgetList[j++] = messageWidget =
2661       XtCreateWidget("message", labelWidgetClass, formWidget,
2662                      messageArgs, XtNumber(messageArgs));
2663     XtSetArg(args[0], XtNtop,    XtChainTop);
2664     XtSetArg(args[1], XtNbottom, XtChainTop);
2665     XtSetValues(messageWidget, args, 2);
2666
2667     widgetList[j++] = boardWidget =
2668       XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2669                      XtNumber(boardArgs));
2670
2671     XtManageChildren(widgetList, j);
2672
2673     timerWidth = (boardWidth - sep) / 2;
2674     XtSetArg(args[0], XtNwidth, timerWidth);
2675     XtSetValues(whiteTimerWidget, args, 1);
2676     XtSetValues(blackTimerWidget, args, 1);
2677
2678     XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2679     XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2680     XtGetValues(whiteTimerWidget, args, 2);
2681
2682     if (appData.showButtonBar) {
2683       XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2684       XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2685       XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2686     }
2687
2688     /*
2689      * formWidget uses these constraints but they are stored
2690      * in the children.
2691      */
2692     i = 0;
2693     XtSetArg(args[i], XtNfromHoriz, 0); i++;
2694     XtSetValues(menuBarWidget, args, i);
2695     if (appData.titleInWindow) {
2696         if (smallLayout) {
2697             i = 0;
2698             XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2699             XtSetValues(whiteTimerWidget, args, i);
2700             i = 0;
2701             XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2702             XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2703             XtSetValues(blackTimerWidget, args, i);
2704             i = 0;
2705             XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2706             XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2707             XtSetValues(titleWidget, args, i);
2708             i = 0;
2709             XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2710             XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2711             XtSetValues(messageWidget, args, i);
2712             if (appData.showButtonBar) {
2713               i = 0;
2714               XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2715               XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2716               XtSetValues(buttonBarWidget, args, i);
2717             }
2718         } else {
2719             i = 0;
2720             XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2721             XtSetValues(whiteTimerWidget, args, i);
2722             i = 0;
2723             XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2724             XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2725             XtSetValues(blackTimerWidget, args, i);
2726             i = 0;
2727             XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2728             XtSetValues(titleWidget, args, i);
2729             i = 0;
2730             XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2731             XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2732             XtSetValues(messageWidget, args, i);
2733             if (appData.showButtonBar) {
2734               i = 0;
2735               XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2736               XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2737               XtSetValues(buttonBarWidget, args, i);
2738             }
2739         }
2740     } else {
2741         i = 0;
2742         XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2743         XtSetValues(whiteTimerWidget, args, i);
2744         i = 0;
2745         XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2746         XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2747         XtSetValues(blackTimerWidget, args, i);
2748         i = 0;
2749         XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2750         XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2751         XtSetValues(messageWidget, args, i);
2752         if (appData.showButtonBar) {
2753           i = 0;
2754           XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2755           XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2756           XtSetValues(buttonBarWidget, args, i);
2757         }
2758     }
2759     i = 0;
2760     XtSetArg(args[0], XtNfromVert, messageWidget);
2761     XtSetArg(args[1], XtNtop,    XtChainTop);
2762     XtSetArg(args[2], XtNbottom, XtChainBottom);
2763     XtSetArg(args[3], XtNleft,   XtChainLeft);
2764     XtSetArg(args[4], XtNright,  XtChainRight);
2765     XtSetValues(boardWidget, args, 5);
2766
2767     XtRealizeWidget(shellWidget);
2768
2769     /*
2770      * Correct the width of the message and title widgets.
2771      * It is not known why some systems need the extra fudge term.
2772      * The value "2" is probably larger than needed.
2773      */
2774     XawFormDoLayout(formWidget, False);
2775
2776 #define WIDTH_FUDGE 2
2777     i = 0;
2778     XtSetArg(args[i], XtNborderWidth, &bor);  i++;
2779     XtSetArg(args[i], XtNheight, &h);  i++;
2780     XtGetValues(messageWidget, args, i);
2781     if (appData.showButtonBar) {
2782       i = 0;
2783       XtSetArg(args[i], XtNwidth, &w);  i++;
2784       XtGetValues(buttonBarWidget, args, i);
2785       w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2786     } else {
2787       w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2788     }
2789
2790     gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2791     if (gres != XtGeometryYes && appData.debugMode) {
2792       fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2793               programName, gres, w, h, wr, hr);
2794     }
2795
2796     /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2797     /* The size used for the child widget in layout lags one resize behind
2798        its true size, so we resize a second time, 1 pixel smaller.  Yeech! */
2799     w--;
2800     gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2801     if (gres != XtGeometryYes && appData.debugMode) {
2802       fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2803               programName, gres, w, h, wr, hr);
2804     }
2805     /* !! end hack */
2806     XtSetArg(args[0], XtNleft,  XtChainLeft);  // [HGM] glue ends for good run-time sizing
2807     XtSetArg(args[1], XtNright, XtChainRight);
2808     XtSetValues(messageWidget, args, 2);
2809
2810     if (appData.titleInWindow) {
2811         i = 0;
2812         XtSetArg(args[i], XtNborderWidth, &bor); i++;
2813         XtSetArg(args[i], XtNheight, &h);  i++;
2814         XtGetValues(titleWidget, args, i);
2815         if (smallLayout) {
2816             w = boardWidth - 2*bor;
2817         } else {
2818             XtSetArg(args[0], XtNwidth, &w);
2819             XtGetValues(menuBarWidget, args, 1);
2820             w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2821         }
2822
2823         gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2824         if (gres != XtGeometryYes && appData.debugMode) {
2825             fprintf(stderr,
2826                     _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2827                     programName, gres, w, h, wr, hr);
2828         }
2829     }
2830     XawFormDoLayout(formWidget, True);
2831
2832     xBoardWindow = XtWindow(boardWidget);
2833
2834     // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2835     //       not need to go into InitDrawingSizes().
2836 #endif
2837
2838     /*
2839      * Create X checkmark bitmap and initialize option menu checks.
2840      */
2841     ReadBitmap(&xMarkPixmap, "checkmark.bm",
2842                checkmark_bits, checkmark_width, checkmark_height);
2843     XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2844     if (appData.alwaysPromoteToQueen) {
2845         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2846                     args, 1);
2847     }
2848     if (appData.animateDragging) {
2849         XtSetValues(XtNameToWidget(menuBarWidget,
2850                                    "menuOptions.Animate Dragging"),
2851                     args, 1);
2852     }
2853     if (appData.animate) {
2854         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2855                     args, 1);
2856     }
2857     if (appData.autoComment) {
2858         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2859                     args, 1);
2860     }
2861     if (appData.autoCallFlag) {
2862         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2863                     args, 1);
2864     }
2865     if (appData.autoFlipView) {
2866         XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2867                     args, 1);
2868     }
2869     if (appData.autoObserve) {
2870         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2871                     args, 1);
2872     }
2873     if (appData.autoRaiseBoard) {
2874         XtSetValues(XtNameToWidget(menuBarWidget,
2875                                    "menuOptions.Auto Raise Board"), args, 1);
2876     }
2877     if (appData.autoSaveGames) {
2878         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2879                     args, 1);
2880     }
2881     if (appData.saveGameFile[0] != NULLCHAR) {
2882         /* Can't turn this off from menu */
2883         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2884                     args, 1);
2885         XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2886                        False);
2887
2888     }
2889     if (appData.blindfold) {
2890         XtSetValues(XtNameToWidget(menuBarWidget,
2891                                    "menuOptions.Blindfold"), args, 1);
2892     }
2893     if (appData.flashCount > 0) {
2894         XtSetValues(XtNameToWidget(menuBarWidget,
2895                                    "menuOptions.Flash Moves"),
2896                     args, 1);
2897     }
2898     if (appData.getMoveList) {
2899         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2900                     args, 1);
2901     }
2902 #if HIGHDRAG
2903     if (appData.highlightDragging) {
2904         XtSetValues(XtNameToWidget(menuBarWidget,
2905                                    "menuOptions.Highlight Dragging"),
2906                     args, 1);
2907     }
2908 #endif
2909     if (appData.highlightLastMove) {
2910         XtSetValues(XtNameToWidget(menuBarWidget,
2911                                    "menuOptions.Highlight Last Move"),
2912                     args, 1);
2913     }
2914     if (appData.icsAlarm) {
2915         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2916                     args, 1);
2917     }
2918     if (appData.ringBellAfterMoves) {
2919         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2920                     args, 1);
2921     }
2922     if (appData.oldSaveStyle) {
2923         XtSetValues(XtNameToWidget(menuBarWidget,
2924                                    "menuOptions.Old Save Style"), args, 1);
2925     }
2926     if (appData.periodicUpdates) {
2927         XtSetValues(XtNameToWidget(menuBarWidget,
2928                                    "menuOptions.Periodic Updates"), args, 1);
2929     }
2930     if (appData.ponderNextMove) {
2931         XtSetValues(XtNameToWidget(menuBarWidget,
2932                                    "menuOptions.Ponder Next Move"), args, 1);
2933     }
2934     if (appData.popupExitMessage) {
2935         XtSetValues(XtNameToWidget(menuBarWidget,
2936                                    "menuOptions.Popup Exit Message"), args, 1);
2937     }
2938     if (appData.popupMoveErrors) {
2939         XtSetValues(XtNameToWidget(menuBarWidget,
2940                                    "menuOptions.Popup Move Errors"), args, 1);
2941     }
2942     if (appData.premove) {
2943         XtSetValues(XtNameToWidget(menuBarWidget,
2944                                    "menuOptions.Premove"), args, 1);
2945     }
2946     if (appData.quietPlay) {
2947         XtSetValues(XtNameToWidget(menuBarWidget,
2948                                    "menuOptions.Quiet Play"), args, 1);
2949     }
2950     if (appData.showCoords) {
2951         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2952                     args, 1);
2953     }
2954     if (appData.hideThinkingFromHuman) {
2955         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2956                     args, 1);
2957     }
2958     if (appData.testLegality) {
2959         XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2960                     args, 1);
2961     }
2962
2963     /*
2964      * Create an icon.
2965      */
2966     ReadBitmap(&wIconPixmap, "icon_white.bm",
2967                icon_white_bits, icon_white_width, icon_white_height);
2968     ReadBitmap(&bIconPixmap, "icon_black.bm",
2969                icon_black_bits, icon_black_width, icon_black_height);
2970     iconPixmap = wIconPixmap;
2971     i = 0;
2972     XtSetArg(args[i], XtNiconPixmap, iconPixmap);  i++;
2973     XtSetValues(shellWidget, args, i);
2974
2975     /*
2976      * Create a cursor for the board widget.
2977      */
2978     window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2979     XChangeWindowAttributes(xDisplay, xBoardWindow,
2980                             CWCursor, &window_attributes);
2981
2982     /*
2983      * Inhibit shell resizing.
2984      */
2985     shellArgs[0].value = (XtArgVal) &w;
2986     shellArgs[1].value = (XtArgVal) &h;
2987     XtGetValues(shellWidget, shellArgs, 2);
2988     shellArgs[4].value = shellArgs[2].value = w;
2989     shellArgs[5].value = shellArgs[3].value = h;
2990     XtSetValues(shellWidget, &shellArgs[2], 4);
2991     marginW =  w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2992     marginH =  h - boardHeight;
2993
2994     CatchDeleteWindow(shellWidget, "QuitProc");
2995
2996     CreateGCs();
2997     CreateGrid();
2998 #if HAVE_LIBXPM
2999     if (appData.bitmapDirectory[0] != NULLCHAR) {
3000       CreatePieces();
3001     } else {
3002       CreateXPMPieces();
3003     }
3004 #else
3005     CreateXIMPieces();
3006     /* Create regular pieces */
3007     if (!useImages) CreatePieces();
3008 #endif
3009
3010     CreatePieceMenus();
3011
3012     if (appData.animate || appData.animateDragging)
3013       CreateAnimVars();
3014
3015     XtAugmentTranslations(formWidget,
3016                           XtParseTranslationTable(globalTranslations));
3017     XtAugmentTranslations(boardWidget,
3018                           XtParseTranslationTable(boardTranslations));
3019     XtAugmentTranslations(whiteTimerWidget,
3020                           XtParseTranslationTable(whiteTranslations));
3021     XtAugmentTranslations(blackTimerWidget,
3022                           XtParseTranslationTable(blackTranslations));
3023
3024     /* Why is the following needed on some versions of X instead
3025      * of a translation? */
3026     XtAddEventHandler(boardWidget, ExposureMask, False,
3027                       (XtEventHandler) EventProc, NULL);
3028     /* end why */
3029
3030     InitBackEnd2();
3031
3032     if (errorExitStatus == -1) {
3033         if (appData.icsActive) {
3034             /* We now wait until we see "login:" from the ICS before
3035                sending the logon script (problems with timestamp otherwise) */
3036             /*ICSInitScript();*/
3037             if (appData.icsInputBox) ICSInputBoxPopUp();
3038         }
3039
3040         signal(SIGINT, IntSigHandler);
3041         signal(SIGTERM, IntSigHandler);
3042         if (*appData.cmailGameName != NULLCHAR) {
3043             signal(SIGUSR1, CmailSigHandler);
3044         }
3045     }
3046         InitPosition(TRUE);
3047
3048     XtAppMainLoop(appContext);
3049     if (appData.debugMode) fclose(debugFP); // [DM] debug
3050     return 0;
3051 }
3052
3053 void
3054 ShutDownFrontEnd()
3055 {
3056     if (appData.icsActive && oldICSInteractionTitle != NULL) {
3057         DisplayIcsInteractionTitle(oldICSInteractionTitle);
3058     }
3059     unlink(gameCopyFilename);
3060     unlink(gamePasteFilename);
3061 }
3062
3063 RETSIGTYPE
3064 IntSigHandler(sig)
3065      int sig;
3066 {
3067     ExitEvent(sig);
3068 }
3069
3070 RETSIGTYPE
3071 CmailSigHandler(sig)
3072      int sig;
3073 {
3074     int dummy = 0;
3075     int error;
3076
3077     signal(SIGUSR1, SIG_IGN);   /* suspend handler     */
3078
3079     /* Activate call-back function CmailSigHandlerCallBack()             */
3080     OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
3081
3082     signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
3083 }
3084
3085 void
3086 CmailSigHandlerCallBack(isr, closure, message, count, error)
3087      InputSourceRef isr;
3088      VOIDSTAR closure;
3089      char *message;
3090      int count;
3091      int error;
3092 {
3093     BoardToTop();
3094     ReloadCmailMsgEvent(TRUE);  /* Reload cmail msg  */
3095 }
3096 /**** end signal code ****/
3097
3098
3099 void
3100 ICSInitScript()
3101 {
3102     FILE *f;
3103     char buf[MSG_SIZ];
3104     char *p;
3105
3106     f = fopen(appData.icsLogon, "r");
3107     if (f == NULL) {
3108         p = getenv("HOME");
3109         if (p != NULL) {
3110             strcpy(buf, p);
3111             strcat(buf, "/");
3112             strcat(buf, appData.icsLogon);
3113             f = fopen(buf, "r");
3114         }
3115     }
3116     if (f != NULL)
3117       ProcessICSInitScript(f);
3118 }
3119
3120 void
3121 ResetFrontEnd()
3122 {
3123     CommentPopDown();
3124     EditCommentPopDown();
3125     TagsPopDown();
3126     return;
3127 }
3128
3129 typedef struct {
3130     char *name;
3131     Boolean value;
3132 } Enables;
3133
3134 void
3135 SetMenuEnables(enab)
3136      Enables *enab;
3137 {
3138   Widget w;
3139   if (!menuBarWidget) return;
3140   while (enab->name != NULL) {
3141     w = XtNameToWidget(menuBarWidget, enab->name);
3142     if (w == NULL) {
3143       DisplayError(enab->name, 0);
3144     } else {
3145       XtSetSensitive(w, enab->value);
3146     }
3147     enab++;
3148   }
3149 }
3150
3151 Enables icsEnables[] = {
3152     { "menuFile.Mail Move", False },
3153     { "menuFile.Reload CMail Message", False },
3154     { "menuMode.Machine Black", False },
3155     { "menuMode.Machine White", False },
3156     { "menuMode.Analysis Mode", False },
3157     { "menuMode.Analyze File", False },
3158     { "menuMode.Two Machines", False },
3159 #ifndef ZIPPY
3160     { "menuHelp.Hint", False },
3161     { "menuHelp.Book", False },
3162     { "menuStep.Move Now", False },
3163     { "menuOptions.Periodic Updates", False },
3164     { "menuOptions.Hide Thinking", False },
3165     { "menuOptions.Ponder Next Move", False },
3166 #endif
3167     { NULL, False }
3168 };
3169
3170 Enables ncpEnables[] = {
3171     { "menuFile.Mail Move", False },
3172     { "menuFile.Reload CMail Message", False },
3173     { "menuMode.Machine White", False },
3174     { "menuMode.Machine Black", False },
3175     { "menuMode.Analysis Mode", False },
3176     { "menuMode.Analyze File", False },
3177     { "menuMode.Two Machines", False },
3178     { "menuMode.ICS Client", False },
3179     { "menuMode.ICS Input Box", False },
3180     { "Action", False },
3181     { "menuStep.Revert", False },
3182     { "menuStep.Move Now", False },
3183     { "menuStep.Retract Move", False },
3184     { "menuOptions.Auto Comment", False },
3185     { "menuOptions.Auto Flag", False },
3186     { "menuOptions.Auto Flip View", False },
3187     { "menuOptions.Auto Observe", False },
3188     { "menuOptions.Auto Raise Board", False },
3189     { "menuOptions.Get Move List", False },
3190     { "menuOptions.ICS Alarm", False },
3191     { "menuOptions.Move Sound", False },
3192     { "menuOptions.Quiet Play", False },
3193     { "menuOptions.Hide Thinking", False },
3194     { "menuOptions.Periodic Updates", False },
3195     { "menuOptions.Ponder Next Move", False },
3196     { "menuHelp.Hint", False },
3197     { "menuHelp.Book", False },
3198     { NULL, False }
3199 };
3200
3201 Enables gnuEnables[] = {
3202     { "menuMode.ICS Client", False },
3203     { "menuMode.ICS Input Box", False },
3204     { "menuAction.Accept", False },
3205     { "menuAction.Decline", False },
3206     { "menuAction.Rematch", False },
3207     { "menuAction.Adjourn", False },
3208     { "menuAction.Stop Examining", False },
3209     { "menuAction.Stop Observing", False },
3210     { "menuStep.Revert", False },
3211     { "menuOptions.Auto Comment", False },
3212     { "menuOptions.Auto Observe", False },
3213     { "menuOptions.Auto Raise Board", False },
3214     { "menuOptions.Get Move List", False },
3215     { "menuOptions.Premove", False },
3216     { "menuOptions.Quiet Play", False },
3217
3218     /* The next two options rely on SetCmailMode being called *after*    */
3219     /* SetGNUMode so that when GNU is being used to give hints these     */
3220     /* menu options are still available                                  */
3221
3222     { "menuFile.Mail Move", False },
3223     { "menuFile.Reload CMail Message", False },
3224     { NULL, False }
3225 };
3226
3227 Enables cmailEnables[] = {
3228     { "Action", True },
3229     { "menuAction.Call Flag", False },
3230     { "menuAction.Draw", True },
3231     { "menuAction.Adjourn", False },
3232     { "menuAction.Abort", False },
3233     { "menuAction.Stop Observing", False },
3234     { "menuAction.Stop Examining", False },
3235     { "menuFile.Mail Move", True },
3236     { "menuFile.Reload CMail Message", True },
3237     { NULL, False }
3238 };
3239
3240 Enables trainingOnEnables[] = {
3241   { "menuMode.Edit Comment", False },
3242   { "menuMode.Pause", False },
3243   { "menuStep.Forward", False },
3244   { "menuStep.Backward", False },
3245   { "menuStep.Forward to End", False },
3246   { "menuStep.Back to Start", False },
3247   { "menuStep.Move Now", False },
3248   { "menuStep.Truncate Game", False },
3249   { NULL, False }
3250 };
3251
3252 Enables trainingOffEnables[] = {
3253   { "menuMode.Edit Comment", True },
3254   { "menuMode.Pause", True },
3255   { "menuStep.Forward", True },
3256   { "menuStep.Backward", True },
3257   { "menuStep.Forward to End", True },
3258   { "menuStep.Back to Start", True },
3259   { "menuStep.Move Now", True },
3260   { "menuStep.Truncate Game", True },
3261   { NULL, False }
3262 };
3263
3264 Enables machineThinkingEnables[] = {
3265   { "menuFile.Load Game", False },
3266   { "menuFile.Load Next Game", False },
3267   { "menuFile.Load Previous Game", False },
3268   { "menuFile.Reload Same Game", False },
3269   { "menuFile.Paste Game", False },
3270   { "menuFile.Load Position", False },
3271   { "menuFile.Load Next Position", False },
3272   { "menuFile.Load Previous Position", False },
3273   { "menuFile.Reload Same Position", False },
3274   { "menuFile.Paste Position", False },
3275   { "menuMode.Machine White", False },
3276   { "menuMode.Machine Black", False },
3277   { "menuMode.Two Machines", False },
3278   { "menuStep.Retract Move", False },
3279   { NULL, False }
3280 };
3281
3282 Enables userThinkingEnables[] = {
3283   { "menuFile.Load Game", True },
3284   { "menuFile.Load Next Game", True },
3285   { "menuFile.Load Previous Game", True },
3286   { "menuFile.Reload Same Game", True },
3287   { "menuFile.Paste Game", True },
3288   { "menuFile.Load Position", True },
3289   { "menuFile.Load Next Position", True },
3290   { "menuFile.Load Previous Position", True },
3291   { "menuFile.Reload Same Position", True },
3292   { "menuFile.Paste Position", True },
3293   { "menuMode.Machine White", True },
3294   { "menuMode.Machine Black", True },
3295   { "menuMode.Two Machines", True },
3296   { "menuStep.Retract Move", True },
3297   { NULL, False }
3298 };
3299
3300 void SetICSMode()
3301 {
3302   SetMenuEnables(icsEnables);
3303
3304 #ifdef ZIPPY
3305   if (appData.zippyPlay && !appData.noChessProgram)   /* [DM] icsEngineAnalyze */
3306      XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
3307 #endif
3308 }
3309
3310 void
3311 SetNCPMode()
3312 {
3313   SetMenuEnables(ncpEnables);
3314 }
3315
3316 void
3317 SetGNUMode()
3318 {
3319   SetMenuEnables(gnuEnables);
3320 }
3321
3322 void
3323 SetCmailMode()
3324 {
3325   SetMenuEnables(cmailEnables);
3326 }
3327
3328 void
3329 SetTrainingModeOn()
3330 {
3331   SetMenuEnables(trainingOnEnables);
3332   if (appData.showButtonBar) {
3333     XtSetSensitive(buttonBarWidget, False);
3334   }
3335   CommentPopDown();
3336 }
3337
3338 void
3339 SetTrainingModeOff()
3340 {
3341   SetMenuEnables(trainingOffEnables);
3342   if (appData.showButtonBar) {
3343     XtSetSensitive(buttonBarWidget, True);
3344   }
3345 }
3346
3347 void
3348 SetUserThinkingEnables()
3349 {
3350   if (appData.noChessProgram) return;
3351   SetMenuEnables(userThinkingEnables);
3352 }
3353
3354 void
3355 SetMachineThinkingEnables()
3356 {
3357   if (appData.noChessProgram) return;
3358   SetMenuEnables(machineThinkingEnables);
3359   switch (gameMode) {
3360   case MachinePlaysBlack:
3361   case MachinePlaysWhite:
3362   case TwoMachinesPlay:
3363     XtSetSensitive(XtNameToWidget(menuBarWidget,
3364                                   ModeToWidgetName(gameMode)), True);
3365     break;
3366   default:
3367     break;
3368   }
3369 }
3370
3371 #define Abs(n) ((n)<0 ? -(n) : (n))
3372
3373 /*
3374  * Find a font that matches "pattern" that is as close as
3375  * possible to the targetPxlSize.  Prefer fonts that are k
3376  * pixels smaller to fonts that are k pixels larger.  The
3377  * pattern must be in the X Consortium standard format,
3378  * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3379  * The return value should be freed with XtFree when no
3380  * longer needed.
3381  */
3382 char *FindFont(pattern, targetPxlSize)
3383      char *pattern;
3384      int targetPxlSize;
3385 {
3386     char **fonts, *p, *best, *scalable, *scalableTail;
3387     int i, j, nfonts, minerr, err, pxlSize;
3388
3389 #ifdef ENABLE_NLS
3390     char **missing_list;
3391     int missing_count;
3392     char *def_string, *base_fnt_lst, strInt[3];
3393     XFontSet fntSet;
3394     XFontStruct **fnt_list;
3395
3396     base_fnt_lst = calloc(1, strlen(pattern) + 3);
3397     sprintf(strInt, "%d", targetPxlSize);
3398     p = strstr(pattern, "--");
3399     strncpy(base_fnt_lst, pattern, p - pattern + 2);
3400     strcat(base_fnt_lst, strInt);
3401     strcat(base_fnt_lst, strchr(p + 2, '-'));
3402
3403     if ((fntSet = XCreateFontSet(xDisplay,
3404                                  base_fnt_lst,
3405                                  &missing_list,
3406                                  &missing_count,
3407                                  &def_string)) == NULL) {
3408
3409        fprintf(stderr, _("Unable to create font set.\n"));
3410        exit (2);
3411     }
3412
3413     nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3414 #else
3415     fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3416     if (nfonts < 1) {
3417         fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3418                 programName, pattern);
3419         exit(2);
3420     }
3421 #endif
3422
3423     best = fonts[0];
3424     scalable = NULL;
3425     minerr = 999999;
3426     for (i=0; i<nfonts; i++) {
3427         j = 0;
3428         p = fonts[i];
3429         if (*p != '-') continue;
3430         while (j < 7) {
3431             if (*p == NULLCHAR) break;
3432             if (*p++ == '-') j++;
3433         }
3434         if (j < 7) continue;
3435         pxlSize = atoi(p);
3436         if (pxlSize == 0) {
3437             scalable = fonts[i];
3438             scalableTail = p;
3439         } else {
3440             err = pxlSize - targetPxlSize;
3441             if (Abs(err) < Abs(minerr) ||
3442                 (minerr > 0 && err < 0 && -err == minerr)) {
3443                 best = fonts[i];
3444                 minerr = err;
3445             }
3446         }
3447     }
3448     if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3449         /* If the error is too big and there is a scalable font,
3450            use the scalable font. */
3451         int headlen = scalableTail - scalable;
3452         p = (char *) XtMalloc(strlen(scalable) + 10);
3453         while (isdigit(*scalableTail)) scalableTail++;
3454         sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3455     } else {
3456         p = (char *) XtMalloc(strlen(best) + 1);
3457         strcpy(p, best);
3458     }
3459     if (appData.debugMode) {
3460         fprintf(debugFP, _("resolved %s at pixel size %d\n  to %s\n"),
3461                 pattern, targetPxlSize, p);
3462     }
3463 #ifdef ENABLE_NLS
3464     if (missing_count > 0)
3465        XFreeStringList(missing_list);
3466     XFreeFontSet(xDisplay, fntSet);
3467 #else
3468      XFreeFontNames(fonts);
3469 #endif
3470     return p;
3471 }
3472
3473 void CreateGCs()
3474 {
3475     XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3476       | GCBackground | GCFunction | GCPlaneMask;
3477     XGCValues gc_values;
3478     GC copyInvertedGC;
3479
3480     gc_values.plane_mask = AllPlanes;
3481     gc_values.line_width = lineGap;
3482     gc_values.line_style = LineSolid;
3483     gc_values.function = GXcopy;
3484
3485     gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3486     gc_values.background = XBlackPixel(xDisplay, xScreen);
3487     lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3488
3489     gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3490     gc_values.background = XWhitePixel(xDisplay, xScreen);
3491     coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3492     XSetFont(xDisplay, coordGC, coordFontID);
3493
3494     // [HGM] make font for holdings counts (white on black0
3495     gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3496     gc_values.background = XBlackPixel(xDisplay, xScreen);
3497     countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3498     XSetFont(xDisplay, countGC, countFontID);
3499
3500     if (appData.monoMode) {
3501         gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3502         gc_values.background = XWhitePixel(xDisplay, xScreen);
3503         highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3504
3505         gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3506         gc_values.background = XBlackPixel(xDisplay, xScreen);
3507         lightSquareGC = wbPieceGC
3508           = XtGetGC(shellWidget, value_mask, &gc_values);
3509
3510         gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3511         gc_values.background = XWhitePixel(xDisplay, xScreen);
3512         darkSquareGC = bwPieceGC
3513           = XtGetGC(shellWidget, value_mask, &gc_values);
3514
3515         if (DefaultDepth(xDisplay, xScreen) == 1) {
3516             /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3517             gc_values.function = GXcopyInverted;
3518             copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3519             gc_values.function = GXcopy;
3520             if (XBlackPixel(xDisplay, xScreen) == 1) {
3521                 bwPieceGC = darkSquareGC;
3522                 wbPieceGC = copyInvertedGC;
3523             } else {
3524                 bwPieceGC = copyInvertedGC;
3525                 wbPieceGC = lightSquareGC;
3526             }
3527         }
3528     } else {
3529         gc_values.foreground = highlightSquareColor;
3530         gc_values.background = highlightSquareColor;
3531         highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3532
3533         gc_values.foreground = premoveHighlightColor;
3534         gc_values.background = premoveHighlightColor;
3535         prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3536
3537         gc_values.foreground = lightSquareColor;
3538         gc_values.background = darkSquareColor;
3539         lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3540
3541         gc_values.foreground = darkSquareColor;
3542         gc_values.background = lightSquareColor;
3543         darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3544
3545         gc_values.foreground = jailSquareColor;
3546         gc_values.background = jailSquareColor;
3547         jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3548
3549         gc_values.foreground = whitePieceColor;
3550         gc_values.background = darkSquareColor;
3551         wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3552
3553         gc_values.foreground = whitePieceColor;
3554         gc_values.background = lightSquareColor;
3555         wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3556
3557         gc_values.foreground = whitePieceColor;
3558         gc_values.background = jailSquareColor;
3559         wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3560
3561         gc_values.foreground = blackPieceColor;
3562         gc_values.background = darkSquareColor;
3563         bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3564
3565         gc_values.foreground = blackPieceColor;
3566         gc_values.background = lightSquareColor;
3567         blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3568
3569         gc_values.foreground = blackPieceColor;
3570         gc_values.background = jailSquareColor;
3571         bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3572     }
3573 }
3574
3575 void loadXIM(xim, xmask, filename, dest, mask)
3576      XImage *xim;
3577      XImage *xmask;
3578      char *filename;
3579      Pixmap *dest;
3580      Pixmap *mask;
3581 {
3582     int x, y, w, h, p;
3583     FILE *fp;
3584     Pixmap temp;
3585     XGCValues   values;
3586     GC maskGC;
3587
3588     fp = fopen(filename, "rb");
3589     if (!fp) {
3590         fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3591         exit(1);
3592     }
3593
3594     w = fgetc(fp);
3595     h = fgetc(fp);
3596
3597     for (y=0; y<h; ++y) {
3598         for (x=0; x<h; ++x) {
3599             p = fgetc(fp);
3600
3601             switch (p) {
3602               case 0:
3603                 XPutPixel(xim, x, y, blackPieceColor);
3604                 if (xmask)
3605                   XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3606                 break;
3607               case 1:
3608                 XPutPixel(xim, x, y, darkSquareColor);
3609                 if (xmask)
3610                   XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3611                 break;
3612               case 2:
3613                 XPutPixel(xim, x, y, whitePieceColor);
3614                 if (xmask)
3615                   XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3616                 break;
3617               case 3:
3618                 XPutPixel(xim, x, y, lightSquareColor);
3619                 if (xmask)
3620                   XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3621                 break;
3622             }
3623         }
3624     }
3625
3626     /* create Pixmap of piece */
3627     *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3628                           w, h, xim->depth);
3629     XPutImage(xDisplay, *dest, lightSquareGC, xim,
3630               0, 0, 0, 0, w, h);
3631
3632     /* create Pixmap of clipmask
3633        Note: We assume the white/black pieces have the same
3634              outline, so we make only 6 masks. This is okay
3635              since the XPM clipmask routines do the same. */
3636     if (xmask) {
3637       temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3638                             w, h, xim->depth);
3639       XPutImage(xDisplay, temp, lightSquareGC, xmask,
3640               0, 0, 0, 0, w, h);
3641
3642       /* now create the 1-bit version */
3643       *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3644                           w, h, 1);
3645
3646       values.foreground = 1;
3647       values.background = 0;
3648
3649       /* Don't use XtGetGC, not read only */
3650       maskGC = XCreateGC(xDisplay, *mask,
3651                     GCForeground | GCBackground, &values);
3652       XCopyPlane(xDisplay, temp, *mask, maskGC,
3653                   0, 0, squareSize, squareSize, 0, 0, 1);
3654       XFreePixmap(xDisplay, temp);
3655     }
3656 }
3657
3658 void CreateXIMPieces()
3659 {
3660     int piece, kind;
3661     char buf[MSG_SIZ];
3662     u_int ss;
3663     static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3664     XImage *ximtemp;
3665
3666     ss = squareSize;
3667
3668     /* The XSynchronize calls were copied from CreatePieces.
3669        Not sure if needed, but can't hurt */
3670     XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3671                                      buffering bug */
3672
3673     /* temp needed by loadXIM() */
3674     ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3675                  0, 0, ss, ss, AllPlanes, XYPixmap);
3676
3677     if (strlen(appData.pixmapDirectory) == 0) {
3678       useImages = 0;
3679     } else {
3680         useImages = 1;
3681         if (appData.monoMode) {
3682           DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3683                             0, 2);
3684           ExitEvent(2);
3685         }
3686         fprintf(stderr, _("\nLoading XIMs...\n"));
3687         /* Load pieces */
3688         for (piece = (int) WhitePawn; piece <= (int) WhiteKing; piece++) {
3689             fprintf(stderr, "%d", piece+1);
3690             for (kind=0; kind<4; kind++) {
3691                 fprintf(stderr, ".");
3692                 sprintf(buf, "%s/%c%s%u.xim",
3693                         ExpandPathName(appData.pixmapDirectory),
3694                         ToLower(PieceToChar((ChessSquare)piece)),
3695                         ximkind[kind], ss);
3696                 ximPieceBitmap[kind][piece] =
3697                   XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3698                             0, 0, ss, ss, AllPlanes, XYPixmap);
3699                 if (appData.debugMode)
3700                   fprintf(stderr, _("(File:%s:) "), buf);
3701                 loadXIM(ximPieceBitmap[kind][piece],
3702                         ximtemp, buf,
3703                         &(xpmPieceBitmap[kind][piece]),
3704                         &(ximMaskPm[piece%(int)BlackPawn]));
3705             }
3706             fprintf(stderr," ");
3707         }
3708         /* Load light and dark squares */
3709         /* If the LSQ and DSQ pieces don't exist, we will
3710            draw them with solid squares. */
3711         sprintf(buf, "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3712         if (access(buf, 0) != 0) {
3713             useImageSqs = 0;
3714         } else {
3715             useImageSqs = 1;
3716             fprintf(stderr, _("light square "));
3717             ximLightSquare=
3718               XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3719                         0, 0, ss, ss, AllPlanes, XYPixmap);
3720             if (appData.debugMode)
3721               fprintf(stderr, _("(File:%s:) "), buf);
3722
3723             loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3724             fprintf(stderr, _("dark square "));
3725             sprintf(buf, "%s/dsq%u.xim",
3726                     ExpandPathName(appData.pixmapDirectory), ss);
3727             if (appData.debugMode)
3728               fprintf(stderr, _("(File:%s:) "), buf);
3729             ximDarkSquare=
3730               XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3731                         0, 0, ss, ss, AllPlanes, XYPixmap);
3732             loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3733             xpmJailSquare = xpmLightSquare;
3734         }
3735         fprintf(stderr, _("Done.\n"));
3736     }
3737     XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3738 }
3739
3740 #if HAVE_LIBXPM
3741 void CreateXPMPieces()
3742 {
3743     int piece, kind, r;
3744     char buf[MSG_SIZ];
3745     u_int ss = squareSize;
3746     XpmAttributes attr;
3747     static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3748     XpmColorSymbol symbols[4];
3749
3750 #if 0
3751     /* Apparently some versions of Xpm don't define XpmFormat at all --tpm */
3752     if (appData.debugMode) {
3753         fprintf(stderr, "XPM Library Version: %d.%d%c\n",
3754                 XpmFormat, XpmVersion, (char)('a' + XpmRevision - 1));
3755     }
3756 #endif
3757
3758     /* The XSynchronize calls were copied from CreatePieces.
3759        Not sure if needed, but can't hurt */
3760     XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3761
3762     /* Setup translations so piece colors match square colors */
3763     symbols[0].name = "light_piece";
3764     symbols[0].value = appData.whitePieceColor;
3765     symbols[1].name = "dark_piece";
3766     symbols[1].value = appData.blackPieceColor;
3767     symbols[2].name = "light_square";
3768     symbols[2].value = appData.lightSquareColor;
3769     symbols[3].name = "dark_square";
3770     symbols[3].value = appData.darkSquareColor;
3771
3772     attr.valuemask = XpmColorSymbols;
3773     attr.colorsymbols = symbols;
3774     attr.numsymbols = 4;
3775
3776     if (appData.monoMode) {
3777       DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3778                         0, 2);
3779       ExitEvent(2);
3780     }
3781     if (strlen(appData.pixmapDirectory) == 0) {
3782         XpmPieces* pieces = builtInXpms;
3783         useImages = 1;
3784         /* Load pieces */
3785         while (pieces->size != squareSize && pieces->size) pieces++;
3786         if (!pieces->size) {
3787           fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3788           exit(1);
3789         }
3790         for (piece = (int) WhitePawn; piece <= (int) WhiteKing; piece++) {
3791             for (kind=0; kind<4; kind++) {
3792
3793                 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3794                                                pieces->xpm[piece][kind],
3795                                                &(xpmPieceBitmap[kind][piece]),
3796                                                NULL, &attr)) != 0) {
3797                   fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3798                           r, buf);
3799                   exit(1);
3800                 }
3801             }
3802         }
3803         useImageSqs = 0;
3804         xpmJailSquare = xpmLightSquare;
3805     } else {
3806         useImages = 1;
3807
3808         fprintf(stderr, _("\nLoading XPMs...\n"));
3809
3810         /* Load pieces */
3811         for (piece = (int) WhitePawn; piece <= (int) WhiteKing; piece++) {
3812             fprintf(stderr, "%d ", piece+1);
3813             for (kind=0; kind<4; kind++) {
3814                 sprintf(buf, "%s/%c%s%u.xpm",
3815                         ExpandPathName(appData.pixmapDirectory),
3816                         ToLower(PieceToChar((ChessSquare)piece)),
3817                         xpmkind[kind], ss);
3818                 if (appData.debugMode) {
3819                     fprintf(stderr, _("(File:%s:) "), buf);
3820                 }
3821                 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3822                                            &(xpmPieceBitmap[kind][piece]),
3823                                            NULL, &attr)) != 0) {
3824                     fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3825                             r, buf);
3826                     exit(1);
3827                 }
3828             }
3829         }
3830         /* Load light and dark squares */
3831         /* If the LSQ and DSQ pieces don't exist, we will
3832            draw them with solid squares. */
3833         fprintf(stderr, _("light square "));
3834         sprintf(buf, "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3835         if (access(buf, 0) != 0) {
3836             useImageSqs = 0;
3837         } else {
3838             useImageSqs = 1;
3839             if (appData.debugMode)
3840               fprintf(stderr, _("(File:%s:) "), buf);
3841
3842             if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3843                                        &xpmLightSquare, NULL, &attr)) != 0) {
3844                 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3845                 exit(1);
3846             }
3847             fprintf(stderr, _("dark square "));
3848             sprintf(buf, "%s/dsq%u.xpm",
3849                     ExpandPathName(appData.pixmapDirectory), ss);
3850             if (appData.debugMode) {
3851                 fprintf(stderr, _("(File:%s:) "), buf);
3852             }
3853             if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3854                                        &xpmDarkSquare, NULL, &attr)) != 0) {
3855                 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3856                 exit(1);
3857             }
3858         }
3859         xpmJailSquare = xpmLightSquare;
3860         fprintf(stderr, _("Done.\n"));
3861     }
3862     XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3863                                       buffering bug */
3864 }
3865 #endif /* HAVE_LIBXPM */
3866
3867 #if HAVE_LIBXPM
3868 /* No built-in bitmaps */
3869 void CreatePieces()
3870 {
3871     int piece, kind;
3872     char buf[MSG_SIZ];
3873     u_int ss = squareSize;
3874
3875     XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3876                                      buffering bug */
3877
3878     for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3879         for (piece = (int) WhitePawn; piece <= (int) WhiteKing; piece++) {
3880             sprintf(buf, "%c%u%c.bm", ToLower(PieceToChar((ChessSquare)piece)),
3881                     ss, kind == SOLID ? 's' : 'o');
3882             ReadBitmap(&pieceBitmap[kind][piece], buf, NULL, ss, ss);
3883         }
3884     }
3885
3886     XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3887                                       buffering bug */
3888 }
3889 #else
3890 /* With built-in bitmaps */
3891 void CreatePieces()
3892 {
3893     BuiltInBits* bib = builtInBits;
3894     int piece, kind;
3895     char buf[MSG_SIZ];
3896     u_int ss = squareSize;
3897
3898     XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3899                                      buffering bug */
3900
3901     while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3902
3903     for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3904         for (piece = (int) WhitePawn; piece <= (int) WhiteKing; piece++) {
3905             sprintf(buf, "%c%u%c.bm", ToLower(PieceToChar((ChessSquare)piece)),
3906                     ss, kind == SOLID ? 's' : 'o');
3907             ReadBitmap(&pieceBitmap[kind][piece], buf,
3908                        bib->bits[kind][piece], ss, ss);
3909         }
3910     }
3911
3912     XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3913                                       buffering bug */
3914 }
3915 #endif
3916
3917 void ReadBitmap(pm, name, bits, wreq, hreq)
3918      Pixmap *pm;
3919      String name;
3920      unsigned char bits[];
3921      u_int wreq, hreq;
3922 {
3923     int x_hot, y_hot;
3924     u_int w, h;
3925     int errcode;
3926     char msg[MSG_SIZ], fullname[MSG_SIZ];
3927
3928     if (*appData.bitmapDirectory != NULLCHAR) {
3929         strcpy(fullname, appData.bitmapDirectory);
3930         strcat(fullname, "/");
3931         strcat(fullname, name);
3932         errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3933                                   &w, &h, pm, &x_hot, &y_hot);
3934         if (errcode != BitmapSuccess) {
3935             switch (errcode) {
3936               case BitmapOpenFailed:
3937                 sprintf(msg, _("Can't open bitmap file %s"), fullname);
3938                 break;
3939               case BitmapFileInvalid:
3940                 sprintf(msg, _("Invalid bitmap in file %s"), fullname);
3941                 break;
3942               case BitmapNoMemory:
3943                 sprintf(msg, _("Ran out of memory reading bitmap file %s"),
3944                         fullname);
3945                 break;
3946               default:
3947                 sprintf(msg, _("Unknown XReadBitmapFile error %d on file %s"),
3948                         errcode, fullname);
3949                 break;
3950             }
3951             fprintf(stderr, _("%s: %s...using built-in\n"),
3952                     programName, msg);
3953         } else if (w != wreq || h != hreq) {
3954             fprintf(stderr,
3955                     _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3956                     programName, fullname, w, h, wreq, hreq);
3957         } else {
3958             return;
3959         }
3960     }
3961     if (bits == NULL) {
3962 #if 0
3963         fprintf(stderr, _("%s: No built-in bitmap for %s; giving up\n"),
3964                 programName, name);
3965         exit(1);
3966 #endif
3967         ; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
3968     } else {
3969         *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3970                                     wreq, hreq);
3971     }
3972 }
3973
3974 void CreateGrid()
3975 {
3976     int i, j;
3977
3978     if (lineGap == 0) return;
3979
3980     /* [HR] Split this into 2 loops for non-square boards. */
3981
3982     for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3983         gridSegments[i].x1 = 0;
3984         gridSegments[i].x2 =
3985           lineGap + BOARD_WIDTH * (squareSize + lineGap);
3986         gridSegments[i].y1 = gridSegments[i].y2
3987           = lineGap / 2 + (i * (squareSize + lineGap));
3988     }
3989
3990     for (j = 0; j < BOARD_WIDTH + 1; j++) {
3991         gridSegments[j + i].y1 = 0;
3992         gridSegments[j + i].y2 =
3993           lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3994         gridSegments[j + i].x1 = gridSegments[j + i].x2
3995           = lineGap / 2 + (j * (squareSize + lineGap));
3996     }
3997 }
3998
3999 static void MenuBarSelect(w, addr, index)
4000      Widget w;
4001      caddr_t addr;
4002      caddr_t index;
4003 {
4004     XtActionProc proc = (XtActionProc) addr;
4005
4006     (proc)(NULL, NULL, NULL, NULL);
4007 }
4008
4009 void CreateMenuBarPopup(parent, name, mb)
4010      Widget parent;
4011      String name;
4012      Menu *mb;
4013 {
4014     int j;
4015     Widget menu, entry;
4016     MenuItem *mi;
4017     Arg args[16];
4018
4019     menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
4020                               parent, NULL, 0);
4021     j = 0;
4022     XtSetArg(args[j], XtNleftMargin, 20);   j++;
4023     XtSetArg(args[j], XtNrightMargin, 20);  j++;
4024     mi = mb->mi;
4025     while (mi->string != NULL) {
4026         if (strcmp(mi->string, "----") == 0) {
4027             entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
4028                                           menu, args, j);
4029         } else {
4030           XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
4031             entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
4032                                           menu, args, j+1);
4033             XtAddCallback(entry, XtNcallback,
4034                           (XtCallbackProc) MenuBarSelect,
4035                           (caddr_t) mi->proc);
4036         }
4037         mi++;
4038     }
4039 }
4040
4041 Widget CreateMenuBar(mb)
4042      Menu *mb;
4043 {
4044     int j;
4045     Widget anchor, menuBar;
4046     Arg args[16];
4047     char menuName[MSG_SIZ];
4048
4049     j = 0;
4050     XtSetArg(args[j], XtNorientation, XtorientHorizontal);  j++;
4051     XtSetArg(args[j], XtNvSpace, 0);                        j++;
4052     XtSetArg(args[j], XtNborderWidth, 0);                   j++;
4053     menuBar = XtCreateWidget("menuBar", boxWidgetClass,
4054                              formWidget, args, j);
4055
4056     while (mb->name != NULL) {
4057         strcpy(menuName, "menu");
4058         strcat(menuName, mb->name);
4059         j = 0;
4060         XtSetArg(args[j], XtNmenuName, XtNewString(menuName));  j++;
4061         if (tinyLayout) {
4062             char shortName[2];
4063             shortName[0] = _(mb->name)[0];
4064             shortName[1] = NULLCHAR;
4065             XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
4066         }
4067       else {
4068           XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
4069       }
4070
4071         XtSetArg(args[j], XtNborderWidth, 0);                   j++;
4072         anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
4073                                        menuBar, args, j);
4074         CreateMenuBarPopup(menuBar, menuName, mb);
4075         mb++;
4076     }
4077     return menuBar;
4078 }
4079
4080 Widget CreateButtonBar(mi)
4081      MenuItem *mi;
4082 {
4083     int j;
4084     Widget button, buttonBar;
4085     Arg args[16];
4086
4087     j = 0;
4088     XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
4089     if (tinyLayout) {
4090         XtSetArg(args[j], XtNhSpace, 0); j++;
4091     }
4092     XtSetArg(args[j], XtNborderWidth, 0); j++;
4093     XtSetArg(args[j], XtNvSpace, 0);                        j++;
4094     buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
4095                                formWidget, args, j);
4096
4097     while (mi->string != NULL) {
4098         j = 0;
4099         if (tinyLayout) {
4100             XtSetArg(args[j], XtNinternalWidth, 2); j++;
4101             XtSetArg(args[j], XtNborderWidth, 0); j++;
4102         }
4103       XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
4104         button = XtCreateManagedWidget(mi->string, commandWidgetClass,
4105                                        buttonBar, args, j);
4106         XtAddCallback(button, XtNcallback,
4107                       (XtCallbackProc) MenuBarSelect,
4108                       (caddr_t) mi->proc);
4109         mi++;
4110     }
4111     return buttonBar;
4112 }
4113
4114 Widget
4115 CreatePieceMenu(name, color)
4116      char *name;
4117      int color;
4118 {
4119     int i;
4120     Widget entry, menu;
4121     Arg args[16];
4122     ChessSquare selection;
4123
4124     menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
4125                               boardWidget, args, 0);
4126
4127     for (i = 0; i < PIECE_MENU_SIZE; i++) {
4128         String item = pieceMenuStrings[color][i];
4129
4130         if (strcmp(item, "----") == 0) {
4131             entry = XtCreateManagedWidget(item, smeLineObjectClass,
4132                                           menu, NULL, 0);
4133         } else {
4134           XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
4135             entry = XtCreateManagedWidget(item, smeBSBObjectClass,
4136                                 menu, args, 1);
4137             selection = pieceMenuTranslation[color][i];
4138             XtAddCallback(entry, XtNcallback,
4139                           (XtCallbackProc) PieceMenuSelect,
4140                           (caddr_t) selection);
4141             if (selection == WhitePawn || selection == BlackPawn) {
4142                 XtSetArg(args[0], XtNpopupOnEntry, entry);
4143                 XtSetValues(menu, args, 1);
4144             }
4145         }
4146     }
4147     return menu;
4148 }
4149
4150 void
4151 CreatePieceMenus()
4152 {
4153     int i;
4154     Widget entry;
4155     Arg args[16];
4156     ChessSquare selection;
4157
4158     whitePieceMenu = CreatePieceMenu("menuW", 0);
4159     blackPieceMenu = CreatePieceMenu("menuB", 1);
4160
4161     XtRegisterGrabAction(PieceMenuPopup, True,
4162                          (unsigned)(ButtonPressMask|ButtonReleaseMask),
4163                          GrabModeAsync, GrabModeAsync);
4164
4165     XtSetArg(args[0], XtNlabel, _("Drop"));
4166     dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
4167                                   boardWidget, args, 1);
4168     for (i = 0; i < DROP_MENU_SIZE; i++) {
4169         String item = dropMenuStrings[i];
4170
4171         if (strcmp(item, "----") == 0) {
4172             entry = XtCreateManagedWidget(item, smeLineObjectClass,
4173                                           dropMenu, NULL, 0);
4174         } else {
4175           XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
4176             entry = XtCreateManagedWidget(item, smeBSBObjectClass,
4177                                 dropMenu, args, 1);
4178             selection = dropMenuTranslation[i];
4179             XtAddCallback(entry, XtNcallback,
4180                           (XtCallbackProc) DropMenuSelect,
4181                           (caddr_t) selection);
4182         }
4183     }
4184 }
4185
4186 void SetupDropMenu()
4187 {
4188     int i, j, count;
4189     char label[32];
4190     Arg args[16];
4191     Widget entry;
4192     char* p;
4193
4194     for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
4195         entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
4196         p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
4197                    dmEnables[i].piece);
4198         XtSetSensitive(entry, p != NULL || !appData.testLegality
4199                        /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
4200                                        && !appData.icsActive));
4201         count = 0;
4202         while (p && *p++ == dmEnables[i].piece) count++;
4203         sprintf(label, "%s  %d", dmEnables[i].widget, count);
4204         j = 0;
4205         XtSetArg(args[j], XtNlabel, label); j++;
4206         XtSetValues(entry, args, j);
4207     }
4208 }
4209
4210 void PieceMenuPopup(w, event, params, num_params)
4211      Widget w;
4212      XEvent *event;
4213      String *params;
4214      Cardinal *num_params;
4215 {
4216     String whichMenu;
4217     if (event->type != ButtonPress) return;
4218     if (errorUp) ErrorPopDown();
4219     switch (gameMode) {
4220       case EditPosition:
4221       case IcsExamining:
4222         whichMenu = params[0];
4223         break;
4224       case IcsPlayingWhite:
4225       case IcsPlayingBlack:
4226       case EditGame:
4227       case MachinePlaysWhite:
4228       case MachinePlaysBlack:
4229         if (appData.testLegality &&
4230             gameInfo.variant != VariantBughouse &&
4231             gameInfo.variant != VariantCrazyhouse) return;
4232         SetupDropMenu();
4233         whichMenu = "menuD";
4234         break;
4235       default:
4236         return;
4237     }
4238
4239     if (((pmFromX = EventToSquare(event->xbutton.x, BOARD_WIDTH)) < 0) ||
4240         ((pmFromY = EventToSquare(event->xbutton.y, BOARD_HEIGHT)) < 0)) {
4241         pmFromX = pmFromY = -1;
4242         return;
4243     }
4244     if (flipView)
4245       pmFromX = BOARD_WIDTH - 1 - pmFromX;
4246     else
4247       pmFromY = BOARD_HEIGHT - 1 - pmFromY;
4248
4249     XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
4250 }
4251
4252 static void PieceMenuSelect(w, piece, junk)
4253      Widget w;
4254      ChessSquare piece;
4255      caddr_t junk;
4256 {
4257     if (pmFromX < 0 || pmFromY < 0) return;
4258     EditPositionMenuEvent(piece, pmFromX, pmFromY);
4259 }
4260
4261 static void DropMenuSelect(w, piece, junk)
4262      Widget w;
4263      ChessSquare piece;
4264      caddr_t junk;
4265 {
4266     if (pmFromX < 0 || pmFromY < 0) return;
4267     DropMenuEvent(piece, pmFromX, pmFromY);
4268 }
4269
4270 void WhiteClock(w, event, prms, nprms)
4271      Widget w;
4272      XEvent *event;
4273      String *prms;
4274      Cardinal *nprms;
4275 {
4276     if (gameMode == EditPosition || gameMode == IcsExamining) {
4277         SetWhiteToPlayEvent();
4278     } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
4279         CallFlagEvent();
4280     }
4281 }
4282
4283 void BlackClock(w, event, prms, nprms)
4284      Widget w;
4285      XEvent *event;
4286      String *prms;
4287      Cardinal *nprms;
4288 {
4289     if (gameMode == EditPosition || gameMode == IcsExamining) {
4290         SetBlackToPlayEvent();
4291     } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
4292         CallFlagEvent();
4293     }
4294 }
4295
4296
4297 /*
4298  * If the user selects on a border boundary, return -1; if off the board,
4299  *   return -2.  Otherwise map the event coordinate to the square.
4300  */
4301 int EventToSquare(x, limit)
4302      int x;
4303 {
4304     if (x <= 0)
4305       return -2;
4306     if (x < lineGap)
4307       return -1;
4308     x -= lineGap;
4309     if ((x % (squareSize + lineGap)) >= squareSize)
4310       return -1;
4311     x /= (squareSize + lineGap);
4312     if (x >= limit)
4313       return -2;
4314     return x;
4315 }
4316
4317 static void do_flash_delay(msec)
4318      unsigned long msec;
4319 {
4320     TimeDelay(msec);
4321 }
4322
4323 static void drawHighlight(file, rank, gc)
4324      int file, rank;
4325      GC gc;
4326 {
4327     int x, y;
4328
4329     if (lineGap == 0 || appData.blindfold) return;
4330
4331     if (flipView) {
4332         x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
4333           (squareSize + lineGap);
4334         y = lineGap/2 + rank * (squareSize + lineGap);
4335     } else {
4336         x = lineGap/2 + file * (squareSize + lineGap);
4337         y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
4338           (squareSize + lineGap);
4339     }
4340
4341     XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
4342                    squareSize+lineGap, squareSize+lineGap);
4343 }
4344
4345 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
4346 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4347
4348 void
4349 SetHighlights(fromX, fromY, toX, toY)
4350      int fromX, fromY, toX, toY;
4351 {
4352     if (hi1X != fromX || hi1Y != fromY) {
4353         if (hi1X >= 0 && hi1Y >= 0) {
4354             drawHighlight(hi1X, hi1Y, lineGC);
4355         }
4356         if (fromX >= 0 && fromY >= 0) {
4357             drawHighlight(fromX, fromY, highlineGC);
4358         }
4359     }
4360     if (hi2X != toX || hi2Y != toY) {
4361         if (hi2X >= 0 && hi2Y >= 0) {
4362             drawHighlight(hi2X, hi2Y, lineGC);
4363         }
4364         if (toX >= 0 && toY >= 0) {
4365             drawHighlight(toX, toY, highlineGC);
4366         }
4367     }
4368     hi1X = fromX;
4369     hi1Y = fromY;
4370     hi2X = toX;
4371     hi2Y = toY;
4372 }
4373
4374 void
4375 ClearHighlights()
4376 {
4377     SetHighlights(-1, -1, -1, -1);
4378 }
4379
4380
4381 void
4382 SetPremoveHighlights(fromX, fromY, toX, toY)
4383      int fromX, fromY, toX, toY;
4384 {
4385     if (pm1X != fromX || pm1Y != fromY) {
4386         if (pm1X >= 0 && pm1Y >= 0) {
4387             drawHighlight(pm1X, pm1Y, lineGC);
4388         }
4389         if (fromX >= 0 && fromY >= 0) {
4390             drawHighlight(fromX, fromY, prelineGC);
4391         }
4392     }
4393     if (pm2X != toX || pm2Y != toY) {
4394         if (pm2X >= 0 && pm2Y >= 0) {
4395             drawHighlight(pm2X, pm2Y, lineGC);
4396         }
4397         if (toX >= 0 && toY >= 0) {
4398             drawHighlight(toX, toY, prelineGC);
4399         }
4400     }
4401     pm1X = fromX;
4402     pm1Y = fromY;
4403     pm2X = toX;
4404     pm2Y = toY;
4405 }
4406
4407 void
4408 ClearPremoveHighlights()
4409 {
4410   SetPremoveHighlights(-1, -1, -1, -1);
4411 }
4412
4413 static void BlankSquare(x, y, color, piece, dest)
4414      int x, y, color;
4415      ChessSquare piece;
4416      Drawable dest;
4417 {
4418     if (useImages && useImageSqs) {
4419         Pixmap pm;
4420         switch (color) {
4421           case 1: /* light */
4422             pm = xpmLightSquare;
4423             break;
4424           case 0: /* dark */
4425             pm = xpmDarkSquare;
4426             break;
4427           case 2: /* neutral */
4428           default:
4429             pm = xpmJailSquare;
4430             break;
4431         }
4432         XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4433                   squareSize, squareSize, x, y);
4434     } else {
4435         GC gc;
4436         switch (color) {
4437           case 1: /* light */
4438             gc = lightSquareGC;
4439             break;
4440           case 0: /* dark */
4441             gc = darkSquareGC;
4442             break;
4443           case 2: /* neutral */
4444           default:
4445             gc = jailSquareGC;
4446             break;
4447         }
4448         XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
4449     }
4450 }
4451
4452 /*
4453    I split out the routines to draw a piece so that I could
4454    make a generic flash routine.
4455 */
4456 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4457      ChessSquare piece;
4458      int square_color, x, y;
4459      Drawable dest;
4460 {
4461     /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4462     switch (square_color) {
4463       case 1: /* light */
4464       case 2: /* neutral */
4465       default:
4466         XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4467                   ? *pieceToOutline(piece)
4468                   : *pieceToSolid(piece),
4469                   dest, bwPieceGC, 0, 0,
4470                   squareSize, squareSize, x, y);
4471         break;
4472       case 0: /* dark */
4473         XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4474                   ? *pieceToSolid(piece)
4475                   : *pieceToOutline(piece),
4476                   dest, wbPieceGC, 0, 0,
4477                   squareSize, squareSize, x, y);
4478         break;
4479     }
4480 }
4481
4482 static void monoDrawPiece(piece, square_color, x, y, dest)
4483      ChessSquare piece;
4484      int square_color, x, y;
4485      Drawable dest;
4486 {
4487     switch (square_color) {
4488       case 1: /* light */
4489       case 2: /* neutral */
4490       default:
4491         XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4492                    ? *pieceToOutline(piece)
4493                    : *pieceToSolid(piece),
4494                    dest, bwPieceGC, 0, 0,
4495                    squareSize, squareSize, x, y, 1);
4496         break;
4497       case 0: /* dark */
4498         XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4499                    ? *pieceToSolid(piece)
4500                    : *pieceToOutline(piece),
4501                    dest, wbPieceGC, 0, 0,
4502                    squareSize, squareSize, x, y, 1);
4503         break;
4504     }
4505 }
4506
4507 static void colorDrawPiece(piece, square_color, x, y, dest)
4508      ChessSquare piece;
4509      int square_color, x, y;
4510      Drawable dest;
4511 {
4512     if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4513     switch (square_color) {
4514       case 1: /* light */
4515         XCopyPlane(xDisplay, *pieceToSolid(piece),
4516                    dest, (int) piece < (int) BlackPawn
4517                    ? wlPieceGC : blPieceGC, 0, 0,
4518                    squareSize, squareSize, x, y, 1);
4519         break;
4520       case 0: /* dark */
4521         XCopyPlane(xDisplay, *pieceToSolid(piece),
4522                    dest, (int) piece < (int) BlackPawn
4523                    ? wdPieceGC : bdPieceGC, 0, 0,
4524                    squareSize, squareSize, x, y, 1);
4525         break;
4526       case 2: /* neutral */
4527       default:
4528         XCopyPlane(xDisplay, *pieceToSolid(piece),
4529                    dest, (int) piece < (int) BlackPawn
4530                    ? wjPieceGC : bjPieceGC, 0, 0,
4531                    squareSize, squareSize, x, y, 1);
4532         break;
4533     }
4534 }
4535
4536 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4537      ChessSquare piece;
4538      int square_color, x, y;
4539      Drawable dest;
4540 {
4541     int kind;
4542
4543     switch (square_color) {
4544       case 1: /* light */
4545       case 2: /* neutral */
4546       default:
4547         if ((int)piece < (int) BlackPawn) {
4548             kind = 0;
4549         } else {
4550             kind = 2;
4551             piece -= BlackPawn;
4552         }
4553         break;
4554       case 0: /* dark */
4555         if ((int)piece < (int) BlackPawn) {
4556             kind = 1;
4557         } else {
4558             kind = 3;
4559             piece -= BlackPawn;
4560         }
4561         break;
4562     }
4563     XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4564               dest, wlPieceGC, 0, 0,
4565               squareSize, squareSize, x, y);
4566 }
4567
4568 typedef void (*DrawFunc)();
4569
4570 DrawFunc ChooseDrawFunc()
4571 {
4572     if (appData.monoMode) {
4573         if (DefaultDepth(xDisplay, xScreen) == 1) {
4574             return monoDrawPiece_1bit;
4575         } else {
4576             return monoDrawPiece;
4577         }
4578     } else {
4579         if (useImages)
4580           return colorDrawPieceImage;
4581         else
4582           return colorDrawPiece;
4583     }
4584 }
4585
4586 /* [HR] determine square color depending on chess variant. */
4587 static int SquareColor(row, column)
4588      int row, column;
4589 {
4590     int square_color;
4591
4592     if (gameInfo.variant == VariantXiangqi) {
4593         if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4594             square_color = 1;
4595         } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4596             square_color = 0;
4597         } else if (row <= 4) {
4598             square_color = 0;
4599         } else {
4600             square_color = 1;
4601         }
4602     } else {
4603         square_color = ((column + row) % 2) == 1;
4604     }
4605
4606     /* [hgm] holdings: next line makes all holdings squares light */
4607     if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4608
4609     return square_color;
4610 }
4611
4612 void DrawSquare(row, column, piece, do_flash)
4613      int row, column, do_flash;
4614      ChessSquare piece;
4615 {
4616     int square_color, x, y, direction, font_ascent, font_descent;
4617     int i;
4618     char string[2];
4619     XCharStruct overall;
4620     DrawFunc drawfunc;
4621     int flash_delay;
4622
4623     if(gameInfo.variant == VariantShogi) { // [HGM] shogi: in shogi Q is used for Lance
4624         if(piece == WhiteQueen) piece = WhiteLance; else
4625         if(piece == BlackQueen) piece = BlackLance;
4626     }
4627 #ifdef GOTHIC
4628     else if(gameInfo.variant == VariantGothic) { // [HGM] shogi: in Gothic Chancelor has alternative look
4629         if(piece == WhiteMarshall) piece = WhiteSilver; else
4630         if(piece == BlackMarshall) piece = BlackSilver;
4631     }
4632 #endif
4633
4634     /* Calculate delay in milliseconds (2-delays per complete flash) */
4635     flash_delay = 500 / appData.flashRate;
4636
4637     if (flipView) {
4638         x = lineGap + ((BOARD_WIDTH-1)-column) *
4639           (squareSize + lineGap);
4640         y = lineGap + row * (squareSize + lineGap);
4641     } else {
4642         x = lineGap + column * (squareSize + lineGap);
4643         y = lineGap + ((BOARD_HEIGHT-1)-row) *
4644           (squareSize + lineGap);
4645     }
4646
4647     square_color = SquareColor(row, column);
4648
4649     if ( // [HGM] holdings: blank out area between board and holdings
4650                  column == BOARD_LEFT-1 ||  column == BOARD_RGHT
4651               || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4652                   || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4653                         BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4654
4655                         // [HGM] print piece counts next to holdings
4656                         string[1] = NULLCHAR;
4657                         if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4658                             string[0] = '0' + piece;
4659                             XTextExtents(countFontStruct, string, 1, &direction,
4660                                  &font_ascent, &font_descent, &overall);
4661                             if (appData.monoMode) {
4662                                 XDrawImageString(xDisplay, xBoardWindow, countGC,
4663                                                  x + squareSize - overall.width - 2,
4664                                                  y + font_ascent + 1, string, 1);
4665                             } else {
4666                                 XDrawString(xDisplay, xBoardWindow, countGC,
4667                                             x + squareSize - overall.width - 2,
4668                                             y + font_ascent + 1, string, 1);
4669                             }
4670                         }
4671                         if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4672                             string[0] = '0' + piece;
4673                             XTextExtents(countFontStruct, string, 1, &direction,
4674                                          &font_ascent, &font_descent, &overall);
4675                             if (appData.monoMode) {
4676                                 XDrawImageString(xDisplay, xBoardWindow, countGC,
4677                                                  x + 2, y + font_ascent + 1, string, 1);
4678                             } else {
4679                                 XDrawString(xDisplay, xBoardWindow, countGC,
4680                                             x + 2, y + font_ascent + 1, string, 1);
4681                             }
4682                         }
4683     } else {
4684             if (piece == EmptySquare || appData.blindfold) {
4685                         BlankSquare(x, y, square_color, piece, xBoardWindow);
4686             } else {
4687                         drawfunc = ChooseDrawFunc();
4688                         if (do_flash && appData.flashCount > 0) {
4689                             for (i=0; i<appData.flashCount; ++i) {
4690
4691                                         drawfunc(piece, square_color, x, y, xBoardWindow);
4692                                         XSync(xDisplay, False);
4693                                         do_flash_delay(flash_delay);
4694
4695                                         BlankSquare(x, y, square_color, piece, xBoardWindow);
4696                                         XSync(xDisplay, False);
4697                                         do_flash_delay(flash_delay);
4698                             }
4699                         }
4700                         drawfunc(piece, square_color, x, y, xBoardWindow);
4701         }
4702         }
4703
4704     string[1] = NULLCHAR;
4705     if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4706                 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4707         string[0] = 'a' + column - BOARD_LEFT;
4708         XTextExtents(coordFontStruct, string, 1, &direction,
4709                      &font_ascent, &font_descent, &overall);
4710         if (appData.monoMode) {
4711             XDrawImageString(xDisplay, xBoardWindow, coordGC,
4712                              x + squareSize - overall.width - 2,
4713                              y + squareSize - font_descent - 1, string, 1);
4714         } else {
4715             XDrawString(xDisplay, xBoardWindow, coordGC,
4716                         x + squareSize - overall.width - 2,
4717                         y + squareSize - font_descent - 1, string, 1);
4718         }
4719     }
4720     if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4721         string[0] = ONE + row;
4722         XTextExtents(coordFontStruct, string, 1, &direction,
4723                      &font_ascent, &font_descent, &overall);
4724         if (appData.monoMode) {
4725             XDrawImageString(xDisplay, xBoardWindow, coordGC,
4726                              x + 2, y + font_ascent + 1, string, 1);
4727         } else {
4728             XDrawString(xDisplay, xBoardWindow, coordGC,
4729                         x + 2, y + font_ascent + 1, string, 1);
4730         }
4731     }
4732 }
4733
4734
4735 /* Why is this needed on some versions of X? */
4736 void EventProc(widget, unused, event)
4737      Widget widget;
4738      caddr_t unused;
4739      XEvent *event;
4740 {
4741     if (!XtIsRealized(widget))
4742       return;
4743
4744     switch (event->type) {
4745       case Expose:
4746         if (event->xexpose.count > 0) return;  /* no clipping is done */
4747         XDrawPosition(widget, True, NULL);
4748         break;
4749       default:
4750         return;
4751     }
4752 }
4753 /* end why */
4754
4755 void DrawPosition(fullRedraw, board)
4756      /*Boolean*/int fullRedraw;
4757      Board board;
4758 {
4759     XDrawPosition(boardWidget, fullRedraw, board);
4760 }
4761
4762 /* Returns 1 if there are "too many" differences between b1 and b2
4763    (i.e. more than 1 move was made) */
4764 static int too_many_diffs(b1, b2)
4765      Board b1, b2;
4766 {
4767     int i, j;
4768     int c = 0;
4769
4770     for (i=0; i<BOARD_HEIGHT; ++i) {
4771         for (j=0; j<BOARD_WIDTH; ++j) {
4772             if (b1[i][j] != b2[i][j]) {
4773                 if (++c > 4)    /* Castling causes 4 diffs */
4774                   return 1;
4775             }
4776         }
4777     }
4778
4779     return 0;
4780 }
4781
4782 /* Matrix describing castling maneuvers */
4783 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4784 static int castling_matrix[4][5] = {
4785     { 0, 0, 4, 3, 2 },          /* 0-0-0, white */
4786     { 0, 7, 4, 5, 6 },          /* 0-0,   white */
4787     { 7, 0, 4, 3, 2 },          /* 0-0-0, black */
4788     { 7, 7, 4, 5, 6 }           /* 0-0,   black */
4789 };
4790
4791 /* Checks whether castling occurred. If it did, *rrow and *rcol
4792    are set to the destination (row,col) of the rook that moved.
4793
4794    Returns 1 if castling occurred, 0 if not.
4795
4796    Note: Only handles a max of 1 castling move, so be sure
4797    to call too_many_diffs() first.
4798    */
4799 static int check_castle_draw(newb, oldb, rrow, rcol)
4800      Board newb, oldb;
4801      int *rrow, *rcol;
4802 {
4803     int i, *r, j;
4804     int match;
4805
4806     /* For each type of castling... */
4807     for (i=0; i<4; ++i) {
4808         r = castling_matrix[i];
4809
4810         /* Check the 4 squares involved in the castling move */
4811         match = 0;
4812         for (j=1; j<=4; ++j) {
4813             if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4814                 match = 1;
4815                 break;
4816             }
4817         }
4818
4819         if (!match) {
4820             /* All 4 changed, so it must be a castling move */
4821             *rrow = r[0];
4822             *rcol = r[3];
4823             return 1;
4824         }
4825     }
4826     return 0;
4827 }
4828
4829 static int damage[BOARD_SIZE][BOARD_SIZE];
4830
4831 /*
4832  * event handler for redrawing the board
4833  */
4834 void XDrawPosition(w, repaint, board)
4835      Widget w;
4836      /*Boolean*/int repaint;
4837      Board board;
4838 {
4839     int i, j, do_flash;
4840     static int lastFlipView = 0;
4841     static int lastBoardValid = 0;
4842     static Board lastBoard;
4843     Arg args[16];
4844     int rrow, rcol;
4845
4846     if (board == NULL) {
4847         if (!lastBoardValid) return;
4848         board = lastBoard;
4849     }
4850     if (!lastBoardValid || lastFlipView != flipView) {
4851         XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4852         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4853                     args, 1);
4854     }
4855
4856     /*
4857      * It would be simpler to clear the window with XClearWindow()
4858      * but this causes a very distracting flicker.
4859      */
4860
4861     if (!repaint && lastBoardValid && lastFlipView == flipView) {
4862
4863         /* If too much changes (begin observing new game, etc.), don't
4864            do flashing */
4865         do_flash = too_many_diffs(board, lastBoard) ? 0 : 1;
4866
4867         /* Special check for castling so we don't flash both the king
4868            and the rook (just flash the king). */
4869         if (do_flash) {
4870             if (check_castle_draw(board, lastBoard, &rrow, &rcol)) {
4871                 /* Draw rook with NO flashing. King will be drawn flashing later */
4872                 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4873                 lastBoard[rrow][rcol] = board[rrow][rcol];
4874             }
4875         }
4876
4877         /* First pass -- Draw (newly) empty squares and repair damage.
4878            This prevents you from having a piece show up twice while it
4879            is flashing on its new square */
4880         for (i = 0; i < BOARD_HEIGHT; i++)
4881           for (j = 0; j < BOARD_WIDTH; j++)
4882             if ((board[i][j] != lastBoard[i][j] && board[i][j] == EmptySquare)
4883                 || damage[i][j]) {
4884                 DrawSquare(i, j, board[i][j], 0);
4885                 damage[i][j] = False;
4886             }
4887
4888         /* Second pass -- Draw piece(s) in new position and flash them */
4889         for (i = 0; i < BOARD_HEIGHT; i++)
4890           for (j = 0; j < BOARD_WIDTH; j++)
4891             if (board[i][j] != lastBoard[i][j]) {
4892                 DrawSquare(i, j, board[i][j], do_flash);
4893             }
4894     } else {
4895         if (lineGap > 0)
4896           XDrawSegments(xDisplay, xBoardWindow, lineGC,
4897                         gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4898
4899         for (i = 0; i < BOARD_HEIGHT; i++)
4900           for (j = 0; j < BOARD_WIDTH; j++) {
4901               DrawSquare(i, j, board[i][j], 0);
4902               damage[i][j] = False;
4903           }
4904     }
4905
4906     CopyBoard(lastBoard, board);
4907     lastBoardValid = 1;
4908     lastFlipView = flipView;
4909
4910     /* Draw highlights */
4911     if (pm1X >= 0 && pm1Y >= 0) {
4912       drawHighlight(pm1X, pm1Y, prelineGC);
4913     }
4914     if (pm2X >= 0 && pm2Y >= 0) {
4915       drawHighlight(pm2X, pm2Y, prelineGC);
4916     }
4917     if (hi1X >= 0 && hi1Y >= 0) {
4918       drawHighlight(hi1X, hi1Y, highlineGC);
4919     }
4920     if (hi2X >= 0 && hi2Y >= 0) {
4921       drawHighlight(hi2X, hi2Y, highlineGC);
4922     }
4923
4924     /* If piece being dragged around board, must redraw that too */
4925     DrawDragPiece();
4926
4927     XSync(xDisplay, False);
4928 }
4929
4930
4931 /*
4932  * event handler for redrawing the board
4933  */
4934 void DrawPositionProc(w, event, prms, nprms)
4935      Widget w;
4936      XEvent *event;
4937      String *prms;
4938      Cardinal *nprms;
4939 {
4940     XDrawPosition(w, True, NULL);
4941 }
4942
4943
4944 /*
4945  * event handler for parsing user moves
4946  */
4947 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4948 //       way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4949 //       it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4950 //       should be made to use the new way, of calling UserMoveTest early  to determine the legality of the
4951 //       move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4952 //       and at the end FinishMove() to perform the move after optional promotion popups.
4953 //       For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4954 void HandleUserMove(w, event, prms, nprms)
4955      Widget w;
4956      XEvent *event;
4957      String *prms;
4958      Cardinal *nprms;
4959 {
4960     int x, y;
4961     Boolean saveAnimate;
4962     static int second = 0;
4963
4964     if (w != boardWidget || errorExitStatus != -1) return;
4965
4966     if (event->type == ButtonPress) ErrorPopDown();
4967
4968     if (promotionUp) {
4969         if (event->type == ButtonPress) {
4970             XtPopdown(promotionShell);
4971             XtDestroyWidget(promotionShell);
4972             promotionUp = False;
4973             ClearHighlights();
4974             fromX = fromY = -1;
4975         } else {
4976             return;
4977         }
4978     }
4979
4980     x = EventToSquare(event->xbutton.x, BOARD_WIDTH);
4981     y = EventToSquare(event->xbutton.y, BOARD_HEIGHT);
4982     if (!flipView && y >= 0) {
4983         y = BOARD_HEIGHT - 1 - y;
4984     }
4985     if (flipView && x >= 0) {
4986         x = BOARD_WIDTH - 1 - x;
4987     }
4988
4989     /* [HGM] holdings: next 5 lines: ignore all clicks between board and holdings */
4990     if(event->type == ButtonPress
4991             && ( x == BOARD_LEFT-1 || x == BOARD_RGHT
4992               || x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize
4993               || x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize) )
4994         return;
4995
4996     if (fromX == -1) {
4997         if (event->type == ButtonPress) {
4998             /* First square */
4999             if (OKToStartUserMove(x, y)) {
5000                 fromX = x;
5001                 fromY = y;
5002                 second = 0;
5003                 DragPieceBegin(event->xbutton.x, event->xbutton.y);
5004                 if (appData.highlightDragging) {
5005                     SetHighlights(x, y, -1, -1);
5006                 }
5007             }
5008         }
5009         return;
5010     }
5011
5012     /* fromX != -1 */
5013     if (event->type == ButtonPress && gameMode != EditPosition &&
5014         x >= 0 && y >= 0) {
5015         ChessSquare fromP;
5016         ChessSquare toP;
5017
5018         /* Check if clicking again on the same color piece */
5019         fromP = boards[currentMove][fromY][fromX];
5020         toP = boards[currentMove][y][x];
5021         if ((WhitePawn <= fromP && fromP < WhiteKing && // [HGM] this test should go, as UserMoveTest now does it.
5022              WhitePawn <= toP && toP <= WhiteKing) ||   //       For now I made it less critical by exempting King
5023             (BlackPawn <= fromP && fromP < BlackKing && //       moves, to not interfere with FRC castlings.
5024              BlackPawn <= toP && toP <= BlackKing)) {
5025             /* Clicked again on same color piece -- changed his mind */
5026             second = (x == fromX && y == fromY);
5027             if (appData.highlightDragging) {
5028                 SetHighlights(x, y, -1, -1);
5029             } else {
5030                 ClearHighlights();
5031             }
5032             if (OKToStartUserMove(x, y)) {
5033                 fromX = x;
5034                 fromY = y;
5035                 DragPieceBegin(event->xbutton.x, event->xbutton.y);
5036             }
5037             return;
5038         }
5039     }
5040
5041     if (event->type == ButtonRelease && x == fromX && y == fromY) {
5042         DragPieceEnd(event->xbutton.x, event->xbutton.y);
5043         if (appData.animateDragging) {
5044             /* Undo animation damage if any */
5045             DrawPosition(FALSE, NULL);
5046         }
5047         if (second) {
5048             /* Second up/down in same square; just abort move */
5049             second = 0;
5050             fromX = fromY = -1;
5051             ClearHighlights();
5052             gotPremove = 0;
5053             ClearPremoveHighlights();
5054         } else {
5055             /* First upclick in same square; start click-click mode */
5056             SetHighlights(x, y, -1, -1);
5057         }
5058         return;
5059     }
5060
5061     /* Completed move */
5062     toX = x;
5063     toY = y;
5064     saveAnimate = appData.animate;
5065     if (event->type == ButtonPress) {
5066         /* Finish clickclick move */
5067         if (appData.animate || appData.highlightLastMove) {
5068             SetHighlights(fromX, fromY, toX, toY);
5069         } else {
5070             ClearHighlights();
5071         }
5072     } else {
5073         /* Finish drag move */
5074         if (appData.highlightLastMove) {
5075             SetHighlights(fromX, fromY, toX, toY);
5076         } else {
5077             ClearHighlights();
5078         }
5079         DragPieceEnd(event->xbutton.x, event->xbutton.y);
5080         /* Don't animate move and drag both */
5081         appData.animate = FALSE;
5082     }
5083     if (IsPromotion(fromX, fromY, toX, toY)) {
5084         if (appData.alwaysPromoteToQueen) {
5085             UserMoveEvent(fromX, fromY, toX, toY, 'q');
5086             if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5087             if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5088             fromX = fromY = -1;
5089         } else {
5090             SetHighlights(fromX, fromY, toX, toY);
5091             PromotionPopUp();
5092         }
5093     } else {
5094         UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR);
5095         if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5096         if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5097         fromX = fromY = -1;
5098     }
5099     appData.animate = saveAnimate;
5100     if (appData.animate || appData.animateDragging) {
5101         /* Undo animation damage if needed */
5102         DrawPosition(FALSE, NULL);
5103     }
5104 }
5105
5106 void AnimateUserMove (Widget w, XEvent * event,
5107                       String * params, Cardinal * nParams)
5108 {
5109     DragPieceMove(event->xmotion.x, event->xmotion.y);
5110 }
5111
5112 Widget CommentCreate(name, text, mutable, callback, lines)
5113      char *name, *text;
5114      int /*Boolean*/ mutable;
5115      XtCallbackProc callback;
5116      int lines;
5117 {
5118     Arg args[16];
5119     Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
5120     Dimension bw_width;
5121     int j;
5122
5123     j = 0;
5124     XtSetArg(args[j], XtNwidth, &bw_width);  j++;
5125     XtGetValues(boardWidget, args, j);
5126
5127     j = 0;
5128     XtSetArg(args[j], XtNresizable, True);  j++;
5129 #if TOPLEVEL
5130     shell =
5131       XtCreatePopupShell(name, topLevelShellWidgetClass,
5132                          shellWidget, args, j);
5133 #else
5134     shell =
5135       XtCreatePopupShell(name, transientShellWidgetClass,
5136                          shellWidget, args, j);
5137 #endif
5138     layout =
5139       XtCreateManagedWidget(layoutName, formWidgetClass, shell,
5140                             layoutArgs, XtNumber(layoutArgs));
5141     form =
5142       XtCreateManagedWidget("form", formWidgetClass, layout,
5143                             formArgs, XtNumber(formArgs));
5144
5145     j = 0;
5146     if (mutable) {
5147         XtSetArg(args[j], XtNeditType, XawtextEdit);  j++;
5148         XtSetArg(args[j], XtNuseStringInPlace, False);  j++;
5149     }
5150     XtSetArg(args[j], XtNstring, text);  j++;
5151     XtSetArg(args[j], XtNtop, XtChainTop);  j++;
5152     XtSetArg(args[j], XtNbottom, XtChainBottom);  j++;
5153     XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
5154     XtSetArg(args[j], XtNright, XtChainRight);  j++;
5155     XtSetArg(args[j], XtNresizable, True);  j++;
5156     XtSetArg(args[j], XtNwidth, bw_width);  j++; /*force wider than buttons*/
5157 #if 0
5158     XtSetArg(args[j], XtNscrollVertical, XawtextScrollWhenNeeded);  j++;
5159 #else
5160     /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
5161     XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways);  j++;
5162 #endif
5163     XtSetArg(args[j], XtNautoFill, True);  j++;
5164     XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
5165     edit =
5166       XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
5167
5168     if (mutable) {
5169         j = 0;
5170         XtSetArg(args[j], XtNfromVert, edit);  j++;
5171         XtSetArg(args[j], XtNtop, XtChainBottom); j++;
5172         XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
5173         XtSetArg(args[j], XtNleft, XtChainLeft); j++;
5174         XtSetArg(args[j], XtNright, XtChainLeft); j++;
5175         b_ok =
5176           XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
5177         XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
5178
5179         j = 0;
5180         XtSetArg(args[j], XtNfromVert, edit);  j++;
5181         XtSetArg(args[j], XtNfromHoriz, b_ok);  j++;
5182         XtSetArg(args[j], XtNtop, XtChainBottom); j++;
5183         XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
5184         XtSetArg(args[j], XtNleft, XtChainLeft); j++;
5185         XtSetArg(args[j], XtNright, XtChainLeft); j++;
5186         b_cancel =
5187           XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
5188         XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
5189
5190         j = 0;
5191         XtSetArg(args[j], XtNfromVert, edit);  j++;
5192         XtSetArg(args[j], XtNfromHoriz, b_cancel);  j++;
5193         XtSetArg(args[j], XtNtop, XtChainBottom); j++;
5194         XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
5195         XtSetArg(args[j], XtNleft, XtChainLeft); j++;
5196         XtSetArg(args[j], XtNright, XtChainLeft); j++;
5197         b_clear =
5198           XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
5199         XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
5200     } else {
5201         j = 0;
5202         XtSetArg(args[j], XtNfromVert, edit);  j++;
5203         XtSetArg(args[j], XtNtop, XtChainBottom); j++;
5204         XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
5205         XtSetArg(args[j], XtNleft, XtChainLeft); j++;
5206         XtSetArg(args[j], XtNright, XtChainLeft); j++;
5207         b_close =
5208           XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
5209         XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
5210
5211         j = 0;
5212         XtSetArg(args[j], XtNfromVert, edit);  j++;
5213         XtSetArg(args[j], XtNfromHoriz, b_close);  j++;
5214         XtSetArg(args[j], XtNtop, XtChainBottom); j++;
5215         XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
5216         XtSetArg(args[j], XtNleft, XtChainLeft); j++;
5217         XtSetArg(args[j], XtNright, XtChainLeft); j++;
5218         b_edit =
5219           XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
5220         XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
5221     }
5222
5223     XtRealizeWidget(shell);
5224
5225     if (commentX == -1) {
5226         int xx, yy;
5227         Window junk;
5228         Dimension pw_height;
5229         Dimension ew_height;
5230
5231         j = 0;
5232         XtSetArg(args[j], XtNheight, &ew_height);  j++;
5233         XtGetValues(edit, args, j);
5234
5235         j = 0;
5236         XtSetArg(args[j], XtNheight, &pw_height);  j++;
5237         XtGetValues(shell, args, j);
5238         commentH = pw_height + (lines - 1) * ew_height;
5239         commentW = bw_width - 16;
5240
5241         XSync(xDisplay, False);
5242 #ifdef NOTDEF
5243         /* This code seems to tickle an X bug if it is executed too soon
5244            after xboard starts up.  The coordinates get transformed as if
5245            the main window was positioned at (0, 0).
5246            */
5247         XtTranslateCoords(shellWidget,
5248                           (bw_width - commentW) / 2, 0 - commentH / 2,
5249                           &commentX, &commentY);
5250 #else  /*!NOTDEF*/
5251         XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
5252                               RootWindowOfScreen(XtScreen(shellWidget)),
5253                               (bw_width - commentW) / 2, 0 - commentH / 2,
5254                               &xx, &yy, &junk);
5255         commentX = xx;
5256         commentY = yy;
5257 #endif /*!NOTDEF*/
5258         if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
5259     }
5260     j = 0;
5261     XtSetArg(args[j], XtNheight, commentH);  j++;
5262     XtSetArg(args[j], XtNwidth, commentW);  j++;
5263     XtSetArg(args[j], XtNx, commentX);  j++;
5264     XtSetArg(args[j], XtNy, commentY);  j++;
5265     XtSetValues(shell, args, j);
5266     XtSetKeyboardFocus(shell, edit);
5267
5268     return shell;
5269 }
5270
5271 /* Used for analysis window and ICS input window */
5272 Widget MiscCreate(name, text, mutable, callback, lines)
5273      char *name, *text;
5274      int /*Boolean*/ mutable;
5275      XtCallbackProc callback;
5276      int lines;
5277 {
5278     Arg args[16];
5279     Widget shell, layout, form, edit;
5280     Position x, y;
5281     Dimension bw_width, pw_height, ew_height, w, h;
5282     int j;
5283     int xx, yy;
5284     Window junk;
5285
5286     j = 0;
5287     XtSetArg(args[j], XtNresizable, True);  j++;
5288 #if TOPLEVEL
5289     shell =
5290       XtCreatePopupShell(name, topLevelShellWidgetClass,
5291                          shellWidget, args, j);
5292 #else
5293     shell =
5294       XtCreatePopupShell(name, transientShellWidgetClass,
5295                          shellWidget, args, j);
5296 #endif
5297     layout =
5298       XtCreateManagedWidget(layoutName, formWidgetClass, shell,
5299                             layoutArgs, XtNumber(layoutArgs));
5300     form =
5301       XtCreateManagedWidget("form", formWidgetClass, layout,
5302                             formArgs, XtNumber(formArgs));
5303
5304     j = 0;
5305     if (mutable) {
5306         XtSetArg(args[j], XtNeditType, XawtextEdit);  j++;
5307         XtSetArg(args[j], XtNuseStringInPlace, False);  j++;
5308     }
5309     XtSetArg(args[j], XtNstring, text);  j++;
5310     XtSetArg(args[j], XtNtop, XtChainTop);  j++;
5311     XtSetArg(args[j], XtNbottom, XtChainBottom);  j++;
5312     XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
5313     XtSetArg(args[j], XtNright, XtChainRight);  j++;
5314     XtSetArg(args[j], XtNresizable, True);  j++;
5315 #if 0
5316     XtSetArg(args[j], XtNscrollVertical, XawtextScrollWhenNeeded);  j++;
5317 #else
5318     /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
5319     XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways);  j++;
5320 #endif
5321     XtSetArg(args[j], XtNautoFill, True);  j++;
5322     XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
5323     edit =
5324       XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
5325
5326     XtRealizeWidget(shell);
5327
5328     j = 0;
5329     XtSetArg(args[j], XtNwidth, &bw_width);  j++;
5330     XtGetValues(boardWidget, args, j);
5331
5332     j = 0;
5333     XtSetArg(args[j], XtNheight, &ew_height);  j++;
5334     XtGetValues(edit, args, j);
5335
5336     j = 0;
5337     XtSetArg(args[j], XtNheight, &pw_height);  j++;
5338     XtGetValues(shell, args, j);
5339     h = pw_height + (lines - 1) * ew_height;
5340     w = bw_width - 16;
5341
5342     XSync(xDisplay, False);
5343 #ifdef NOTDEF
5344     /* This code seems to tickle an X bug if it is executed too soon
5345        after xboard starts up.  The coordinates get transformed as if
5346        the main window was positioned at (0, 0).
5347     */
5348     XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
5349 #else  /*!NOTDEF*/
5350     XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
5351                           RootWindowOfScreen(XtScreen(shellWidget)),
5352                           (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
5353 #endif /*!NOTDEF*/
5354     x = xx;
5355     y = yy;
5356     if (y < 0) y = 0; /*avoid positioning top offscreen*/
5357
5358     j = 0;
5359     XtSetArg(args[j], XtNheight, h);  j++;
5360     XtSetArg(args[j], XtNwidth, w);  j++;
5361     XtSetArg(args[j], XtNx, x);  j++;
5362     XtSetArg(args[j], XtNy, y);  j++;
5363     XtSetValues(shell, args, j);
5364
5365     return shell;
5366 }
5367
5368
5369 static int savedIndex;  /* gross that this is global */
5370
5371 void EditCommentPopUp(index, title, text)
5372      int index;
5373      char *title, *text;
5374 {
5375     Widget edit;
5376     Arg args[16];
5377     int j;
5378
5379     savedIndex = index;
5380     if (text == NULL) text = "";
5381
5382     if (editShell == NULL) {
5383         editShell =
5384           CommentCreate(title, text, True, EditCommentCallback, 4);
5385         XtRealizeWidget(editShell);
5386         CatchDeleteWindow(editShell, "EditCommentPopDown");
5387     } else {
5388         edit = XtNameToWidget(editShell, "*form.text");
5389         j = 0;
5390         XtSetArg(args[j], XtNstring, text); j++;
5391         XtSetValues(edit, args, j);
5392         j = 0;
5393         XtSetArg(args[j], XtNiconName, (XtArgVal) title);   j++;
5394         XtSetArg(args[j], XtNtitle, (XtArgVal) title);      j++;
5395         XtSetValues(editShell, args, j);
5396     }
5397
5398     XtPopup(editShell, XtGrabNone);
5399
5400     editUp = True;
5401     j = 0;
5402     XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5403     XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
5404                 args, j);
5405 }
5406
5407 void EditCommentCallback(w, client_data, call_data)
5408      Widget w;
5409      XtPointer client_data, call_data;
5410 {
5411     String name, val;
5412     Arg args[16];
5413     int j;
5414     Widget edit;
5415
5416     j = 0;
5417     XtSetArg(args[j], XtNlabel, &name);  j++;
5418     XtGetValues(w, args, j);
5419
5420     if (strcmp(name, _("ok")) == 0) {
5421         edit = XtNameToWidget(editShell, "*form.text");
5422         j = 0;
5423         XtSetArg(args[j], XtNstring, &val); j++;
5424         XtGetValues(edit, args, j);
5425         ReplaceComment(savedIndex, val);
5426         EditCommentPopDown();
5427     } else if (strcmp(name, _("cancel")) == 0) {
5428         EditCommentPopDown();
5429     } else if (strcmp(name, _("clear")) == 0) {
5430         edit = XtNameToWidget(editShell, "*form.text");
5431         XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5432         XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5433     }
5434 }
5435
5436 void EditCommentPopDown()
5437 {
5438     Arg args[16];
5439     int j;
5440
5441     if (!editUp) return;
5442     j = 0;
5443     XtSetArg(args[j], XtNx, &commentX); j++;
5444     XtSetArg(args[j], XtNy, &commentY); j++;
5445     XtSetArg(args[j], XtNheight, &commentH); j++;
5446     XtSetArg(args[j], XtNwidth, &commentW); j++;
5447     XtGetValues(editShell, args, j);
5448     XtPopdown(editShell);
5449     editUp = False;
5450     j = 0;
5451     XtSetArg(args[j], XtNleftBitmap, None); j++;
5452     XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
5453                 args, j);
5454 }
5455
5456 void ICSInputBoxPopUp()
5457 {
5458     Widget edit;
5459     Arg args[16];
5460     int j;
5461     char *title = _("ICS Input");
5462     XtTranslations tr;
5463
5464     if (ICSInputShell == NULL) {
5465         ICSInputShell = MiscCreate(title, "", True, NULL, 1);
5466         tr = XtParseTranslationTable(ICSInputTranslations);
5467         edit = XtNameToWidget(ICSInputShell, "*form.text");
5468         XtOverrideTranslations(edit, tr);
5469         XtRealizeWidget(ICSInputShell);
5470         CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
5471
5472     } else {
5473         edit = XtNameToWidget(ICSInputShell, "*form.text");
5474         j = 0;
5475         XtSetArg(args[j], XtNstring, ""); j++;
5476         XtSetValues(edit, args, j);
5477         j = 0;
5478         XtSetArg(args[j], XtNiconName, (XtArgVal) title);   j++;
5479         XtSetArg(args[j], XtNtitle, (XtArgVal) title);      j++;
5480         XtSetValues(ICSInputShell, args, j);
5481     }
5482
5483     XtPopup(ICSInputShell, XtGrabNone);
5484     XtSetKeyboardFocus(ICSInputShell, edit);
5485
5486     ICSInputBoxUp = True;
5487     j = 0;
5488     XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5489     XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
5490                 args, j);
5491 }
5492
5493 void ICSInputSendText()
5494 {
5495     Widget edit;
5496     int j;
5497     Arg args[16];
5498     String val;
5499
5500     edit = XtNameToWidget(ICSInputShell, "*form.text");
5501     j = 0;
5502     XtSetArg(args[j], XtNstring, &val); j++;
5503     XtGetValues(edit, args, j);
5504     SendMultiLineToICS(val);
5505     XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5506     XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5507 }
5508
5509 void ICSInputBoxPopDown()
5510 {
5511     Arg args[16];
5512     int j;
5513
5514     if (!ICSInputBoxUp) return;
5515     j = 0;
5516     XtPopdown(ICSInputShell);
5517     ICSInputBoxUp = False;
5518     j = 0;
5519     XtSetArg(args[j], XtNleftBitmap, None); j++;
5520     XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
5521                 args, j);
5522 }
5523
5524 void CommentPopUp(title, text)
5525      char *title, *text;
5526 {
5527     Arg args[16];
5528     int j;
5529     Widget edit;
5530
5531     if (commentShell == NULL) {
5532         commentShell =
5533           CommentCreate(title, text, False, CommentCallback, 4);
5534         XtRealizeWidget(commentShell);
5535         CatchDeleteWindow(commentShell, "CommentPopDown");
5536     } else {
5537         edit = XtNameToWidget(commentShell, "*form.text");
5538         j = 0;
5539         XtSetArg(args[j], XtNstring, text); j++;
5540         XtSetValues(edit, args, j);
5541         j = 0;
5542         XtSetArg(args[j], XtNiconName, (XtArgVal) title);   j++;
5543         XtSetArg(args[j], XtNtitle, (XtArgVal) title);      j++;
5544         XtSetValues(commentShell, args, j);
5545     }
5546
5547     XtPopup(commentShell, XtGrabNone);
5548     XSync(xDisplay, False);
5549
5550     commentUp = True;
5551 }
5552
5553 void AnalysisPopUp(title, text)
5554      char *title, *text;
5555 {
5556     Arg args[16];
5557     int j;
5558     Widget edit;
5559
5560     if (analysisShell == NULL) {
5561         analysisShell = MiscCreate(title, text, False, NULL, 4);
5562         XtRealizeWidget(analysisShell);
5563         CatchDeleteWindow(analysisShell, "AnalysisPopDown");
5564
5565     } else {
5566         edit = XtNameToWidget(analysisShell, "*form.text");
5567         j = 0;
5568         XtSetArg(args[j], XtNstring, text); j++;
5569         XtSetValues(edit, args, j);
5570         j = 0;
5571         XtSetArg(args[j], XtNiconName, (XtArgVal) title);   j++;
5572         XtSetArg(args[j], XtNtitle, (XtArgVal) title);      j++;
5573         XtSetValues(analysisShell, args, j);
5574     }
5575
5576     if (!analysisUp) {
5577         XtPopup(analysisShell, XtGrabNone);
5578     }
5579     XSync(xDisplay, False);
5580
5581     analysisUp = True;
5582 }
5583
5584 void CommentCallback(w, client_data, call_data)
5585      Widget w;
5586      XtPointer client_data, call_data;
5587 {
5588     String name;
5589     Arg args[16];
5590     int j;
5591
5592     j = 0;
5593     XtSetArg(args[j], XtNlabel, &name);  j++;
5594     XtGetValues(w, args, j);
5595
5596     if (strcmp(name, _("close")) == 0) {
5597         CommentPopDown();
5598     } else if (strcmp(name, _("edit")) == 0) {
5599         CommentPopDown();
5600         EditCommentEvent();
5601     }
5602 }
5603
5604
5605 void CommentPopDown()
5606 {
5607     Arg args[16];
5608     int j;
5609
5610     if (!commentUp) return;
5611     j = 0;
5612     XtSetArg(args[j], XtNx, &commentX); j++;
5613     XtSetArg(args[j], XtNy, &commentY); j++;
5614     XtSetArg(args[j], XtNwidth, &commentW); j++;
5615     XtSetArg(args[j], XtNheight, &commentH); j++;
5616     XtGetValues(commentShell, args, j);
5617     XtPopdown(commentShell);
5618     XSync(xDisplay, False);
5619     commentUp = False;
5620 }
5621
5622 void AnalysisPopDown()
5623 {
5624     if (!analysisUp) return;
5625     XtPopdown(analysisShell);
5626     XSync(xDisplay, False);
5627     analysisUp = False;
5628     if (appData.icsEngineAnalyze) ExitAnalyzeMode();    /* [DM] icsEngineAnalyze */
5629 }
5630
5631
5632 void FileNamePopUp(label, def, proc, openMode)
5633      char *label;
5634      char *def;
5635      FileProc proc;
5636      char *openMode;
5637 {
5638     Arg args[16];
5639     Widget popup, layout, dialog, edit;
5640     Window root, child;
5641     int x, y, i;
5642     int win_x, win_y;
5643     unsigned int mask;
5644
5645     fileProc = proc;            /* I can't see a way not */
5646     fileOpenMode = openMode;    /*   to use globals here */
5647
5648     i = 0;
5649     XtSetArg(args[i], XtNresizable, True); i++;
5650     XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
5651     XtSetArg(args[i], XtNtitle, XtNewString(_("File name prompt"))); i++;
5652     fileNameShell = popup =
5653       XtCreatePopupShell("File name prompt", transientShellWidgetClass,
5654                          shellWidget, args, i);
5655
5656     layout =
5657       XtCreateManagedWidget(layoutName, formWidgetClass, popup,
5658                             layoutArgs, XtNumber(layoutArgs));
5659
5660     i = 0;
5661     XtSetArg(args[i], XtNlabel, label); i++;
5662     XtSetArg(args[i], XtNvalue, def); i++;
5663     XtSetArg(args[i], XtNborderWidth, 0); i++;
5664     dialog = XtCreateManagedWidget("fileName", dialogWidgetClass,
5665                                    layout, args, i);
5666
5667     XawDialogAddButton(dialog, _("ok"), FileNameCallback, (XtPointer) dialog);
5668     XawDialogAddButton(dialog, _("cancel"), FileNameCallback,
5669                        (XtPointer) dialog);
5670
5671     XtRealizeWidget(popup);
5672     CatchDeleteWindow(popup, "FileNamePopDown");
5673
5674     XQueryPointer(xDisplay, xBoardWindow, &root, &child,
5675                   &x, &y, &win_x, &win_y, &mask);
5676
5677     XtSetArg(args[0], XtNx, x - 10);
5678     XtSetArg(args[1], XtNy, y - 30);
5679     XtSetValues(popup, args, 2);
5680
5681     XtPopup(popup, XtGrabExclusive);
5682     filenameUp = True;
5683
5684     edit = XtNameToWidget(dialog, "*value");
5685     XtSetKeyboardFocus(popup, edit);
5686 }
5687
5688 void FileNamePopDown()
5689 {
5690     if (!filenameUp) return;
5691     XtPopdown(fileNameShell);
5692     XtDestroyWidget(fileNameShell);
5693     filenameUp = False;
5694     ModeHighlight();
5695 }
5696
5697 void FileNameCallback(w, client_data, call_data)
5698      Widget w;
5699      XtPointer client_data, call_data;
5700 {
5701     String name;
5702     Arg args[16];
5703
5704     XtSetArg(args[0], XtNlabel, &name);
5705     XtGetValues(w, args, 1);
5706
5707     if (strcmp(name, _("cancel")) == 0) {
5708         FileNamePopDown();
5709         return;
5710     }
5711
5712     FileNameAction(w, NULL, NULL, NULL);
5713 }
5714
5715 void FileNameAction(w, event, prms, nprms)
5716      Widget w;
5717      XEvent *event;
5718      String *prms;
5719      Cardinal *nprms;
5720 {
5721     char buf[MSG_SIZ];
5722     String name;
5723     FILE *f;
5724     char *p, *fullname;
5725     int index;
5726
5727     name = XawDialogGetValueString(w = XtParent(w));
5728
5729     if ((name != NULL) && (*name != NULLCHAR)) {
5730         strcpy(buf, name);
5731         XtPopdown(w = XtParent(XtParent(w)));
5732         XtDestroyWidget(w);
5733         filenameUp = False;
5734
5735         p = strrchr(buf, ' ');
5736         if (p == NULL) {
5737             index = 0;
5738         } else {
5739             *p++ = NULLCHAR;
5740             index = atoi(p);
5741         }
5742         fullname = ExpandPathName(buf);
5743         if (!fullname) {
5744             ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5745         }
5746         else {
5747             f = fopen(fullname, fileOpenMode);
5748             if (f == NULL) {
5749                 DisplayError(_("Failed to open file"), errno);
5750             } else {
5751                 (void) (*fileProc)(f, index, buf);
5752             }
5753         }
5754         ModeHighlight();
5755         return;
5756     }
5757
5758     XtPopdown(w = XtParent(XtParent(w)));
5759     XtDestroyWidget(w);
5760     filenameUp = False;
5761     ModeHighlight();
5762 }
5763
5764 void PromotionPopUp()
5765 {
5766     Arg args[16];
5767     Widget dialog, layout;
5768     Position x, y;
5769     Dimension bw_width, pw_width;
5770     int j;
5771
5772     j = 0;
5773     XtSetArg(args[j], XtNwidth, &bw_width); j++;
5774     XtGetValues(boardWidget, args, j);
5775
5776     j = 0;
5777     XtSetArg(args[j], XtNresizable, True); j++;
5778     XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5779     promotionShell =
5780       XtCreatePopupShell("Promotion", transientShellWidgetClass,
5781                          shellWidget, args, j);
5782     layout =
5783       XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5784                             layoutArgs, XtNumber(layoutArgs));
5785
5786     j = 0;
5787     XtSetArg(args[j], XtNlabel, _("Promote pawn to what?")); j++;
5788     XtSetArg(args[j], XtNborderWidth, 0); j++;
5789     dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5790                                    layout, args, j);
5791
5792     XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5793                        (XtPointer) dialog);
5794     XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5795                        (XtPointer) dialog);
5796     XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5797                        (XtPointer) dialog);
5798     XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5799                        (XtPointer) dialog);
5800     if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5801         gameInfo.variant == VariantGiveaway) {
5802       XawDialogAddButton(dialog, _("King"), PromotionCallback,
5803                          (XtPointer) dialog);
5804     }
5805     XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5806                        (XtPointer) dialog);
5807
5808     XtRealizeWidget(promotionShell);
5809     CatchDeleteWindow(promotionShell, "PromotionPopDown");
5810
5811     j = 0;
5812     XtSetArg(args[j], XtNwidth, &pw_width); j++;
5813     XtGetValues(promotionShell, args, j);
5814
5815     XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5816                       lineGap + squareSize/3 +
5817                       ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5818                        0 : 6*(squareSize + lineGap)), &x, &y);
5819
5820     j = 0;
5821     XtSetArg(args[j], XtNx, x); j++;
5822     XtSetArg(args[j], XtNy, y); j++;
5823     XtSetValues(promotionShell, args, j);
5824
5825     XtPopup(promotionShell, XtGrabNone);
5826
5827     promotionUp = True;
5828 }
5829
5830 void PromotionPopDown()
5831 {
5832     if (!promotionUp) return;
5833     XtPopdown(promotionShell);
5834     XtDestroyWidget(promotionShell);
5835     promotionUp = False;
5836 }
5837
5838 void PromotionCallback(w, client_data, call_data)
5839      Widget w;
5840      XtPointer client_data, call_data;
5841 {
5842     String name;
5843     Arg args[16];
5844     int promoChar;
5845
5846     XtSetArg(args[0], XtNlabel, &name);
5847     XtGetValues(w, args, 1);
5848
5849     PromotionPopDown();
5850
5851     if (fromX == -1) return;
5852
5853     if (strcmp(name, _("cancel")) == 0) {
5854         fromX = fromY = -1;
5855         ClearHighlights();
5856         return;
5857     } else if (strcmp(name, _("Knight")) == 0) {
5858         promoChar = 'n';
5859     } else {
5860         promoChar = ToLower(name[0]);
5861     }
5862
5863     UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5864
5865     if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5866     if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5867     fromX = fromY = -1;
5868 }
5869
5870
5871 void ErrorCallback(w, client_data, call_data)
5872      Widget w;
5873      XtPointer client_data, call_data;
5874 {
5875     errorUp = False;
5876     XtPopdown(w = XtParent(XtParent(XtParent(w))));
5877     XtDestroyWidget(w);
5878     if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5879 }
5880
5881
5882 void ErrorPopDown()
5883 {
5884     if (!errorUp) return;
5885     errorUp = False;
5886     XtPopdown(errorShell);
5887     XtDestroyWidget(errorShell);
5888     if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5889 }
5890
5891 void ErrorPopUp(title, label, modal)
5892      char *title, *label;
5893      int modal;
5894 {
5895     Arg args[16];
5896     Widget dialog, layout;
5897     Position x, y;
5898     int xx, yy;
5899     Window junk;
5900     Dimension bw_width, pw_width;
5901     Dimension pw_height;
5902     int i;
5903
5904     i = 0;
5905     XtSetArg(args[i], XtNresizable, True);  i++;
5906     XtSetArg(args[i], XtNtitle, title); i++;
5907     errorShell =
5908       XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5909                          shellWidget, args, i);
5910     layout =
5911       XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5912                             layoutArgs, XtNumber(layoutArgs));
5913
5914     i = 0;
5915     XtSetArg(args[i], XtNlabel, label); i++;
5916     XtSetArg(args[i], XtNborderWidth, 0); i++;
5917     dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5918                                    layout, args, i);
5919
5920     XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5921
5922     XtRealizeWidget(errorShell);
5923     CatchDeleteWindow(errorShell, "ErrorPopDown");
5924
5925     i = 0;
5926     XtSetArg(args[i], XtNwidth, &bw_width);  i++;
5927     XtGetValues(boardWidget, args, i);
5928     i = 0;
5929     XtSetArg(args[i], XtNwidth, &pw_width);  i++;
5930     XtSetArg(args[i], XtNheight, &pw_height);  i++;
5931     XtGetValues(errorShell, args, i);
5932
5933 #ifdef NOTDEF
5934     /* This code seems to tickle an X bug if it is executed too soon
5935        after xboard starts up.  The coordinates get transformed as if
5936        the main window was positioned at (0, 0).
5937        */
5938     XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5939                       0 - pw_height + squareSize / 3, &x, &y);
5940 #else
5941     XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5942                           RootWindowOfScreen(XtScreen(boardWidget)),
5943                           (bw_width - pw_width) / 2,
5944                           0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5945     x = xx;
5946     y = yy;
5947 #endif
5948     if (y < 0) y = 0; /*avoid positioning top offscreen*/
5949
5950     i = 0;
5951     XtSetArg(args[i], XtNx, x);  i++;
5952     XtSetArg(args[i], XtNy, y);  i++;
5953     XtSetValues(errorShell, args, i);
5954
5955     errorUp = True;
5956     XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5957 }
5958
5959 /* Disable all user input other than deleting the window */
5960 static int frozen = 0;
5961 void FreezeUI()
5962 {
5963   if (frozen) return;
5964   /* Grab by a widget that doesn't accept input */
5965   XtAddGrab(messageWidget, TRUE, FALSE);
5966   frozen = 1;
5967 }
5968
5969 /* Undo a FreezeUI */
5970 void ThawUI()
5971 {
5972   if (!frozen) return;
5973   XtRemoveGrab(messageWidget);
5974   frozen = 0;
5975 }
5976
5977 char *ModeToWidgetName(mode)
5978      GameMode mode;
5979 {
5980     switch (mode) {
5981       case BeginningOfGame:
5982         if (appData.icsActive)
5983           return "menuMode.ICS Client";
5984         else if (appData.noChessProgram ||
5985                  *appData.cmailGameName != NULLCHAR)
5986           return "menuMode.Edit Game";
5987         else
5988           return "menuMode.Machine Black";
5989       case MachinePlaysBlack:
5990         return "menuMode.Machine Black";
5991       case MachinePlaysWhite:
5992         return "menuMode.Machine White";
5993       case AnalyzeMode:
5994         return "menuMode.Analysis Mode";
5995       case AnalyzeFile:
5996         return "menuMode.Analyze File";
5997       case TwoMachinesPlay:
5998         return "menuMode.Two Machines";
5999       case EditGame:
6000         return "menuMode.Edit Game";
6001       case PlayFromGameFile:
6002         return "menuFile.Load Game";
6003       case EditPosition:
6004         return "menuMode.Edit Position";
6005       case Training:
6006         return "menuMode.Training";
6007       case IcsPlayingWhite:
6008       case IcsPlayingBlack:
6009       case IcsObserving:
6010       case IcsIdle:
6011       case IcsExamining:
6012         return "menuMode.ICS Client";
6013       default:
6014       case EndOfGame:
6015         return NULL;
6016     }
6017 }
6018
6019 void ModeHighlight()
6020 {
6021     Arg args[16];
6022     static int oldPausing = FALSE;
6023     static GameMode oldmode = (GameMode) -1;
6024     char *wname;
6025
6026     if (!boardWidget || !XtIsRealized(boardWidget)) return;
6027
6028     if (pausing != oldPausing) {
6029         oldPausing = pausing;
6030         if (pausing) {
6031             XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6032         } else {
6033             XtSetArg(args[0], XtNleftBitmap, None);
6034         }
6035         XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
6036                     args, 1);
6037
6038         if (appData.showButtonBar) {
6039 #if 0
6040           if (pausing) {
6041             XtSetArg(args[0], XtNbackground, buttonForegroundPixel);
6042             XtSetArg(args[1], XtNforeground, buttonBackgroundPixel);
6043           } else {
6044             XtSetArg(args[0], XtNbackground, buttonBackgroundPixel);
6045             XtSetArg(args[1], XtNforeground, buttonForegroundPixel);
6046           }
6047 #else
6048           /* Always toggle, don't set.  Previous code messes up when
6049              invoked while the button is pressed, as releasing it
6050              toggles the state again. */
6051           {
6052             Pixel oldbg, oldfg;
6053             XtSetArg(args[0], XtNbackground, &oldbg);
6054             XtSetArg(args[1], XtNforeground, &oldfg);
6055             XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
6056                         args, 2);
6057             XtSetArg(args[0], XtNbackground, oldfg);
6058             XtSetArg(args[1], XtNforeground, oldbg);
6059           }
6060 #endif
6061           XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
6062         }
6063     }
6064
6065     wname = ModeToWidgetName(oldmode);
6066     if (wname != NULL) {
6067         XtSetArg(args[0], XtNleftBitmap, None);
6068         XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
6069     }
6070     wname = ModeToWidgetName(gameMode);
6071     if (wname != NULL) {
6072         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6073         XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
6074     }
6075     oldmode = gameMode;
6076
6077     /* Maybe all the enables should be handled here, not just this one */
6078     XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
6079                    gameMode == Training || gameMode == PlayFromGameFile);
6080 }
6081
6082
6083 /*
6084  * Button/menu procedures
6085  */
6086 void ResetProc(w, event, prms, nprms)
6087      Widget w;
6088      XEvent *event;
6089      String *prms;
6090      Cardinal *nprms;
6091 {
6092     ResetGameEvent();
6093     AnalysisPopDown();
6094 }
6095
6096 int LoadGamePopUp(f, gameNumber, title)
6097      FILE *f;
6098      int gameNumber;
6099      char *title;
6100 {
6101     cmailMsgLoaded = FALSE;
6102     if (gameNumber == 0) {
6103         int error = GameListBuild(f);
6104         if (error) {
6105             DisplayError(_("Cannot build game list"), error);
6106         } else if (!ListEmpty(&gameList) &&
6107                    ((ListGame *) gameList.tailPred)->number > 1) {
6108             GameListPopUp(f, title);
6109             return TRUE;
6110         }
6111         GameListDestroy();
6112         gameNumber = 1;
6113     }
6114     return LoadGame(f, gameNumber, title, FALSE);
6115 }
6116
6117 void LoadGameProc(w, event, prms, nprms)
6118      Widget w;
6119      XEvent *event;
6120      String *prms;
6121      Cardinal *nprms;
6122 {
6123     if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
6124         Reset(FALSE, TRUE);
6125     }
6126     FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
6127 }
6128
6129 void LoadNextGameProc(w, event, prms, nprms)
6130      Widget w;
6131      XEvent *event;
6132      String *prms;
6133      Cardinal *nprms;
6134 {
6135     ReloadGame(1);
6136 }
6137
6138 void LoadPrevGameProc(w, event, prms, nprms)
6139      Widget w;
6140      XEvent *event;
6141      String *prms;
6142      Cardinal *nprms;
6143 {
6144     ReloadGame(-1);
6145 }
6146
6147 void ReloadGameProc(w, event, prms, nprms)
6148      Widget w;
6149      XEvent *event;
6150      String *prms;
6151      Cardinal *nprms;
6152 {
6153     ReloadGame(0);
6154 }
6155
6156 void LoadNextPositionProc(w, event, prms, nprms)
6157      Widget w;
6158      XEvent *event;
6159      String *prms;
6160      Cardinal *nprms;
6161 {
6162     ReloadPosition(1);
6163 }
6164
6165 void LoadPrevPositionProc(w, event, prms, nprms)
6166      Widget w;
6167      XEvent *event;
6168      String *prms;
6169      Cardinal *nprms;
6170 {
6171     ReloadPosition(-1);
6172 }
6173
6174 void ReloadPositionProc(w, event, prms, nprms)
6175      Widget w;
6176      XEvent *event;
6177      String *prms;
6178      Cardinal *nprms;
6179 {
6180     ReloadPosition(0);
6181 }
6182
6183 void LoadPositionProc(w, event, prms, nprms)
6184      Widget w;
6185      XEvent *event;
6186      String *prms;
6187      Cardinal *nprms;
6188 {
6189     if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
6190         Reset(FALSE, TRUE);
6191     }
6192     FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
6193 }
6194
6195 void SaveGameProc(w, event, prms, nprms)
6196      Widget w;
6197      XEvent *event;
6198      String *prms;
6199      Cardinal *nprms;
6200 {
6201     FileNamePopUp(_("Save game file name?"),
6202                   DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
6203                   SaveGame, "a");
6204 }
6205
6206 void SavePositionProc(w, event, prms, nprms)
6207      Widget w;
6208      XEvent *event;
6209      String *prms;
6210      Cardinal *nprms;
6211 {
6212     FileNamePopUp(_("Save position file name?"),
6213                   DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
6214                   SavePosition, "a");
6215 }
6216
6217 void ReloadCmailMsgProc(w, event, prms, nprms)
6218      Widget w;
6219      XEvent *event;
6220      String *prms;
6221      Cardinal *nprms;
6222 {
6223     ReloadCmailMsgEvent(FALSE);
6224 }
6225
6226 void MailMoveProc(w, event, prms, nprms)
6227      Widget w;
6228      XEvent *event;
6229      String *prms;
6230      Cardinal *nprms;
6231 {
6232     MailMoveEvent();
6233 }
6234
6235 /* this variable is shared between CopyPositionProc and SendPositionSelection */
6236 static char *selected_fen_position=NULL;
6237
6238 static Boolean
6239 SendPositionSelection(Widget w, Atom *selection, Atom *target,
6240                  Atom *type_return, XtPointer *value_return,
6241                  unsigned long *length_return, int *format_return)
6242 {
6243   char *selection_tmp;
6244
6245   if (!selected_fen_position) return False; /* should never happen */
6246   if (*target == XA_STRING){
6247     /* note: since no XtSelectionDoneProc was registered, Xt will
6248      * automatically call XtFree on the value returned.  So have to
6249      * make a copy of it allocated with XtMalloc */
6250     selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
6251     strcpy(selection_tmp, selected_fen_position);
6252
6253     *value_return=selection_tmp;
6254     *length_return=strlen(selection_tmp);
6255     *type_return=XA_STRING;
6256     *format_return = 8; /* bits per byte */
6257     return True;
6258   } else {
6259     return False;
6260   }
6261 }
6262
6263 /* note: when called from menu all parameters are NULL, so no clue what the
6264  * Widget which was clicked on was, or what the click event was
6265  */
6266 void CopyPositionProc(w, event, prms, nprms)
6267   Widget w;
6268   XEvent *event;
6269   String *prms;
6270   Cardinal *nprms;
6271   {
6272     int ret;
6273
6274     if (selected_fen_position) free(selected_fen_position);
6275     selected_fen_position = (char *)PositionToFEN(currentMove,1);
6276     if (!selected_fen_position) return;
6277     ret = XtOwnSelection(menuBarWidget, XA_PRIMARY,
6278                          CurrentTime,
6279                          SendPositionSelection,
6280                          NULL/* lose_ownership_proc */ ,
6281                          NULL/* transfer_done_proc */);
6282     if (!ret) {
6283       free(selected_fen_position);
6284       selected_fen_position=NULL;
6285     }
6286   }
6287
6288 /* function called when the data to Paste is ready */
6289 static void
6290 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
6291            Atom *type, XtPointer value, unsigned long *len, int *format)
6292 {
6293   char *fenstr=value;
6294   if (value==NULL || *len==0) return; /* nothing had been selected to copy */
6295   fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
6296   EditPositionPasteFEN(fenstr);
6297   XtFree(value);
6298 }
6299
6300 /* called when Paste Position button is pressed,
6301  * all parameters will be NULL */
6302 void PastePositionProc(w, event, prms, nprms)
6303   Widget w;
6304   XEvent *event;
6305   String *prms;
6306   Cardinal *nprms;
6307 {
6308     XtGetSelectionValue(menuBarWidget, XA_PRIMARY, XA_STRING,
6309       /* (XtSelectionCallbackProc) */ PastePositionCB,
6310       NULL, /* client_data passed to PastePositionCB */
6311
6312       /* better to use the time field from the event that triggered the
6313        * call to this function, but that isn't trivial to get
6314        */
6315       CurrentTime
6316     );
6317     return;
6318 }
6319
6320 static Boolean
6321 SendGameSelection(Widget w, Atom *selection, Atom *target,
6322                   Atom *type_return, XtPointer *value_return,
6323                   unsigned long *length_return, int *format_return)
6324 {
6325   char *selection_tmp;
6326
6327   if (*target == XA_STRING){
6328     FILE* f = fopen(gameCopyFilename, "r");
6329     long len;
6330     size_t count;
6331     if (f == NULL) return False;
6332     fseek(f, 0, 2);
6333     len = ftell(f);
6334     rewind(f);
6335     selection_tmp = XtMalloc(len + 1);
6336     count = fread(selection_tmp, 1, len, f);
6337     if (len != count) {
6338       XtFree(selection_tmp);
6339       return False;
6340     }
6341     selection_tmp[len] = NULLCHAR;
6342     *value_return = selection_tmp;
6343     *length_return = len;
6344     *type_return = XA_STRING;
6345     *format_return = 8; /* bits per byte */
6346     return True;
6347   } else {
6348     return False;
6349   }
6350 }
6351
6352 /* note: when called from menu all parameters are NULL, so no clue what the
6353  * Widget which was clicked on was, or what the click event was
6354  */
6355 void CopyGameProc(w, event, prms, nprms)
6356   Widget w;
6357   XEvent *event;
6358   String *prms;
6359   Cardinal *nprms;
6360 {
6361   int ret;
6362
6363   ret = SaveGameToFile(gameCopyFilename, FALSE);
6364   if (!ret) return;
6365
6366   ret = XtOwnSelection(menuBarWidget, XA_PRIMARY,
6367                        CurrentTime,
6368                        SendGameSelection,
6369                        NULL/* lose_ownership_proc */ ,
6370                        NULL/* transfer_done_proc */);
6371 }
6372
6373 /* function called when the data to Paste is ready */
6374 static void
6375 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
6376             Atom *type, XtPointer value, unsigned long *len, int *format)
6377 {
6378   FILE* f;
6379   if (value == NULL || *len == 0) {
6380     return; /* nothing had been selected to copy */
6381   }
6382   f = fopen(gamePasteFilename, "w");
6383   if (f == NULL) {
6384     DisplayError(_("Can't open temp file"), errno);
6385     return;
6386   }
6387   fwrite(value, 1, *len, f);
6388   fclose(f);
6389   XtFree(value);
6390   LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
6391 }
6392
6393 /* called when Paste Game button is pressed,
6394  * all parameters will be NULL */
6395 void PasteGameProc(w, event, prms, nprms)
6396   Widget w;
6397   XEvent *event;
6398   String *prms;
6399   Cardinal *nprms;
6400 {
6401     XtGetSelectionValue(menuBarWidget, XA_PRIMARY, XA_STRING,
6402       /* (XtSelectionCallbackProc) */ PasteGameCB,
6403       NULL, /* client_data passed to PasteGameCB */
6404
6405       /* better to use the time field from the event that triggered the
6406        * call to this function, but that isn't trivial to get
6407        */
6408       CurrentTime
6409     );
6410     return;
6411 }
6412
6413
6414 void AutoSaveGame()
6415 {
6416     SaveGameProc(NULL, NULL, NULL, NULL);
6417 }
6418
6419
6420 void QuitProc(w, event, prms, nprms)
6421      Widget w;
6422      XEvent *event;
6423      String *prms;
6424      Cardinal *nprms;
6425 {
6426     ExitEvent(0);
6427 }
6428
6429 void PauseProc(w, event, prms, nprms)
6430      Widget w;
6431      XEvent *event;
6432      String *prms;
6433      Cardinal *nprms;
6434 {
6435     PauseEvent();
6436 }
6437
6438
6439 void MachineBlackProc(w, event, prms, nprms)
6440      Widget w;
6441      XEvent *event;
6442      String *prms;
6443      Cardinal *nprms;
6444 {
6445     MachineBlackEvent();
6446 }
6447
6448 void MachineWhiteProc(w, event, prms, nprms)
6449      Widget w;
6450      XEvent *event;
6451      String *prms;
6452      Cardinal *nprms;
6453 {
6454     MachineWhiteEvent();
6455 }
6456
6457 void AnalyzeModeProc(w, event, prms, nprms)
6458      Widget w;
6459      XEvent *event;
6460      String *prms;
6461      Cardinal *nprms;
6462 {
6463     char buf[MSG_SIZ];
6464
6465     if (!first.analysisSupport) {
6466       sprintf(buf, _("%s does not support analysis"), first.tidy);
6467       DisplayError(buf, 0);
6468       return;
6469     }
6470     /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
6471     if (appData.icsActive) {
6472         if (gameMode != IcsObserving) {
6473             sprintf(buf,_("You are not observing a game"));
6474             DisplayError(buf, 0);
6475             /* secure check */
6476             if (appData.icsEngineAnalyze) {
6477                 if (appData.debugMode)
6478                     fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
6479                 ExitAnalyzeMode();
6480                 ModeHighlight();
6481             }
6482             return;
6483         }
6484         /* if enable, use want disable icsEngineAnalyze */
6485         if (appData.icsEngineAnalyze) {
6486                 ExitAnalyzeMode();
6487                 ModeHighlight();
6488                 return;
6489         }
6490         appData.icsEngineAnalyze = TRUE;
6491         if (appData.debugMode)
6492             fprintf(debugFP, _("ICS engine analyze starting... \n"));
6493     }
6494     if (!appData.showThinking)
6495       ShowThinkingProc(w,event,prms,nprms);
6496
6497     AnalyzeModeEvent();
6498 }
6499
6500 void AnalyzeFileProc(w, event, prms, nprms)
6501      Widget w;
6502      XEvent *event;
6503      String *prms;
6504      Cardinal *nprms;
6505 {
6506     if (!first.analysisSupport) {
6507       char buf[MSG_SIZ];
6508       sprintf(buf, _("%s does not support analysis"), first.tidy);
6509       DisplayError(buf, 0);
6510       return;
6511     }
6512     Reset(FALSE, TRUE);
6513
6514     if (!appData.showThinking)
6515       ShowThinkingProc(w,event,prms,nprms);
6516
6517     AnalyzeFileEvent();
6518     FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
6519     AnalysisPeriodicEvent(1);
6520 }
6521
6522 void TwoMachinesProc(w, event, prms, nprms)
6523      Widget w;
6524      XEvent *event;
6525      String *prms;
6526      Cardinal *nprms;
6527 {
6528     TwoMachinesEvent();
6529 }
6530
6531 void IcsClientProc(w, event, prms, nprms)
6532      Widget w;
6533      XEvent *event;
6534      String *prms;
6535      Cardinal *nprms;
6536 {
6537     IcsClientEvent();
6538 }
6539
6540 void EditGameProc(w, event, prms, nprms)
6541      Widget w;
6542      XEvent *event;
6543      String *prms;
6544      Cardinal *nprms;
6545 {
6546     EditGameEvent();
6547 }
6548
6549 void EditPositionProc(w, event, prms, nprms)
6550      Widget w;
6551      XEvent *event;
6552      String *prms;
6553      Cardinal *nprms;
6554 {
6555     EditPositionEvent();
6556 }
6557
6558 void TrainingProc(w, event, prms, nprms)
6559      Widget w;
6560      XEvent *event;
6561      String *prms;
6562      Cardinal *nprms;
6563 {
6564     TrainingEvent();
6565 }
6566
6567 void EditCommentProc(w, event, prms, nprms)
6568      Widget w;
6569      XEvent *event;
6570      String *prms;
6571      Cardinal *nprms;
6572 {
6573     if (editUp) {
6574         EditCommentPopDown();
6575     } else {
6576         EditCommentEvent();
6577     }
6578 }
6579
6580 void IcsInputBoxProc(w, event, prms, nprms)
6581      Widget w;
6582      XEvent *event;
6583      String *prms;
6584      Cardinal *nprms;
6585 {
6586     if (ICSInputBoxUp) {
6587         ICSInputBoxPopDown();
6588     } else {
6589         ICSInputBoxPopUp();
6590     }
6591 }
6592
6593 void AcceptProc(w, event, prms, nprms)
6594      Widget w;
6595      XEvent *event;
6596      String *prms;
6597      Cardinal *nprms;
6598 {
6599     AcceptEvent();
6600 }
6601
6602 void DeclineProc(w, event, prms, nprms)
6603      Widget w;
6604      XEvent *event;
6605      String *prms;
6606      Cardinal *nprms;
6607 {
6608     DeclineEvent();
6609 }
6610
6611 void RematchProc(w, event, prms, nprms)
6612      Widget w;
6613      XEvent *event;
6614      String *prms;
6615      Cardinal *nprms;
6616 {
6617     RematchEvent();
6618 }
6619
6620 void CallFlagProc(w, event, prms, nprms)
6621      Widget w;
6622      XEvent *event;
6623      String *prms;
6624      Cardinal *nprms;
6625 {
6626     CallFlagEvent();
6627 }
6628
6629 void DrawProc(w, event, prms, nprms)
6630      Widget w;
6631      XEvent *event;
6632      String *prms;
6633      Cardinal *nprms;
6634 {
6635     DrawEvent();
6636 }
6637
6638 void AbortProc(w, event, prms, nprms)
6639      Widget w;
6640      XEvent *event;
6641      String *prms;
6642      Cardinal *nprms;
6643 {
6644     AbortEvent();
6645 }
6646
6647 void AdjournProc(w, event, prms, nprms)
6648      Widget w;
6649      XEvent *event;
6650      String *prms;
6651      Cardinal *nprms;
6652 {
6653     AdjournEvent();
6654 }
6655
6656 void ResignProc(w, event, prms, nprms)
6657      Widget w;
6658      XEvent *event;
6659      String *prms;
6660      Cardinal *nprms;
6661 {
6662     ResignEvent();
6663 }
6664
6665 void AdjuWhiteProc(w, event, prms, nprms)
6666      Widget w;
6667      XEvent *event;
6668      String *prms;
6669      Cardinal *nprms;
6670 {
6671     UserAdjudicationEvent(+1);
6672 }
6673
6674 void AdjuBlackProc(w, event, prms, nprms)
6675      Widget w;
6676      XEvent *event;
6677      String *prms;
6678      Cardinal *nprms;
6679 {
6680     UserAdjudicationEvent(-1);
6681 }
6682
6683 void AdjuDrawProc(w, event, prms, nprms)
6684      Widget w;
6685      XEvent *event;
6686      String *prms;
6687      Cardinal *nprms;
6688 {
6689     UserAdjudicationEvent(0);
6690 }
6691
6692 void EnterKeyProc(w, event, prms, nprms)
6693      Widget w;
6694      XEvent *event;
6695      String *prms;
6696      Cardinal *nprms;
6697 {
6698     if (ICSInputBoxUp == True)
6699       ICSInputSendText();
6700 }
6701
6702 void StopObservingProc(w, event, prms, nprms)
6703      Widget w;
6704      XEvent *event;
6705      String *prms;
6706      Cardinal *nprms;
6707 {
6708     StopObservingEvent();
6709 }
6710
6711 void StopExaminingProc(w, event, prms, nprms)
6712      Widget w;
6713      XEvent *event;
6714      String *prms;
6715      Cardinal *nprms;
6716 {
6717     StopExaminingEvent();
6718 }
6719
6720
6721 void ForwardProc(w, event, prms, nprms)
6722      Widget w;
6723      XEvent *event;
6724      String *prms;
6725      Cardinal *nprms;
6726 {
6727     ForwardEvent();
6728 }
6729
6730
6731 void BackwardProc(w, event, prms, nprms)
6732      Widget w;
6733      XEvent *event;
6734      String *prms;
6735      Cardinal *nprms;
6736 {
6737     BackwardEvent();
6738 }
6739
6740 void ToStartProc(w, event, prms, nprms)
6741      Widget w;
6742      XEvent *event;
6743      String *prms;
6744      Cardinal *nprms;
6745 {
6746     ToStartEvent();
6747 }
6748
6749 void ToEndProc(w, event, prms, nprms)
6750      Widget w;
6751      XEvent *event;
6752      String *prms;
6753      Cardinal *nprms;
6754 {
6755     ToEndEvent();
6756 }
6757
6758 void RevertProc(w, event, prms, nprms)
6759      Widget w;
6760      XEvent *event;
6761      String *prms;
6762      Cardinal *nprms;
6763 {
6764     RevertEvent();
6765 }
6766
6767 void TruncateGameProc(w, event, prms, nprms)
6768      Widget w;
6769      XEvent *event;
6770      String *prms;
6771      Cardinal *nprms;
6772 {
6773     TruncateGameEvent();
6774 }
6775 void RetractMoveProc(w, event, prms, nprms)
6776      Widget w;
6777      XEvent *event;
6778      String *prms;
6779      Cardinal *nprms;
6780 {
6781     RetractMoveEvent();
6782 }
6783
6784 void MoveNowProc(w, event, prms, nprms)
6785      Widget w;
6786      XEvent *event;
6787      String *prms;
6788      Cardinal *nprms;
6789 {
6790     MoveNowEvent();
6791 }
6792
6793
6794 void AlwaysQueenProc(w, event, prms, nprms)
6795      Widget w;
6796      XEvent *event;
6797      String *prms;
6798      Cardinal *nprms;
6799 {
6800     Arg args[16];
6801
6802     appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6803
6804     if (appData.alwaysPromoteToQueen) {
6805         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6806     } else {
6807         XtSetArg(args[0], XtNleftBitmap, None);
6808     }
6809     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6810                 args, 1);
6811 }
6812
6813 void AnimateDraggingProc(w, event, prms, nprms)
6814      Widget w;
6815      XEvent *event;
6816      String *prms;
6817      Cardinal *nprms;
6818 {
6819     Arg args[16];
6820
6821     appData.animateDragging = !appData.animateDragging;
6822
6823     if (appData.animateDragging) {
6824         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6825         CreateAnimVars();
6826     } else {
6827         XtSetArg(args[0], XtNleftBitmap, None);
6828     }
6829     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6830                 args, 1);
6831 }
6832
6833 void AnimateMovingProc(w, event, prms, nprms)
6834      Widget w;
6835      XEvent *event;
6836      String *prms;
6837      Cardinal *nprms;
6838 {
6839     Arg args[16];
6840
6841     appData.animate = !appData.animate;
6842
6843     if (appData.animate) {
6844         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6845         CreateAnimVars();
6846     } else {
6847         XtSetArg(args[0], XtNleftBitmap, None);
6848     }
6849     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6850                 args, 1);
6851 }
6852
6853 void AutocommProc(w, event, prms, nprms)
6854      Widget w;
6855      XEvent *event;
6856      String *prms;
6857      Cardinal *nprms;
6858 {
6859     Arg args[16];
6860
6861     appData.autoComment = !appData.autoComment;
6862
6863     if (appData.autoComment) {
6864         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6865     } else {
6866         XtSetArg(args[0], XtNleftBitmap, None);
6867     }
6868     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6869                 args, 1);
6870 }
6871
6872
6873 void AutoflagProc(w, event, prms, nprms)
6874      Widget w;
6875      XEvent *event;
6876      String *prms;
6877      Cardinal *nprms;
6878 {
6879     Arg args[16];
6880
6881     appData.autoCallFlag = !appData.autoCallFlag;
6882
6883     if (appData.autoCallFlag) {
6884         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6885     } else {
6886         XtSetArg(args[0], XtNleftBitmap, None);
6887     }
6888     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6889                 args, 1);
6890 }
6891
6892 void AutoflipProc(w, event, prms, nprms)
6893      Widget w;
6894      XEvent *event;
6895      String *prms;
6896      Cardinal *nprms;
6897 {
6898     Arg args[16];
6899
6900     appData.autoFlipView = !appData.autoFlipView;
6901
6902     if (appData.autoFlipView) {
6903         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6904     } else {
6905         XtSetArg(args[0], XtNleftBitmap, None);
6906     }
6907     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6908                 args, 1);
6909 }
6910
6911 void AutobsProc(w, event, prms, nprms)
6912      Widget w;
6913      XEvent *event;
6914      String *prms;
6915      Cardinal *nprms;
6916 {
6917     Arg args[16];
6918
6919     appData.autoObserve = !appData.autoObserve;
6920
6921     if (appData.autoObserve) {
6922         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6923     } else {
6924         XtSetArg(args[0], XtNleftBitmap, None);
6925     }
6926     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6927                 args, 1);
6928 }
6929
6930 void AutoraiseProc(w, event, prms, nprms)
6931      Widget w;
6932      XEvent *event;
6933      String *prms;
6934      Cardinal *nprms;
6935 {
6936     Arg args[16];
6937
6938     appData.autoRaiseBoard = !appData.autoRaiseBoard;
6939
6940     if (appData.autoRaiseBoard) {
6941         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6942     } else {
6943         XtSetArg(args[0], XtNleftBitmap, None);
6944     }
6945     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6946                 args, 1);
6947 }
6948
6949 void AutosaveProc(w, event, prms, nprms)
6950      Widget w;
6951      XEvent *event;
6952      String *prms;
6953      Cardinal *nprms;
6954 {
6955     Arg args[16];
6956
6957     appData.autoSaveGames = !appData.autoSaveGames;
6958
6959     if (appData.autoSaveGames) {
6960         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6961     } else {
6962         XtSetArg(args[0], XtNleftBitmap, None);
6963     }
6964     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6965                 args, 1);
6966 }
6967
6968 void BlindfoldProc(w, event, prms, nprms)
6969      Widget w;
6970      XEvent *event;
6971      String *prms;
6972      Cardinal *nprms;
6973 {
6974     Arg args[16];
6975
6976     appData.blindfold = !appData.blindfold;
6977
6978     if (appData.blindfold) {
6979         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6980     } else {
6981         XtSetArg(args[0], XtNleftBitmap, None);
6982     }
6983     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6984                 args, 1);
6985
6986     DrawPosition(True, NULL);
6987 }
6988
6989 void TestLegalityProc(w, event, prms, nprms)
6990      Widget w;
6991      XEvent *event;
6992      String *prms;
6993      Cardinal *nprms;
6994 {
6995     Arg args[16];
6996
6997     appData.testLegality = !appData.testLegality;
6998
6999     if (appData.testLegality) {
7000         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
7001     } else {
7002         XtSetArg(args[0], XtNleftBitmap, None);
7003     }
7004     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
7005                 args, 1);
7006 }
7007
7008
7009 void FlashMovesProc(w, event, prms, nprms)
7010      Widget w;
7011      XEvent *event;
7012      String *prms;
7013      Cardinal *nprms;
7014 {
7015     Arg args[16];
7016
7017     if (appData.flashCount == 0) {
7018         appData.flashCount = 3;
7019     } else {
7020         appData.flashCount = -appData.flashCount;
7021     }
7022
7023     if (appData.flashCount > 0) {
7024         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
7025     } else {
7026         XtSetArg(args[0], XtNleftBitmap, None);
7027     }
7028     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
7029                 args, 1);
7030 }
7031
7032 void FlipViewProc(w, event, prms, nprms)
7033      Widget w;
7034      XEvent *event;
7035      String *prms;
7036      Cardinal *nprms;
7037 {
7038     flipView = !flipView;
7039     DrawPosition(True, NULL);
7040 }
7041
7042 void GetMoveListProc(w, event, prms, nprms)
7043      Widget w;
7044      XEvent *event;
7045      String *prms;
7046      Cardinal *nprms;
7047 {
7048     Arg args[16];
7049
7050     appData.getMoveList = !appData.getMoveList;
7051
7052     if (appData.getMoveList) {
7053         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
7054         GetMoveListEvent();
7055     } else {
7056         XtSetArg(args[0], XtNleftBitmap, None);
7057     }
7058     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
7059                 args, 1);
7060 }
7061
7062 #if HIGHDRAG
7063 void HighlightDraggingProc(w, event, prms, nprms)
7064      Widget w;
7065      XEvent *event;
7066      String *prms;
7067      Cardinal *nprms;
7068 {
7069     Arg args[16];
7070
7071     appData.highlightDragging = !appData.highlightDragging;
7072
7073     if (appData.highlightDragging) {
7074         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
7075     } else {
7076         XtSetArg(args[0], XtNleftBitmap, None);
7077     }
7078     XtSetValues(XtNameToWidget(menuBarWidget,
7079                                "menuOptions.Highlight Dragging"), args, 1);
7080 }
7081 #endif
7082
7083 void HighlightLastMoveProc(w, event, prms, nprms)
7084      Widget w;
7085      XEvent *event;
7086      String *prms;
7087      Cardinal *nprms;
7088 {
7089     Arg args[16];
7090
7091     appData.highlightLastMove = !appData.highlightLastMove;
7092
7093     if (appData.highlightLastMove) {
7094         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
7095     } else {
7096         XtSetArg(args[0], XtNleftBitmap, None);
7097     }
7098     XtSetValues(XtNameToWidget(menuBarWidget,
7099                                "menuOptions.Highlight Last Move"), args, 1);
7100 }
7101
7102 void IcsAlarmProc(w, event, prms, nprms)
7103      Widget w;
7104      XEvent *event;
7105      String *prms;
7106      Cardinal *nprms;
7107 {
7108     Arg args[16];
7109
7110     appData.icsAlarm = !appData.icsAlarm;
7111
7112     if (appData.icsAlarm) {
7113         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
7114     } else {
7115         XtSetArg(args[0], XtNleftBitmap, None);
7116     }
7117     XtSetValues(XtNameToWidget(menuBarWidget,
7118                                "menuOptions.ICS Alarm"), args, 1);
7119 }
7120
7121 void MoveSoundProc(w, event, prms, nprms)
7122      Widget w;
7123      XEvent *event;
7124      String *prms;
7125      Cardinal *nprms;
7126 {
7127     Arg args[16];
7128
7129     appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
7130
7131     if (appData.ringBellAfterMoves) {
7132         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
7133     } else {
7134         XtSetArg(args[0], XtNleftBitmap, None);
7135     }
7136     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
7137                 args, 1);
7138 }
7139
7140
7141 void OldSaveStyleProc(w, event, prms, nprms)
7142      Widget w;
7143      XEvent *event;
7144      String *prms;
7145      Cardinal *nprms;
7146 {
7147     Arg args[16];
7148
7149     appData.oldSaveStyle = !appData.oldSaveStyle;
7150
7151     if (appData.oldSaveStyle) {
7152         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
7153     } else {
7154         XtSetArg(args[0], XtNleftBitmap, None);
7155     }
7156     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
7157                 args, 1);
7158 }
7159
7160 void PeriodicUpdatesProc(w, event, prms, nprms)
7161      Widget w;
7162      XEvent *event;
7163      String *prms;
7164      Cardinal *nprms;
7165 {
7166     Arg args[16];
7167
7168     PeriodicUpdatesEvent(!appData.periodicUpdates);
7169
7170     if (appData.periodicUpdates) {
7171         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
7172     } else {
7173         XtSetArg(args[0], XtNleftBitmap, None);
7174     }
7175     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
7176                 args, 1);
7177 }
7178
7179 void PonderNextMoveProc(w, event, prms, nprms)
7180      Widget w;
7181      XEvent *event;
7182      String *prms;
7183      Cardinal *nprms;
7184 {
7185     Arg args[16];
7186
7187     PonderNextMoveEvent(!appData.ponderNextMove);
7188
7189     if (appData.ponderNextMove) {
7190         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
7191     } else {
7192         XtSetArg(args[0], XtNleftBitmap, None);
7193     }
7194     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
7195                 args, 1);
7196 }
7197
7198 void PopupExitMessageProc(w, event, prms, nprms)
7199      Widget w;
7200      XEvent *event;
7201      String *prms;
7202      Cardinal *nprms;
7203 {
7204     Arg args[16];
7205
7206     appData.popupExitMessage = !appData.popupExitMessage;
7207
7208     if (appData.popupExitMessage) {
7209         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
7210     } else {
7211         XtSetArg(args[0], XtNleftBitmap, None);
7212     }
7213     XtSetValues(XtNameToWidget(menuBarWidget,
7214                                "menuOptions.Popup Exit Message"), args, 1);
7215 }
7216
7217 void PopupMoveErrorsProc(w, event, prms, nprms)
7218      Widget w;
7219      XEvent *event;
7220      String *prms;
7221      Cardinal *nprms;
7222 {
7223     Arg args[16];
7224
7225     appData.popupMoveErrors = !appData.popupMoveErrors;
7226
7227     if (appData.popupMoveErrors) {
7228         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
7229     } else {
7230         XtSetArg(args[0], XtNleftBitmap, None);
7231     }
7232     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
7233                 args, 1);
7234 }
7235
7236 void PremoveProc(w, event, prms, nprms)
7237      Widget w;
7238      XEvent *event;
7239      String *prms;
7240      Cardinal *nprms;
7241 {
7242     Arg args[16];
7243
7244     appData.premove = !appData.premove;
7245
7246     if (appData.premove) {
7247         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
7248     } else {
7249         XtSetArg(args[0], XtNleftBitmap, None);
7250     }
7251     XtSetValues(XtNameToWidget(menuBarWidget,
7252                                "menuOptions.Premove"), args, 1);
7253 }
7254
7255 void QuietPlayProc(w, event, prms, nprms)
7256      Widget w;
7257      XEvent *event;
7258      String *prms;
7259      Cardinal *nprms;
7260 {
7261     Arg args[16];
7262
7263     appData.quietPlay = !appData.quietPlay;
7264
7265     if (appData.quietPlay) {
7266         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
7267     } else {
7268         XtSetArg(args[0], XtNleftBitmap, None);
7269     }
7270     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
7271                 args, 1);
7272 }
7273
7274 void ShowCoordsProc(w, event, prms, nprms)
7275      Widget w;
7276      XEvent *event;
7277      String *prms;
7278      Cardinal *nprms;
7279 {
7280     Arg args[16];
7281
7282     appData.showCoords = !appData.showCoords;
7283
7284     if (appData.showCoords) {
7285         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
7286     } else {
7287         XtSetArg(args[0], XtNleftBitmap, None);
7288     }
7289     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
7290                 args, 1);
7291
7292     DrawPosition(True, NULL);
7293 }
7294
7295 void ShowThinkingProc(w, event, prms, nprms)
7296      Widget w;
7297      XEvent *event;
7298      String *prms;
7299      Cardinal *nprms;
7300 {
7301     Arg args[16];
7302
7303     appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
7304     ShowThinkingEvent();
7305 #if 0
7306     // [HGM] thinking: currently no suc menu item; replaced by Hide Thinking (From Human)
7307     if (appData.showThinking) {
7308         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
7309     } else {
7310         XtSetArg(args[0], XtNleftBitmap, None);
7311     }
7312     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Thinking"),
7313                 args, 1);
7314 #endif
7315 }
7316
7317 void HideThinkingProc(w, event, prms, nprms)
7318      Widget w;
7319      XEvent *event;
7320      String *prms;
7321      Cardinal *nprms;
7322 {
7323     Arg args[16];
7324
7325     appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
7326     ShowThinkingEvent();
7327
7328     if (appData.hideThinkingFromHuman) {
7329         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
7330     } else {
7331         XtSetArg(args[0], XtNleftBitmap, None);
7332     }
7333     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
7334                 args, 1);
7335 }
7336
7337 void InfoProc(w, event, prms, nprms)
7338      Widget w;
7339      XEvent *event;
7340      String *prms;
7341      Cardinal *nprms;
7342 {
7343     char buf[MSG_SIZ];
7344     sprintf(buf, "xterm -e info --directory %s --directory . -f %s &",
7345             INFODIR, INFOFILE);
7346     system(buf);
7347 }
7348
7349 void ManProc(w, event, prms, nprms)
7350      Widget w;
7351      XEvent *event;
7352      String *prms;
7353      Cardinal *nprms;
7354 {
7355     char buf[MSG_SIZ];
7356     String name;
7357     if (nprms && *nprms > 0)
7358       name = prms[0];
7359     else
7360       name = "xboard";
7361     sprintf(buf, "xterm -e man %s &", name);
7362     system(buf);
7363 }
7364
7365 void HintProc(w, event, prms, nprms)
7366      Widget w;
7367      XEvent *event;
7368      String *prms;
7369      Cardinal *nprms;
7370 {
7371     HintEvent();
7372 }
7373
7374 void BookProc(w, event, prms, nprms)
7375      Widget w;
7376      XEvent *event;
7377      String *prms;
7378      Cardinal *nprms;
7379 {
7380     BookEvent();
7381 }
7382
7383 void AboutProc(w, event, prms, nprms)
7384      Widget w;
7385      XEvent *event;
7386      String *prms;
7387      Cardinal *nprms;
7388 {
7389     char buf[MSG_SIZ];
7390 #if ZIPPY
7391     char *zippy = " (with Zippy code)";
7392 #else
7393     char *zippy = "";
7394 #endif
7395     sprintf(buf, "%s%s\n\n%s\n%s\n%s\n%s\n\n%s%s\n%s",
7396             programVersion, zippy,
7397             "Copyright 1991 Digital Equipment Corporation",
7398             "Enhancements Copyright 1992-2009 Free Software Foundation",
7399             "Enhancements Copyright 2005 Alessandro Scotti",
7400             PRODUCT, " is free software and carries NO WARRANTY;",
7401             "see the file COPYING for more information.");
7402     ErrorPopUp(_("About XBoard"), buf, FALSE);
7403 }
7404
7405 void DebugProc(w, event, prms, nprms)
7406      Widget w;
7407      XEvent *event;
7408      String *prms;
7409      Cardinal *nprms;
7410 {
7411     appData.debugMode = !appData.debugMode;
7412 }
7413
7414 void AboutGameProc(w, event, prms, nprms)
7415      Widget w;
7416      XEvent *event;
7417      String *prms;
7418      Cardinal *nprms;
7419 {
7420     AboutGameEvent();
7421 }
7422
7423 void NothingProc(w, event, prms, nprms)
7424      Widget w;
7425      XEvent *event;
7426      String *prms;
7427      Cardinal *nprms;
7428 {
7429     return;
7430 }
7431
7432 void Iconify(w, event, prms, nprms)
7433      Widget w;
7434      XEvent *event;
7435      String *prms;
7436      Cardinal *nprms;
7437 {
7438     Arg args[16];
7439
7440     fromX = fromY = -1;
7441     XtSetArg(args[0], XtNiconic, True);
7442     XtSetValues(shellWidget, args, 1);
7443 }
7444
7445 void DisplayMessage(message, extMessage)
7446      char *message, *extMessage;
7447 {
7448     char buf[MSG_SIZ];
7449     Arg arg;
7450
7451     if (extMessage) {
7452         if (*message) {
7453             sprintf(buf, "%s  %s", message, extMessage);
7454             message = buf;
7455         } else {
7456             message = extMessage;
7457         }
7458     }
7459     XtSetArg(arg, XtNlabel, message);
7460     XtSetValues(messageWidget, &arg, 1);
7461 }
7462
7463 void DisplayTitle(text)
7464      char *text;
7465 {
7466     Arg args[16];
7467     int i;
7468     char title[MSG_SIZ];
7469     char icon[MSG_SIZ];
7470
7471     if (text == NULL) text = "";
7472
7473     if (appData.titleInWindow) {
7474         i = 0;
7475         XtSetArg(args[i], XtNlabel, text);   i++;
7476         XtSetValues(titleWidget, args, i);
7477     }
7478
7479     if (*text != NULLCHAR) {
7480         strcpy(icon, text);
7481         strcpy(title, text);
7482     } else if (appData.icsActive) {
7483         sprintf(icon, "%s", appData.icsHost);
7484         sprintf(title, "%s: %s", programName, appData.icsHost);
7485     } else if (appData.cmailGameName[0] != NULLCHAR) {
7486         sprintf(icon, "%s", "CMail");
7487         sprintf(title, "%s: %s", programName, "CMail");
7488 #ifdef GOTHIC
7489     // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7490     } else if (gameInfo.variant == VariantGothic) {
7491         strcpy(icon, programName);
7492         strcpy(title, GOTHIC);
7493 #endif
7494 #ifdef FALCON
7495     } else if (gameInfo.variant == VariantFalcon) {
7496         strcpy(icon, programName);
7497         strcpy(title, FALCON);
7498 #endif
7499     } else if (appData.noChessProgram) {
7500         strcpy(icon, programName);
7501         strcpy(title, programName);
7502     } else {
7503         strcpy(icon, first.tidy);
7504         sprintf(title, "%s: %s", programName, first.tidy);
7505     }
7506     i = 0;
7507     XtSetArg(args[i], XtNiconName, (XtArgVal) icon);    i++;
7508     XtSetArg(args[i], XtNtitle, (XtArgVal) title);      i++;
7509     XtSetValues(shellWidget, args, i);
7510 }
7511
7512
7513 void DisplayError(message, error)
7514      String message;
7515      int error;
7516 {
7517     char buf[MSG_SIZ];
7518
7519     if (error == 0) {
7520         if (appData.debugMode || appData.matchMode) {
7521             fprintf(stderr, "%s: %s\n", programName, message);
7522         }
7523     } else {
7524         if (appData.debugMode || appData.matchMode) {
7525             fprintf(stderr, "%s: %s: %s\n",
7526                     programName, message, strerror(error));
7527         }
7528         sprintf(buf, "%s: %s", message, strerror(error));
7529         message = buf;
7530     }
7531     ErrorPopUp(_("Error"), message, FALSE);
7532 }
7533
7534
7535 void DisplayMoveError(message)
7536      String message;
7537 {
7538     fromX = fromY = -1;
7539     ClearHighlights();
7540     DrawPosition(FALSE, NULL);
7541     if (appData.debugMode || appData.matchMode) {
7542         fprintf(stderr, "%s: %s\n", programName, message);
7543     }
7544     if (appData.popupMoveErrors) {
7545         ErrorPopUp(_("Error"), message, FALSE);
7546     } else {
7547         DisplayMessage(message, "");
7548     }
7549 }
7550
7551
7552 void DisplayFatalError(message, error, status)
7553      String message;
7554      int error, status;
7555 {
7556     char buf[MSG_SIZ];
7557
7558     errorExitStatus = status;
7559     if (error == 0) {
7560         fprintf(stderr, "%s: %s\n", programName, message);
7561     } else {
7562         fprintf(stderr, "%s: %s: %s\n",
7563                 programName, message, strerror(error));
7564         sprintf(buf, "%s: %s", message, strerror(error));
7565         message = buf;
7566     }
7567     if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7568       ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7569     } else {
7570       ExitEvent(status);
7571     }
7572 }
7573
7574 void DisplayInformation(message)
7575      String message;
7576 {
7577     ErrorPopDown();
7578     ErrorPopUp(_("Information"), message, TRUE);
7579 }
7580
7581 void DisplayNote(message)
7582      String message;
7583 {
7584     ErrorPopDown();
7585     ErrorPopUp(_("Note"), message, FALSE);
7586 }
7587
7588 static int
7589 NullXErrorCheck(dpy, error_event)
7590      Display *dpy;
7591      XErrorEvent *error_event;
7592 {
7593     return 0;
7594 }
7595
7596 void DisplayIcsInteractionTitle(message)
7597      String message;
7598 {
7599   if (oldICSInteractionTitle == NULL) {
7600     /* Magic to find the old window title, adapted from vim */
7601     char *wina = getenv("WINDOWID");
7602     if (wina != NULL) {
7603       Window win = (Window) atoi(wina);
7604       Window root, parent, *children;
7605       unsigned int nchildren;
7606       int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7607       for (;;) {
7608         if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7609         if (!XQueryTree(xDisplay, win, &root, &parent,
7610                         &children, &nchildren)) break;
7611         if (children) XFree((void *)children);
7612         if (parent == root || parent == 0) break;
7613         win = parent;
7614       }
7615       XSetErrorHandler(oldHandler);
7616     }
7617     if (oldICSInteractionTitle == NULL) {
7618       oldICSInteractionTitle = "xterm";
7619     }
7620   }
7621   printf("\033]0;%s\007", message);
7622   fflush(stdout);
7623 }
7624
7625 char pendingReplyPrefix[MSG_SIZ];
7626 ProcRef pendingReplyPR;
7627
7628 void AskQuestionProc(w, event, prms, nprms)
7629      Widget w;
7630      XEvent *event;
7631      String *prms;
7632      Cardinal *nprms;
7633 {
7634     if (*nprms != 4) {
7635         fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7636                 *nprms);
7637         return;
7638     }
7639     AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7640 }
7641
7642 void AskQuestionPopDown()
7643 {
7644     if (!askQuestionUp) return;
7645     XtPopdown(askQuestionShell);
7646     XtDestroyWidget(askQuestionShell);
7647     askQuestionUp = False;
7648 }
7649
7650 void AskQuestionReplyAction(w, event, prms, nprms)
7651      Widget w;
7652      XEvent *event;
7653      String *prms;
7654      Cardinal *nprms;
7655 {
7656     char buf[MSG_SIZ];
7657     int err;
7658     String reply;
7659
7660     reply = XawDialogGetValueString(w = XtParent(w));
7661     strcpy(buf, pendingReplyPrefix);
7662     if (*buf) strcat(buf, " ");
7663     strcat(buf, reply);
7664     strcat(buf, "\n");
7665     OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7666     AskQuestionPopDown();
7667
7668     if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7669 }
7670
7671 void AskQuestionCallback(w, client_data, call_data)
7672      Widget w;
7673      XtPointer client_data, call_data;
7674 {
7675     String name;
7676     Arg args[16];
7677
7678     XtSetArg(args[0], XtNlabel, &name);
7679     XtGetValues(w, args, 1);
7680
7681     if (strcmp(name, _("cancel")) == 0) {
7682         AskQuestionPopDown();
7683     } else {
7684         AskQuestionReplyAction(w, NULL, NULL, NULL);
7685     }
7686 }
7687
7688 void AskQuestion(title, question, replyPrefix, pr)
7689      char *title, *question, *replyPrefix;
7690      ProcRef pr;
7691 {
7692     Arg args[16];
7693     Widget popup, layout, dialog, edit;
7694     Window root, child;
7695     int x, y, i;
7696     int win_x, win_y;
7697     unsigned int mask;
7698
7699     strcpy(pendingReplyPrefix, replyPrefix);
7700     pendingReplyPR = pr;
7701
7702     i = 0;
7703     XtSetArg(args[i], XtNresizable, True); i++;
7704     XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7705     askQuestionShell = popup =
7706       XtCreatePopupShell(title, transientShellWidgetClass,
7707                          shellWidget, args, i);
7708
7709     layout =
7710       XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7711                             layoutArgs, XtNumber(layoutArgs));
7712
7713     i = 0;
7714     XtSetArg(args[i], XtNlabel, question); i++;
7715     XtSetArg(args[i], XtNvalue, ""); i++;
7716     XtSetArg(args[i], XtNborderWidth, 0); i++;
7717     dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7718                                    layout, args, i);
7719
7720     XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7721                        (XtPointer) dialog);
7722     XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7723                        (XtPointer) dialog);
7724
7725     XtRealizeWidget(popup);
7726     CatchDeleteWindow(popup, "AskQuestionPopDown");
7727
7728     XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7729                   &x, &y, &win_x, &win_y, &mask);
7730
7731     XtSetArg(args[0], XtNx, x - 10);
7732     XtSetArg(args[1], XtNy, y - 30);
7733     XtSetValues(popup, args, 2);
7734
7735     XtPopup(popup, XtGrabExclusive);
7736     askQuestionUp = True;
7737
7738     edit = XtNameToWidget(dialog, "*value");
7739     XtSetKeyboardFocus(popup, edit);
7740 }
7741
7742
7743 void
7744 PlaySound(name)
7745      char *name;
7746 {
7747   if (*name == NULLCHAR) {
7748     return;
7749   } else if (strcmp(name, "$") == 0) {
7750     putc(BELLCHAR, stderr);
7751   } else {
7752     char buf[2048];
7753     sprintf(buf, "%s '%s' &", appData.soundProgram, name);
7754     system(buf);
7755   }
7756 }
7757
7758 void
7759 RingBell()
7760 {
7761   PlaySound(appData.soundMove);
7762 }
7763
7764 void
7765 PlayIcsWinSound()
7766 {
7767   PlaySound(appData.soundIcsWin);
7768 }
7769
7770 void
7771 PlayIcsLossSound()
7772 {
7773   PlaySound(appData.soundIcsLoss);
7774 }
7775
7776 void
7777 PlayIcsDrawSound()
7778 {
7779   PlaySound(appData.soundIcsDraw);
7780 }
7781
7782 void
7783 PlayIcsUnfinishedSound()
7784 {
7785   PlaySound(appData.soundIcsUnfinished);
7786 }
7787
7788 void
7789 PlayAlarmSound()
7790 {
7791   PlaySound(appData.soundIcsAlarm);
7792 }
7793
7794 void
7795 EchoOn()
7796 {
7797     system("stty echo");
7798 }
7799
7800 void
7801 EchoOff()
7802 {
7803     system("stty -echo");
7804 }
7805
7806 void
7807 Colorize(cc, continuation)
7808      ColorClass cc;
7809      int continuation;
7810 {
7811     char buf[MSG_SIZ];
7812     int count, outCount, error;
7813
7814     if (textColors[(int)cc].bg > 0) {
7815         if (textColors[(int)cc].fg > 0) {
7816             sprintf(buf, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7817                     textColors[(int)cc].fg, textColors[(int)cc].bg);
7818         } else {
7819             sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7820                     textColors[(int)cc].bg);
7821         }
7822     } else {
7823         if (textColors[(int)cc].fg > 0) {
7824             sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7825                     textColors[(int)cc].fg);
7826         } else {
7827             sprintf(buf, "\033[0;%dm", textColors[(int)cc].attr);
7828         }
7829     }
7830     count = strlen(buf);
7831     outCount = OutputToProcess(NoProc, buf, count, &error);
7832     if (outCount < count) {
7833         DisplayFatalError(_("Error writing to display"), error, 1);
7834     }
7835
7836     if (continuation) return;
7837     switch (cc) {
7838     case ColorShout:
7839       PlaySound(appData.soundShout);
7840       break;
7841     case ColorSShout:
7842       PlaySound(appData.soundSShout);
7843       break;
7844     case ColorChannel1:
7845       PlaySound(appData.soundChannel1);
7846       break;
7847     case ColorChannel:
7848       PlaySound(appData.soundChannel);
7849       break;
7850     case ColorKibitz:
7851       PlaySound(appData.soundKibitz);
7852       break;
7853     case ColorTell:
7854       PlaySound(appData.soundTell);
7855       break;
7856     case ColorChallenge:
7857       PlaySound(appData.soundChallenge);
7858       break;
7859     case ColorRequest:
7860       PlaySound(appData.soundRequest);
7861       break;
7862     case ColorSeek:
7863       PlaySound(appData.soundSeek);
7864       break;
7865     case ColorNormal:
7866     case ColorNone:
7867     default:
7868       break;
7869     }
7870 }
7871
7872 char *UserName()
7873 {
7874     return getpwuid(getuid())->pw_name;
7875 }
7876
7877 static char *ExpandPathName(path)
7878      char *path;
7879 {
7880     static char static_buf[2000];
7881     char *d, *s, buf[2000];
7882     struct passwd *pwd;
7883
7884     s = path;
7885     d = static_buf;
7886
7887     while (*s && isspace(*s))
7888       ++s;
7889
7890     if (!*s) {
7891         *d = 0;
7892         return static_buf;
7893     }
7894
7895     if (*s == '~') {
7896         if (*(s+1) == '/') {
7897             strcpy(d, getpwuid(getuid())->pw_dir);
7898             strcat(d, s+1);
7899         }
7900         else {
7901             strcpy(buf, s+1);
7902             *strchr(buf, '/') = 0;
7903             pwd = getpwnam(buf);
7904             if (!pwd)
7905               {
7906                   fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7907                           buf, path);
7908                   return NULL;
7909               }
7910             strcpy(d, pwd->pw_dir);
7911             strcat(d, strchr(s+1, '/'));
7912         }
7913     }
7914     else
7915       strcpy(d, s);
7916
7917     return static_buf;
7918 }
7919
7920 char *HostName()
7921 {
7922     static char host_name[MSG_SIZ];
7923
7924 #if HAVE_GETHOSTNAME
7925     gethostname(host_name, MSG_SIZ);
7926     return host_name;
7927 #else  /* not HAVE_GETHOSTNAME */
7928 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7929     sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7930     return host_name;
7931 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7932     return "localhost";
7933 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7934 #endif /* not HAVE_GETHOSTNAME */
7935 }
7936
7937 XtIntervalId delayedEventTimerXID = 0;
7938 DelayedEventCallback delayedEventCallback = 0;
7939
7940 void
7941 FireDelayedEvent()
7942 {
7943     delayedEventTimerXID = 0;
7944     delayedEventCallback();
7945 }
7946
7947 void
7948 ScheduleDelayedEvent(cb, millisec)
7949      DelayedEventCallback cb; long millisec;
7950 {
7951     delayedEventCallback = cb;
7952     delayedEventTimerXID =
7953       XtAppAddTimeOut(appContext, millisec,
7954                       (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7955 }
7956
7957 DelayedEventCallback
7958 GetDelayedEvent()
7959 {
7960   if (delayedEventTimerXID) {
7961     return delayedEventCallback;
7962   } else {
7963     return NULL;
7964   }
7965 }
7966
7967 void
7968 CancelDelayedEvent()
7969 {
7970   if (delayedEventTimerXID) {
7971     XtRemoveTimeOut(delayedEventTimerXID);
7972     delayedEventTimerXID = 0;
7973   }
7974 }
7975
7976 XtIntervalId loadGameTimerXID = 0;
7977
7978 int LoadGameTimerRunning()
7979 {
7980     return loadGameTimerXID != 0;
7981 }
7982
7983 int StopLoadGameTimer()
7984 {
7985     if (loadGameTimerXID != 0) {
7986         XtRemoveTimeOut(loadGameTimerXID);
7987         loadGameTimerXID = 0;
7988         return TRUE;
7989     } else {
7990         return FALSE;
7991     }
7992 }
7993
7994 void
7995 LoadGameTimerCallback(arg, id)
7996      XtPointer arg;
7997      XtIntervalId *id;
7998 {
7999     loadGameTimerXID = 0;
8000     AutoPlayGameLoop();
8001 }
8002
8003 void
8004 StartLoadGameTimer(millisec)
8005      long millisec;
8006 {
8007     loadGameTimerXID =
8008       XtAppAddTimeOut(appContext, millisec,
8009                       (XtTimerCallbackProc) LoadGameTimerCallback,
8010                       (XtPointer) 0);
8011 }
8012
8013 XtIntervalId analysisClockXID = 0;
8014
8015 void
8016 AnalysisClockCallback(arg, id)
8017      XtPointer arg;
8018      XtIntervalId *id;
8019 {
8020     if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
8021          || appData.icsEngineAnalyze) { // [DM]
8022         AnalysisPeriodicEvent(0);
8023         StartAnalysisClock();
8024     }
8025 }
8026
8027 void
8028 StartAnalysisClock()
8029 {
8030     analysisClockXID =
8031       XtAppAddTimeOut(appContext, 2000,
8032                       (XtTimerCallbackProc) AnalysisClockCallback,
8033                       (XtPointer) 0);
8034 }
8035
8036 XtIntervalId clockTimerXID = 0;
8037
8038 int ClockTimerRunning()
8039 {
8040     return clockTimerXID != 0;
8041 }
8042
8043 int StopClockTimer()
8044 {
8045     if (clockTimerXID != 0) {
8046         XtRemoveTimeOut(clockTimerXID);
8047         clockTimerXID = 0;
8048         return TRUE;
8049     } else {
8050         return FALSE;
8051     }
8052 }
8053
8054 void
8055 ClockTimerCallback(arg, id)
8056      XtPointer arg;
8057      XtIntervalId *id;
8058 {
8059     clockTimerXID = 0;
8060     DecrementClocks();
8061 }
8062
8063 void
8064 StartClockTimer(millisec)
8065      long millisec;
8066 {
8067     clockTimerXID =
8068       XtAppAddTimeOut(appContext, millisec,
8069                       (XtTimerCallbackProc) ClockTimerCallback,
8070                       (XtPointer) 0);
8071 }
8072
8073 void
8074 DisplayTimerLabel(w, color, timer, highlight)
8075      Widget w;
8076      char *color;
8077      long timer;
8078      int highlight;
8079 {
8080     char buf[MSG_SIZ];
8081     Arg args[16];
8082
8083     if (appData.clockMode) {
8084         sprintf(buf, "%s: %s", color, TimeString(timer));
8085         XtSetArg(args[0], XtNlabel, buf);
8086     } else {
8087         sprintf(buf, "%s  ", color);
8088         XtSetArg(args[0], XtNlabel, buf);
8089     }
8090
8091     if (highlight) {
8092         XtSetArg(args[1], XtNbackground, timerForegroundPixel);
8093         XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
8094     } else {
8095         XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
8096         XtSetArg(args[2], XtNforeground, timerForegroundPixel);
8097     }
8098
8099     XtSetValues(w, args, 3);
8100 }
8101
8102 void
8103 DisplayWhiteClock(timeRemaining, highlight)
8104      long timeRemaining;
8105      int highlight;
8106 {
8107     Arg args[16];
8108
8109     if(appData.noGUI) return;
8110     DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
8111     if (highlight && iconPixmap == bIconPixmap) {
8112         iconPixmap = wIconPixmap;
8113         XtSetArg(args[0], XtNiconPixmap, iconPixmap);
8114         XtSetValues(shellWidget, args, 1);
8115     }
8116 }
8117
8118 void
8119 DisplayBlackClock(timeRemaining, highlight)
8120      long timeRemaining;
8121      int highlight;
8122 {
8123     Arg args[16];
8124
8125     if(appData.noGUI) return;
8126     DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
8127     if (highlight && iconPixmap == wIconPixmap) {
8128         iconPixmap = bIconPixmap;
8129         XtSetArg(args[0], XtNiconPixmap, iconPixmap);
8130         XtSetValues(shellWidget, args, 1);
8131     }
8132 }
8133
8134 #define CPNone 0
8135 #define CPReal 1
8136 #define CPComm 2
8137 #define CPSock 3
8138 #define CPLoop 4
8139 typedef int CPKind;
8140
8141 typedef struct {
8142     CPKind kind;
8143     int pid;
8144     int fdTo, fdFrom;
8145 } ChildProc;
8146
8147
8148 int StartChildProcess(cmdLine, dir, pr)
8149      char *cmdLine;
8150      char *dir;
8151      ProcRef *pr;
8152 {
8153     char *argv[64], *p;
8154     int i, pid;
8155     int to_prog[2], from_prog[2];
8156     ChildProc *cp;
8157     char buf[MSG_SIZ];
8158
8159     if (appData.debugMode) {
8160         fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
8161     }
8162
8163     /* We do NOT feed the cmdLine to the shell; we just
8164        parse it into blank-separated arguments in the
8165        most simple-minded way possible.
8166        */
8167     i = 0;
8168     strcpy(buf, cmdLine);
8169     p = buf;
8170     for (;;) {
8171         argv[i++] = p;
8172         p = strchr(p, ' ');
8173         if (p == NULL) break;
8174         *p++ = NULLCHAR;
8175     }
8176     argv[i] = NULL;
8177
8178     SetUpChildIO(to_prog, from_prog);
8179
8180     if ((pid = fork()) == 0) {
8181         /* Child process */
8182         // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
8183         close(to_prog[1]);     // first close the unused pipe ends
8184         close(from_prog[0]);
8185         dup2(to_prog[0], 0);   // to_prog was created first, nd is the only one to use 0 or 1
8186         dup2(from_prog[1], 1);
8187         if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
8188         close(from_prog[1]);                   // and closing again loses one of the pipes!
8189         if(fileno(stderr) >= 2) // better safe than sorry...
8190                 dup2(1, fileno(stderr)); /* force stderr to the pipe */
8191
8192         if (dir[0] != NULLCHAR && chdir(dir) != 0) {
8193             perror(dir);
8194             exit(1);
8195         }
8196
8197         nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
8198
8199         execvp(argv[0], argv);
8200
8201         /* If we get here, exec failed */
8202         perror(argv[0]);
8203         exit(1);
8204     }
8205
8206     /* Parent process */
8207     close(to_prog[0]);
8208     close(from_prog[1]);
8209
8210     cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8211     cp->kind = CPReal;
8212     cp->pid = pid;
8213     cp->fdFrom = from_prog[0];
8214     cp->fdTo = to_prog[1];
8215     *pr = (ProcRef) cp;
8216     return 0;
8217 }
8218
8219 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
8220 static RETSIGTYPE AlarmCallBack(int n)
8221 {
8222     return;
8223 }
8224
8225 void
8226 DestroyChildProcess(pr, signalType)
8227      ProcRef pr;
8228      int signalType;
8229 {
8230     ChildProc *cp = (ChildProc *) pr;
8231
8232     if (cp->kind != CPReal) return;
8233     cp->kind = CPNone;
8234     if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
8235         signal(SIGALRM, AlarmCallBack);
8236         alarm(3);
8237         if(wait((int *) 0) == -1) { // process does not terminate on its own accord
8238             kill(cp->pid, SIGKILL); // kill it forcefully
8239             wait((int *) 0);        // and wait again
8240         }
8241     } else {
8242         if (signalType) {
8243             kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
8244         }
8245         /* Process is exiting either because of the kill or because of
8246            a quit command sent by the backend; either way, wait for it to die.
8247         */
8248         wait((int *) 0);
8249     }
8250     close(cp->fdFrom);
8251     close(cp->fdTo);
8252 }
8253
8254 void
8255 InterruptChildProcess(pr)
8256      ProcRef pr;
8257 {
8258     ChildProc *cp = (ChildProc *) pr;
8259
8260     if (cp->kind != CPReal) return;
8261     (void) kill(cp->pid, SIGINT); /* stop it thinking */
8262 }
8263
8264 int OpenTelnet(host, port, pr)
8265      char *host;
8266      char *port;
8267      ProcRef *pr;
8268 {
8269     char cmdLine[MSG_SIZ];
8270
8271     if (port[0] == NULLCHAR) {
8272         sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
8273     } else {
8274         sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
8275     }
8276     return StartChildProcess(cmdLine, "", pr);
8277 }
8278
8279 int OpenTCP(host, port, pr)
8280      char *host;
8281      char *port;
8282      ProcRef *pr;
8283 {
8284 #if OMIT_SOCKETS
8285     DisplayFatalError(_("Socket support is not configured in"), 0, 2);
8286 #else  /* !OMIT_SOCKETS */
8287     int s;
8288     struct sockaddr_in sa;
8289     struct hostent     *hp;
8290     unsigned short uport;
8291     ChildProc *cp;
8292
8293     if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
8294         return errno;
8295     }
8296
8297     memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
8298     sa.sin_family = AF_INET;
8299     sa.sin_addr.s_addr = INADDR_ANY;
8300     uport = (unsigned short) 0;
8301     sa.sin_port = htons(uport);
8302     if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
8303         return errno;
8304     }
8305
8306     memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
8307     if (!(hp = gethostbyname(host))) {
8308         int b0, b1, b2, b3;
8309         if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
8310             hp = (struct hostent *) calloc(1, sizeof(struct hostent));
8311             hp->h_addrtype = AF_INET;
8312             hp->h_length = 4;
8313             hp->h_addr_list = (char **) calloc(2, sizeof(char *));
8314             hp->h_addr_list[0] = (char *) malloc(4);
8315             hp->h_addr_list[0][0] = b0;
8316             hp->h_addr_list[0][1] = b1;
8317             hp->h_addr_list[0][2] = b2;
8318             hp->h_addr_list[0][3] = b3;
8319         } else {
8320             return ENOENT;
8321         }
8322     }
8323     sa.sin_family = hp->h_addrtype;
8324     uport = (unsigned short) atoi(port);
8325     sa.sin_port = htons(uport);
8326     memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
8327
8328     if (connect(s, (struct sockaddr *) &sa,
8329                 sizeof(struct sockaddr_in)) < 0) {
8330         return errno;
8331     }
8332
8333     cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8334     cp->kind = CPSock;
8335     cp->pid = 0;
8336     cp->fdFrom = s;
8337     cp->fdTo = s;
8338     *pr = (ProcRef) cp;
8339
8340 #endif /* !OMIT_SOCKETS */
8341
8342     return 0;
8343 }
8344
8345 int OpenCommPort(name, pr)
8346      char *name;
8347      ProcRef *pr;
8348 {
8349     int fd;
8350     ChildProc *cp;
8351
8352     fd = open(name, 2, 0);
8353     if (fd < 0) return errno;
8354
8355     cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8356     cp->kind = CPComm;
8357     cp->pid = 0;
8358     cp->fdFrom = fd;
8359     cp->fdTo = fd;
8360     *pr = (ProcRef) cp;
8361
8362     return 0;
8363 }
8364
8365 int OpenLoopback(pr)
8366      ProcRef *pr;
8367 {
8368     ChildProc *cp;
8369     int to[2], from[2];
8370
8371     SetUpChildIO(to, from);
8372
8373     cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8374     cp->kind = CPLoop;
8375     cp->pid = 0;
8376     cp->fdFrom = to[0];         /* note not from[0]; we are doing a loopback */
8377     cp->fdTo = to[1];
8378     *pr = (ProcRef) cp;
8379
8380     return 0;
8381 }
8382
8383 int OpenRcmd(host, user, cmd, pr)
8384      char *host, *user, *cmd;
8385      ProcRef *pr;
8386 {
8387     DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
8388     return -1;
8389 }
8390
8391 #define INPUT_SOURCE_BUF_SIZE 8192
8392
8393 typedef struct {
8394     CPKind kind;
8395     int fd;
8396     int lineByLine;
8397     char *unused;
8398     InputCallback func;
8399     XtInputId xid;
8400     char buf[INPUT_SOURCE_BUF_SIZE];
8401     VOIDSTAR closure;
8402 } InputSource;
8403
8404 void
8405 DoInputCallback(closure, source, xid)
8406      caddr_t closure;
8407      int *source;
8408      XtInputId *xid;
8409 {
8410     InputSource *is = (InputSource *) closure;
8411     int count;
8412     int error;
8413     char *p, *q;
8414
8415     if (is->lineByLine) {
8416         count = read(is->fd, is->unused,
8417                      INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
8418         if (count <= 0) {
8419             (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
8420             return;
8421         }
8422         is->unused += count;
8423         p = is->buf;
8424         while (p < is->unused) {
8425             q = memchr(p, '\n', is->unused - p);
8426             if (q == NULL) break;
8427             q++;
8428             (is->func)(is, is->closure, p, q - p, 0);
8429             p = q;
8430         }
8431         q = is->buf;
8432         while (p < is->unused) {
8433             *q++ = *p++;
8434         }
8435         is->unused = q;
8436     } else {
8437         count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8438         if (count == -1)
8439           error = errno;
8440         else
8441           error = 0;
8442         (is->func)(is, is->closure, is->buf, count, error);
8443     }
8444 }
8445
8446 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8447      ProcRef pr;
8448      int lineByLine;
8449      InputCallback func;
8450      VOIDSTAR closure;
8451 {
8452     InputSource *is;
8453     ChildProc *cp = (ChildProc *) pr;
8454
8455     is = (InputSource *) calloc(1, sizeof(InputSource));
8456     is->lineByLine = lineByLine;
8457     is->func = func;
8458     if (pr == NoProc) {
8459         is->kind = CPReal;
8460         is->fd = fileno(stdin);
8461     } else {
8462         is->kind = cp->kind;
8463         is->fd = cp->fdFrom;
8464     }
8465     if (lineByLine) {
8466         is->unused = is->buf;
8467     }
8468
8469     is->xid = XtAppAddInput(appContext, is->fd,
8470                             (XtPointer) (XtInputReadMask),
8471                             (XtInputCallbackProc) DoInputCallback,
8472                             (XtPointer) is);
8473     is->closure = closure;
8474     return (InputSourceRef) is;
8475 }
8476
8477 void
8478 RemoveInputSource(isr)
8479      InputSourceRef isr;
8480 {
8481     InputSource *is = (InputSource *) isr;
8482
8483     if (is->xid == 0) return;
8484     XtRemoveInput(is->xid);
8485     is->xid = 0;
8486 }
8487
8488 int OutputToProcess(pr, message, count, outError)
8489      ProcRef pr;
8490      char *message;
8491      int count;
8492      int *outError;
8493 {
8494     ChildProc *cp = (ChildProc *) pr;
8495     int outCount;
8496
8497     if (pr == NoProc)
8498       outCount = fwrite(message, 1, count, stdout);
8499     else
8500       outCount = write(cp->fdTo, message, count);
8501
8502     if (outCount == -1)
8503       *outError = errno;
8504     else
8505       *outError = 0;
8506
8507     return outCount;
8508 }
8509
8510 /* Output message to process, with "ms" milliseconds of delay
8511    between each character. This is needed when sending the logon
8512    script to ICC, which for some reason doesn't like the
8513    instantaneous send. */
8514 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8515      ProcRef pr;
8516      char *message;
8517      int count;
8518      int *outError;
8519      long msdelay;
8520 {
8521     ChildProc *cp = (ChildProc *) pr;
8522     int outCount = 0;
8523     int r;
8524
8525     while (count--) {
8526         r = write(cp->fdTo, message++, 1);
8527         if (r == -1) {
8528             *outError = errno;
8529             return outCount;
8530         }
8531         ++outCount;
8532         if (msdelay >= 0)
8533           TimeDelay(msdelay);
8534     }
8535
8536     return outCount;
8537 }
8538
8539 /****   Animation code by Hugh Fisher, DCS, ANU.
8540
8541         Known problem: if a window overlapping the board is
8542         moved away while a piece is being animated underneath,
8543         the newly exposed area won't be updated properly.
8544         I can live with this.
8545
8546         Known problem: if you look carefully at the animation
8547         of pieces in mono mode, they are being drawn as solid
8548         shapes without interior detail while moving. Fixing
8549         this would be a major complication for minimal return.
8550 ****/
8551
8552 /*      Masks for XPM pieces. Black and white pieces can have
8553         different shapes, but in the interest of retaining my
8554         sanity pieces must have the same outline on both light
8555         and dark squares, and all pieces must use the same
8556         background square colors/images.                */
8557
8558 static void
8559 CreateAnimMasks (pieceDepth)
8560      int pieceDepth;
8561 {
8562   ChessSquare   piece;
8563   Pixmap        buf;
8564   GC            bufGC, maskGC;
8565   int           kind, n;
8566   unsigned long plane;
8567   XGCValues     values;
8568
8569   /* Need a bitmap just to get a GC with right depth */
8570   buf = XCreatePixmap(xDisplay, xBoardWindow,
8571                         8, 8, 1);
8572   values.foreground = 1;
8573   values.background = 0;
8574   /* Don't use XtGetGC, not read only */
8575   maskGC = XCreateGC(xDisplay, buf,
8576                     GCForeground | GCBackground, &values);
8577   XFreePixmap(xDisplay, buf);
8578
8579   buf = XCreatePixmap(xDisplay, xBoardWindow,
8580                       squareSize, squareSize, pieceDepth);
8581   values.foreground = XBlackPixel(xDisplay, xScreen);
8582   values.background = XWhitePixel(xDisplay, xScreen);
8583   bufGC = XCreateGC(xDisplay, buf,
8584                     GCForeground | GCBackground, &values);
8585
8586   for (piece = WhitePawn; piece <= BlackKing; piece++) {
8587     /* Begin with empty mask */
8588     xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8589                                  squareSize, squareSize, 1);
8590     XSetFunction(xDisplay, maskGC, GXclear);
8591     XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8592                    0, 0, squareSize, squareSize);
8593
8594     /* Take a copy of the piece */
8595     if (White(piece))
8596       kind = 0;
8597     else
8598       kind = 2;
8599     XSetFunction(xDisplay, bufGC, GXcopy);
8600     XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8601               buf, bufGC,
8602               0, 0, squareSize, squareSize, 0, 0);
8603
8604     /* XOR the background (light) over the piece */
8605     XSetFunction(xDisplay, bufGC, GXxor);
8606     if (useImageSqs)
8607       XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8608                 0, 0, squareSize, squareSize, 0, 0);
8609     else {
8610       XSetForeground(xDisplay, bufGC, lightSquareColor);
8611       XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8612     }
8613
8614     /* We now have an inverted piece image with the background
8615        erased. Construct mask by just selecting all the non-zero
8616        pixels - no need to reconstruct the original image.      */
8617     XSetFunction(xDisplay, maskGC, GXor);
8618     plane = 1;
8619     /* Might be quicker to download an XImage and create bitmap
8620        data from it rather than this N copies per piece, but it
8621        only takes a fraction of a second and there is a much
8622        longer delay for loading the pieces.             */
8623     for (n = 0; n < pieceDepth; n ++) {
8624       XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8625                  0, 0, squareSize, squareSize,
8626                  0, 0, plane);
8627       plane = plane << 1;
8628     }
8629   }
8630   /* Clean up */
8631   XFreePixmap(xDisplay, buf);
8632   XFreeGC(xDisplay, bufGC);
8633   XFreeGC(xDisplay, maskGC);
8634 }
8635
8636 static void
8637 InitAnimState (anim, info)
8638   AnimState * anim;
8639   XWindowAttributes * info;
8640 {
8641   XtGCMask  mask;
8642   XGCValues values;
8643
8644   /* Each buffer is square size, same depth as window */
8645   anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8646                         squareSize, squareSize, info->depth);
8647   anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8648                         squareSize, squareSize, info->depth);
8649
8650   /* Create a plain GC for blitting */
8651   mask = GCForeground | GCBackground | GCFunction |
8652          GCPlaneMask | GCGraphicsExposures;
8653   values.foreground = XBlackPixel(xDisplay, xScreen);
8654   values.background = XWhitePixel(xDisplay, xScreen);
8655   values.function   = GXcopy;
8656   values.plane_mask = AllPlanes;
8657   values.graphics_exposures = False;
8658   anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8659
8660   /* Piece will be copied from an existing context at
8661      the start of each new animation/drag. */
8662   anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8663
8664   /* Outline will be a read-only copy of an existing */
8665   anim->outlineGC = None;
8666 }
8667
8668 static void
8669 CreateAnimVars ()
8670 {
8671   static int done = 0;
8672   XWindowAttributes info;
8673
8674   if (done) return;
8675   done = 1;
8676   XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8677
8678   InitAnimState(&game, &info);
8679   InitAnimState(&player, &info);
8680
8681   /* For XPM pieces, we need bitmaps to use as masks. */
8682   if (useImages)
8683     CreateAnimMasks(info.depth);
8684 }
8685
8686 #ifndef HAVE_USLEEP
8687
8688 static Boolean frameWaiting;
8689
8690 static RETSIGTYPE FrameAlarm (sig)
8691      int sig;
8692 {
8693   frameWaiting = False;
8694   /* In case System-V style signals.  Needed?? */
8695   signal(SIGALRM, FrameAlarm);
8696 }
8697
8698 static void
8699 FrameDelay (time)
8700      int time;
8701 {
8702   struct itimerval delay;
8703
8704   XSync(xDisplay, False);
8705
8706   if (time > 0) {
8707     frameWaiting = True;
8708     signal(SIGALRM, FrameAlarm);
8709     delay.it_interval.tv_sec =
8710       delay.it_value.tv_sec = time / 1000;
8711     delay.it_interval.tv_usec =
8712       delay.it_value.tv_usec = (time % 1000) * 1000;
8713     setitimer(ITIMER_REAL, &delay, NULL);
8714 #if 0
8715     /* Ugh -- busy-wait! --tpm */
8716     while (frameWaiting);
8717 #else
8718     while (frameWaiting) pause();
8719 #endif
8720     delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8721     delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8722     setitimer(ITIMER_REAL, &delay, NULL);
8723   }
8724 }
8725
8726 #else
8727
8728 static void
8729 FrameDelay (time)
8730      int time;
8731 {
8732   XSync(xDisplay, False);
8733   if (time > 0)
8734     usleep(time * 1000);
8735 }
8736
8737 #endif
8738
8739 /*      Convert board position to corner of screen rect and color       */
8740
8741 static void
8742 ScreenSquare(column, row, pt, color)
8743      int column; int row; XPoint * pt; int * color;
8744 {
8745   if (flipView) {
8746     pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8747     pt->y = lineGap + row * (squareSize + lineGap);
8748   } else {
8749     pt->x = lineGap + column * (squareSize + lineGap);
8750     pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8751   }
8752   *color = SquareColor(row, column);
8753 }
8754
8755 /*      Convert window coords to square                 */
8756
8757 static void
8758 BoardSquare(x, y, column, row)
8759      int x; int y; int * column; int * row;
8760 {
8761   *column = EventToSquare(x, BOARD_WIDTH);
8762   if (flipView && *column >= 0)
8763     *column = BOARD_WIDTH - 1 - *column;
8764   *row = EventToSquare(y, BOARD_HEIGHT);
8765   if (!flipView && *row >= 0)
8766     *row = BOARD_HEIGHT - 1 - *row;
8767 }
8768
8769 /*   Utilities  */
8770
8771 #undef Max  /* just in case */
8772 #undef Min
8773 #define Max(a, b) ((a) > (b) ? (a) : (b))
8774 #define Min(a, b) ((a) < (b) ? (a) : (b))
8775
8776 static void
8777 SetRect(rect, x, y, width, height)
8778      XRectangle * rect; int x; int y; int width; int height;
8779 {
8780   rect->x = x;
8781   rect->y = y;
8782   rect->width  = width;
8783   rect->height = height;
8784 }
8785
8786 /*      Test if two frames overlap. If they do, return
8787         intersection rect within old and location of
8788         that rect within new. */
8789
8790 static Boolean
8791 Intersect(old, new, size, area, pt)
8792      XPoint * old; XPoint * new;
8793      int size; XRectangle * area; XPoint * pt;
8794 {
8795   if (old->x > new->x + size || new->x > old->x + size ||
8796       old->y > new->y + size || new->y > old->y + size) {
8797     return False;
8798   } else {
8799     SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8800             size - abs(old->x - new->x), size - abs(old->y - new->y));
8801     pt->x = Max(old->x - new->x, 0);
8802     pt->y = Max(old->y - new->y, 0);
8803     return True;
8804   }
8805 }
8806
8807 /*      For two overlapping frames, return the rect(s)
8808         in the old that do not intersect with the new.   */
8809
8810 static void
8811 CalcUpdateRects(old, new, size, update, nUpdates)
8812      XPoint * old; XPoint * new; int size;
8813      XRectangle update[]; int * nUpdates;
8814 {
8815   int        count;
8816
8817   /* If old = new (shouldn't happen) then nothing to draw */
8818   if (old->x == new->x && old->y == new->y) {
8819     *nUpdates = 0;
8820     return;
8821   }
8822   /* Work out what bits overlap. Since we know the rects
8823      are the same size we don't need a full intersect calc. */
8824   count = 0;
8825   /* Top or bottom edge? */
8826   if (new->y > old->y) {
8827     SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8828     count ++;
8829   } else if (old->y > new->y) {
8830     SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8831                               size, old->y - new->y);
8832     count ++;
8833   }
8834   /* Left or right edge - don't overlap any update calculated above. */
8835   if (new->x > old->x) {
8836     SetRect(&(update[count]), old->x, Max(new->y, old->y),
8837                               new->x - old->x, size - abs(new->y - old->y));
8838     count ++;
8839   } else if (old->x > new->x) {
8840     SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8841                               old->x - new->x, size - abs(new->y - old->y));
8842     count ++;
8843   }
8844   /* Done */
8845   *nUpdates = count;
8846 }
8847
8848 /*      Generate a series of frame coords from start->mid->finish.
8849         The movement rate doubles until the half way point is
8850         reached, then halves back down to the final destination,
8851         which gives a nice slow in/out effect. The algorithmn
8852         may seem to generate too many intermediates for short
8853         moves, but remember that the purpose is to attract the
8854         viewers attention to the piece about to be moved and
8855         then to where it ends up. Too few frames would be less
8856         noticeable.                                             */
8857
8858 static void
8859 Tween(start, mid, finish, factor, frames, nFrames)
8860      XPoint * start; XPoint * mid;
8861      XPoint * finish; int factor;
8862      XPoint frames[]; int * nFrames;
8863 {
8864   int fraction, n, count;
8865
8866   count = 0;
8867
8868   /* Slow in, stepping 1/16th, then 1/8th, ... */
8869   fraction = 1;
8870   for (n = 0; n < factor; n++)
8871     fraction *= 2;
8872   for (n = 0; n < factor; n++) {
8873     frames[count].x = start->x + (mid->x - start->x) / fraction;
8874     frames[count].y = start->y + (mid->y - start->y) / fraction;
8875     count ++;
8876     fraction = fraction / 2;
8877   }
8878
8879   /* Midpoint */
8880   frames[count] = *mid;
8881   count ++;
8882
8883   /* Slow out, stepping 1/2, then 1/4, ... */
8884   fraction = 2;
8885   for (n = 0; n < factor; n++) {
8886     frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8887     frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8888     count ++;
8889     fraction = fraction * 2;
8890   }
8891   *nFrames = count;
8892 }
8893
8894 /*      Draw a piece on the screen without disturbing what's there      */
8895
8896 static void
8897 SelectGCMask(piece, clip, outline, mask)
8898      ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8899 {
8900   GC source;
8901
8902   /* Bitmap for piece being moved. */
8903   if (appData.monoMode) {
8904       *mask = *pieceToSolid(piece);
8905   } else if (useImages) {
8906 #if HAVE_LIBXPM
8907       *mask = xpmMask[piece];
8908 #else
8909       *mask = ximMaskPm[piece%(int)BlackPawn];
8910 #endif
8911   } else {
8912       *mask = *pieceToSolid(piece);
8913   }
8914
8915   /* GC for piece being moved. Square color doesn't matter, but
8916      since it gets modified we make a copy of the original. */
8917   if (White(piece)) {
8918     if (appData.monoMode)
8919       source = bwPieceGC;
8920     else
8921       source = wlPieceGC;
8922   } else {
8923     if (appData.monoMode)
8924       source = wbPieceGC;
8925     else
8926       source = blPieceGC;
8927   }
8928   XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8929
8930   /* Outline only used in mono mode and is not modified */
8931   if (White(piece))
8932     *outline = bwPieceGC;
8933   else
8934     *outline = wbPieceGC;
8935 }
8936
8937 static void
8938 OverlayPiece(piece, clip, outline,  dest)
8939      ChessSquare piece; GC clip; GC outline; Drawable dest;
8940 {
8941   int   kind;
8942
8943   if (!useImages) {
8944     /* Draw solid rectangle which will be clipped to shape of piece */
8945     XFillRectangle(xDisplay, dest, clip,
8946                    0, 0, squareSize, squareSize);
8947     if (appData.monoMode)
8948       /* Also draw outline in contrasting color for black
8949          on black / white on white cases                */
8950       XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8951                  0, 0, squareSize, squareSize, 0, 0, 1);
8952   } else {
8953     /* Copy the piece */
8954     if (White(piece))
8955       kind = 0;
8956     else
8957       kind = 2;
8958     XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8959               dest, clip,
8960               0, 0, squareSize, squareSize,
8961               0, 0);
8962   }
8963 }
8964
8965 /* Animate the movement of a single piece */
8966
8967 static void
8968 BeginAnimation(anim, piece, startColor, start)
8969      AnimState *anim;
8970      ChessSquare piece;
8971      int startColor;
8972      XPoint * start;
8973 {
8974   Pixmap mask;
8975
8976   /* The old buffer is initialised with the start square (empty) */
8977   BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8978   anim->prevFrame = *start;
8979
8980   /* The piece will be drawn using its own bitmap as a matte    */
8981   SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8982   XSetClipMask(xDisplay, anim->pieceGC, mask);
8983 }
8984
8985 static void
8986 AnimationFrame(anim, frame, piece)
8987      AnimState *anim;
8988      XPoint *frame;
8989      ChessSquare piece;
8990 {
8991   XRectangle updates[4];
8992   XRectangle overlap;
8993   XPoint     pt;
8994   int        count, i;
8995
8996   /* Save what we are about to draw into the new buffer */
8997   XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8998             frame->x, frame->y, squareSize, squareSize,
8999             0, 0);
9000
9001   /* Erase bits of the previous frame */
9002   if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
9003     /* Where the new frame overlapped the previous,
9004        the contents in newBuf are wrong. */
9005     XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
9006               overlap.x, overlap.y,
9007               overlap.width, overlap.height,
9008               pt.x, pt.y);
9009     /* Repaint the areas in the old that don't overlap new */
9010     CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
9011     for (i = 0; i < count; i++)
9012       XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
9013                 updates[i].x - anim->prevFrame.x,
9014                 updates[i].y - anim->prevFrame.y,
9015                 updates[i].width, updates[i].height,
9016                 updates[i].x, updates[i].y);
9017   } else {
9018     /* Easy when no overlap */
9019     XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
9020                   0, 0, squareSize, squareSize,
9021                   anim->prevFrame.x, anim->prevFrame.y);
9022   }
9023
9024   /* Save this frame for next time round */
9025   XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
9026                 0, 0, squareSize, squareSize,
9027                 0, 0);
9028   anim->prevFrame = *frame;
9029
9030   /* Draw piece over original screen contents, not current,
9031      and copy entire rect. Wipes out overlapping piece images. */
9032   OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
9033   XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
9034                 0, 0, squareSize, squareSize,
9035                 frame->x, frame->y);
9036 }
9037
9038 static void
9039 EndAnimation (anim, finish)
9040      AnimState *anim;
9041      XPoint *finish;
9042 {
9043   XRectangle updates[4];
9044   XRectangle overlap;
9045   XPoint     pt;
9046   int        count, i;
9047
9048   /* The main code will redraw the final square, so we
9049      only need to erase the bits that don't overlap.    */
9050   if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
9051     CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
9052     for (i = 0; i < count; i++)
9053       XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
9054                 updates[i].x - anim->prevFrame.x,
9055                 updates[i].y - anim->prevFrame.y,
9056                 updates[i].width, updates[i].height,
9057                 updates[i].x, updates[i].y);
9058   } else {
9059     XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
9060                 0, 0, squareSize, squareSize,
9061                 anim->prevFrame.x, anim->prevFrame.y);
9062   }
9063 }
9064
9065 static void
9066 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
9067      AnimState *anim;
9068      ChessSquare piece; int startColor;
9069      XPoint * start; XPoint * finish;
9070      XPoint frames[]; int nFrames;
9071 {
9072   int n;
9073
9074   BeginAnimation(anim, piece, startColor, start);
9075   for (n = 0; n < nFrames; n++) {
9076     AnimationFrame(anim, &(frames[n]), piece);
9077     FrameDelay(appData.animSpeed);
9078   }
9079   EndAnimation(anim, finish);
9080 }
9081
9082 /* Main control logic for deciding what to animate and how */
9083
9084 void
9085 AnimateMove(board, fromX, fromY, toX, toY)
9086      Board board;
9087      int fromX;
9088      int fromY;
9089      int toX;
9090      int toY;
9091 {
9092   ChessSquare piece;
9093   int hop;
9094   XPoint      start, finish, mid;
9095   XPoint      frames[kFactor * 2 + 1];
9096   int         nFrames, startColor, endColor;
9097
9098   /* Are we animating? */
9099   if (!appData.animate || appData.blindfold)
9100     return;
9101
9102   if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
9103   piece = board[fromY][fromX];
9104   if (piece >= EmptySquare) return;
9105
9106 #if DONT_HOP
9107   hop = FALSE;
9108 #else
9109   hop = (piece == WhiteKnight || piece == BlackKnight);
9110 #endif
9111
9112   if (appData.debugMode) {
9113       fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
9114                              _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
9115              piece, fromX, fromY, toX, toY);  }
9116
9117   ScreenSquare(fromX, fromY, &start, &startColor);
9118   ScreenSquare(toX, toY, &finish, &endColor);
9119
9120   if (hop) {
9121     /* Knight: make diagonal movement then straight */
9122     if (abs(toY - fromY) < abs(toX - fromX)) {
9123        mid.x = start.x + (finish.x - start.x) / 2;
9124        mid.y = finish.y;
9125      } else {
9126        mid.x = finish.x;
9127        mid.y = start.y + (finish.y - start.y) / 2;
9128      }
9129   } else {
9130     mid.x = start.x + (finish.x - start.x) / 2;
9131     mid.y = start.y + (finish.y - start.y) / 2;
9132   }
9133
9134   /* Don't use as many frames for very short moves */
9135   if (abs(toY - fromY) + abs(toX - fromX) <= 2)
9136     Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
9137   else
9138     Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
9139   FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
9140
9141   /* Be sure end square is redrawn */
9142   damage[toY][toX] = True;
9143 }
9144
9145 static void
9146 DragPieceBegin(x, y)
9147      int x; int y;
9148 {
9149     int  boardX, boardY, color;
9150     XPoint corner;
9151
9152     /* Are we animating? */
9153     if (!appData.animateDragging || appData.blindfold)
9154       return;
9155
9156     /* Figure out which square we start in and the
9157        mouse position relative to top left corner. */
9158     BoardSquare(x, y, &boardX, &boardY);
9159     player.startBoardX = boardX;
9160     player.startBoardY = boardY;
9161     ScreenSquare(boardX, boardY, &corner, &color);
9162     player.startSquare  = corner;
9163     player.startColor   = color;
9164 #if 0
9165     /* Start from exactly where the piece is.  This can be confusing
9166        if you start dragging far from the center of the square; most
9167        or all of the piece can be over a different square from the one
9168        the mouse pointer is in. */
9169     player.mouseDelta.x = x - corner.x;
9170     player.mouseDelta.y = y - corner.y;
9171 #else
9172     /* As soon as we start dragging, the piece will jump slightly to
9173        be centered over the mouse pointer. */
9174     player.mouseDelta.x = squareSize/2;
9175     player.mouseDelta.y = squareSize/2;
9176 #endif
9177     /* Initialise animation */
9178     player.dragPiece = PieceForSquare(boardX, boardY);
9179     /* Sanity check */
9180     if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
9181         player.dragActive = True;
9182         BeginAnimation(&player, player.dragPiece, color, &corner);
9183         /* Mark this square as needing to be redrawn. Note that
9184            we don't remove the piece though, since logically (ie
9185            as seen by opponent) the move hasn't been made yet. */
9186            if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
9187               boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
9188            XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
9189                      corner.x, corner.y, squareSize, squareSize,
9190                      0, 0); // [HGM] zh: unstack in stead of grab
9191         damage[boardY][boardX] = True;
9192     } else {
9193         player.dragActive = False;
9194     }
9195 }
9196
9197 static void
9198 DragPieceMove(x, y)
9199      int x; int y;
9200 {
9201     XPoint corner;
9202
9203     /* Are we animating? */
9204     if (!appData.animateDragging || appData.blindfold)
9205       return;
9206
9207     /* Sanity check */
9208     if (! player.dragActive)
9209       return;
9210     /* Move piece, maintaining same relative position
9211        of mouse within square    */
9212     corner.x = x - player.mouseDelta.x;
9213     corner.y = y - player.mouseDelta.y;
9214     AnimationFrame(&player, &corner, player.dragPiece);
9215 #if HIGHDRAG
9216     if (appData.highlightDragging) {
9217         int boardX, boardY;
9218         BoardSquare(x, y, &boardX, &boardY);
9219         SetHighlights(fromX, fromY, boardX, boardY);
9220     }
9221 #endif
9222 }
9223
9224 static void
9225 DragPieceEnd(x, y)
9226      int x; int y;
9227 {
9228     int boardX, boardY, color;
9229     XPoint corner;
9230
9231     /* Are we animating? */
9232     if (!appData.animateDragging || appData.blindfold)
9233       return;
9234
9235     /* Sanity check */
9236     if (! player.dragActive)
9237       return;
9238     /* Last frame in sequence is square piece is
9239        placed on, which may not match mouse exactly. */
9240     BoardSquare(x, y, &boardX, &boardY);
9241     ScreenSquare(boardX, boardY, &corner, &color);
9242     EndAnimation(&player, &corner);
9243
9244     /* Be sure end square is redrawn */
9245     damage[boardY][boardX] = True;
9246
9247     /* This prevents weird things happening with fast successive
9248        clicks which on my Sun at least can cause motion events
9249        without corresponding press/release. */
9250     player.dragActive = False;
9251 }
9252
9253 /* Handle expose event while piece being dragged */
9254
9255 static void
9256 DrawDragPiece ()
9257 {
9258   if (!player.dragActive || appData.blindfold)
9259     return;
9260
9261   /* What we're doing: logically, the move hasn't been made yet,
9262      so the piece is still in it's original square. But visually
9263      it's being dragged around the board. So we erase the square
9264      that the piece is on and draw it at the last known drag point. */
9265   BlankSquare(player.startSquare.x, player.startSquare.y,
9266                 player.startColor, EmptySquare, xBoardWindow);
9267   AnimationFrame(&player, &player.prevFrame, player.dragPiece);
9268   damage[player.startBoardY][player.startBoardX] = TRUE;
9269 }
9270
9271 void
9272 SetProgramStats( FrontEndProgramStats * stats )
9273 {
9274   // [HR] TODO
9275   // [HGM] done, but perhaps backend should call this directly?
9276     EngineOutputUpdate( stats );
9277 }