added gamelisttag option to xboard
[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-2001 Free Software Foundation",
7399             "Enhancements Copyright 2005 Alessandro Scotti",
7400             "Enhancements Copyright 2007-2008 H.G.Muller",
7401             PRODUCT, " is free software and carries NO WARRANTY;",
7402             "see the file COPYING for more information.");
7403     ErrorPopUp(_("About XBoard"), buf, FALSE);
7404 }
7405
7406 void DebugProc(w, event, prms, nprms)
7407      Widget w;
7408      XEvent *event;
7409      String *prms;
7410      Cardinal *nprms;
7411 {
7412     appData.debugMode = !appData.debugMode;
7413 }
7414
7415 void AboutGameProc(w, event, prms, nprms)
7416      Widget w;
7417      XEvent *event;
7418      String *prms;
7419      Cardinal *nprms;
7420 {
7421     AboutGameEvent();
7422 }
7423
7424 void NothingProc(w, event, prms, nprms)
7425      Widget w;
7426      XEvent *event;
7427      String *prms;
7428      Cardinal *nprms;
7429 {
7430     return;
7431 }
7432
7433 void Iconify(w, event, prms, nprms)
7434      Widget w;
7435      XEvent *event;
7436      String *prms;
7437      Cardinal *nprms;
7438 {
7439     Arg args[16];
7440
7441     fromX = fromY = -1;
7442     XtSetArg(args[0], XtNiconic, True);
7443     XtSetValues(shellWidget, args, 1);
7444 }
7445
7446 void DisplayMessage(message, extMessage)
7447      char *message, *extMessage;
7448 {
7449     char buf[MSG_SIZ];
7450     Arg arg;
7451
7452     if (extMessage) {
7453         if (*message) {
7454             sprintf(buf, "%s  %s", message, extMessage);
7455             message = buf;
7456         } else {
7457             message = extMessage;
7458         }
7459     }
7460     XtSetArg(arg, XtNlabel, message);
7461     XtSetValues(messageWidget, &arg, 1);
7462 }
7463
7464 void DisplayTitle(text)
7465      char *text;
7466 {
7467     Arg args[16];
7468     int i;
7469     char title[MSG_SIZ];
7470     char icon[MSG_SIZ];
7471
7472     if (text == NULL) text = "";
7473
7474     if (appData.titleInWindow) {
7475         i = 0;
7476         XtSetArg(args[i], XtNlabel, text);   i++;
7477         XtSetValues(titleWidget, args, i);
7478     }
7479
7480     if (*text != NULLCHAR) {
7481         strcpy(icon, text);
7482         strcpy(title, text);
7483     } else if (appData.icsActive) {
7484         sprintf(icon, "%s", appData.icsHost);
7485         sprintf(title, "%s: %s", programName, appData.icsHost);
7486     } else if (appData.cmailGameName[0] != NULLCHAR) {
7487         sprintf(icon, "%s", "CMail");
7488         sprintf(title, "%s: %s", programName, "CMail");
7489 #ifdef GOTHIC
7490     // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7491     } else if (gameInfo.variant == VariantGothic) {
7492         strcpy(icon, programName);
7493         strcpy(title, GOTHIC);
7494 #endif
7495 #ifdef FALCON
7496     } else if (gameInfo.variant == VariantFalcon) {
7497         strcpy(icon, programName);
7498         strcpy(title, FALCON);
7499 #endif
7500     } else if (appData.noChessProgram) {
7501         strcpy(icon, programName);
7502         strcpy(title, programName);
7503     } else {
7504         strcpy(icon, first.tidy);
7505         sprintf(title, "%s: %s", programName, first.tidy);
7506     }
7507     i = 0;
7508     XtSetArg(args[i], XtNiconName, (XtArgVal) icon);    i++;
7509     XtSetArg(args[i], XtNtitle, (XtArgVal) title);      i++;
7510     XtSetValues(shellWidget, args, i);
7511 }
7512
7513
7514 void DisplayError(message, error)
7515      String message;
7516      int error;
7517 {
7518     char buf[MSG_SIZ];
7519
7520     if (error == 0) {
7521         if (appData.debugMode || appData.matchMode) {
7522             fprintf(stderr, "%s: %s\n", programName, message);
7523         }
7524     } else {
7525         if (appData.debugMode || appData.matchMode) {
7526             fprintf(stderr, "%s: %s: %s\n",
7527                     programName, message, strerror(error));
7528         }
7529         sprintf(buf, "%s: %s", message, strerror(error));
7530         message = buf;
7531     }
7532     ErrorPopUp(_("Error"), message, FALSE);
7533 }
7534
7535
7536 void DisplayMoveError(message)
7537      String message;
7538 {
7539     fromX = fromY = -1;
7540     ClearHighlights();
7541     DrawPosition(FALSE, NULL);
7542     if (appData.debugMode || appData.matchMode) {
7543         fprintf(stderr, "%s: %s\n", programName, message);
7544     }
7545     if (appData.popupMoveErrors) {
7546         ErrorPopUp(_("Error"), message, FALSE);
7547     } else {
7548         DisplayMessage(message, "");
7549     }
7550 }
7551
7552
7553 void DisplayFatalError(message, error, status)
7554      String message;
7555      int error, status;
7556 {
7557     char buf[MSG_SIZ];
7558
7559     errorExitStatus = status;
7560     if (error == 0) {
7561         fprintf(stderr, "%s: %s\n", programName, message);
7562     } else {
7563         fprintf(stderr, "%s: %s: %s\n",
7564                 programName, message, strerror(error));
7565         sprintf(buf, "%s: %s", message, strerror(error));
7566         message = buf;
7567     }
7568     if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7569       ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7570     } else {
7571       ExitEvent(status);
7572     }
7573 }
7574
7575 void DisplayInformation(message)
7576      String message;
7577 {
7578     ErrorPopDown();
7579     ErrorPopUp(_("Information"), message, TRUE);
7580 }
7581
7582 void DisplayNote(message)
7583      String message;
7584 {
7585     ErrorPopDown();
7586     ErrorPopUp(_("Note"), message, FALSE);
7587 }
7588
7589 static int
7590 NullXErrorCheck(dpy, error_event)
7591      Display *dpy;
7592      XErrorEvent *error_event;
7593 {
7594     return 0;
7595 }
7596
7597 void DisplayIcsInteractionTitle(message)
7598      String message;
7599 {
7600   if (oldICSInteractionTitle == NULL) {
7601     /* Magic to find the old window title, adapted from vim */
7602     char *wina = getenv("WINDOWID");
7603     if (wina != NULL) {
7604       Window win = (Window) atoi(wina);
7605       Window root, parent, *children;
7606       unsigned int nchildren;
7607       int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7608       for (;;) {
7609         if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7610         if (!XQueryTree(xDisplay, win, &root, &parent,
7611                         &children, &nchildren)) break;
7612         if (children) XFree((void *)children);
7613         if (parent == root || parent == 0) break;
7614         win = parent;
7615       }
7616       XSetErrorHandler(oldHandler);
7617     }
7618     if (oldICSInteractionTitle == NULL) {
7619       oldICSInteractionTitle = "xterm";
7620     }
7621   }
7622   printf("\033]0;%s\007", message);
7623   fflush(stdout);
7624 }
7625
7626 char pendingReplyPrefix[MSG_SIZ];
7627 ProcRef pendingReplyPR;
7628
7629 void AskQuestionProc(w, event, prms, nprms)
7630      Widget w;
7631      XEvent *event;
7632      String *prms;
7633      Cardinal *nprms;
7634 {
7635     if (*nprms != 4) {
7636         fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7637                 *nprms);
7638         return;
7639     }
7640     AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7641 }
7642
7643 void AskQuestionPopDown()
7644 {
7645     if (!askQuestionUp) return;
7646     XtPopdown(askQuestionShell);
7647     XtDestroyWidget(askQuestionShell);
7648     askQuestionUp = False;
7649 }
7650
7651 void AskQuestionReplyAction(w, event, prms, nprms)
7652      Widget w;
7653      XEvent *event;
7654      String *prms;
7655      Cardinal *nprms;
7656 {
7657     char buf[MSG_SIZ];
7658     int err;
7659     String reply;
7660
7661     reply = XawDialogGetValueString(w = XtParent(w));
7662     strcpy(buf, pendingReplyPrefix);
7663     if (*buf) strcat(buf, " ");
7664     strcat(buf, reply);
7665     strcat(buf, "\n");
7666     OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7667     AskQuestionPopDown();
7668
7669     if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7670 }
7671
7672 void AskQuestionCallback(w, client_data, call_data)
7673      Widget w;
7674      XtPointer client_data, call_data;
7675 {
7676     String name;
7677     Arg args[16];
7678
7679     XtSetArg(args[0], XtNlabel, &name);
7680     XtGetValues(w, args, 1);
7681
7682     if (strcmp(name, _("cancel")) == 0) {
7683         AskQuestionPopDown();
7684     } else {
7685         AskQuestionReplyAction(w, NULL, NULL, NULL);
7686     }
7687 }
7688
7689 void AskQuestion(title, question, replyPrefix, pr)
7690      char *title, *question, *replyPrefix;
7691      ProcRef pr;
7692 {
7693     Arg args[16];
7694     Widget popup, layout, dialog, edit;
7695     Window root, child;
7696     int x, y, i;
7697     int win_x, win_y;
7698     unsigned int mask;
7699
7700     strcpy(pendingReplyPrefix, replyPrefix);
7701     pendingReplyPR = pr;
7702
7703     i = 0;
7704     XtSetArg(args[i], XtNresizable, True); i++;
7705     XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7706     askQuestionShell = popup =
7707       XtCreatePopupShell(title, transientShellWidgetClass,
7708                          shellWidget, args, i);
7709
7710     layout =
7711       XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7712                             layoutArgs, XtNumber(layoutArgs));
7713
7714     i = 0;
7715     XtSetArg(args[i], XtNlabel, question); i++;
7716     XtSetArg(args[i], XtNvalue, ""); i++;
7717     XtSetArg(args[i], XtNborderWidth, 0); i++;
7718     dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7719                                    layout, args, i);
7720
7721     XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7722                        (XtPointer) dialog);
7723     XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7724                        (XtPointer) dialog);
7725
7726     XtRealizeWidget(popup);
7727     CatchDeleteWindow(popup, "AskQuestionPopDown");
7728
7729     XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7730                   &x, &y, &win_x, &win_y, &mask);
7731
7732     XtSetArg(args[0], XtNx, x - 10);
7733     XtSetArg(args[1], XtNy, y - 30);
7734     XtSetValues(popup, args, 2);
7735
7736     XtPopup(popup, XtGrabExclusive);
7737     askQuestionUp = True;
7738
7739     edit = XtNameToWidget(dialog, "*value");
7740     XtSetKeyboardFocus(popup, edit);
7741 }
7742
7743
7744 void
7745 PlaySound(name)
7746      char *name;
7747 {
7748   if (*name == NULLCHAR) {
7749     return;
7750   } else if (strcmp(name, "$") == 0) {
7751     putc(BELLCHAR, stderr);
7752   } else {
7753     char buf[2048];
7754     sprintf(buf, "%s '%s' &", appData.soundProgram, name);
7755     system(buf);
7756   }
7757 }
7758
7759 void
7760 RingBell()
7761 {
7762   PlaySound(appData.soundMove);
7763 }
7764
7765 void
7766 PlayIcsWinSound()
7767 {
7768   PlaySound(appData.soundIcsWin);
7769 }
7770
7771 void
7772 PlayIcsLossSound()
7773 {
7774   PlaySound(appData.soundIcsLoss);
7775 }
7776
7777 void
7778 PlayIcsDrawSound()
7779 {
7780   PlaySound(appData.soundIcsDraw);
7781 }
7782
7783 void
7784 PlayIcsUnfinishedSound()
7785 {
7786   PlaySound(appData.soundIcsUnfinished);
7787 }
7788
7789 void
7790 PlayAlarmSound()
7791 {
7792   PlaySound(appData.soundIcsAlarm);
7793 }
7794
7795 void
7796 EchoOn()
7797 {
7798     system("stty echo");
7799 }
7800
7801 void
7802 EchoOff()
7803 {
7804     system("stty -echo");
7805 }
7806
7807 void
7808 Colorize(cc, continuation)
7809      ColorClass cc;
7810      int continuation;
7811 {
7812     char buf[MSG_SIZ];
7813     int count, outCount, error;
7814
7815     if (textColors[(int)cc].bg > 0) {
7816         if (textColors[(int)cc].fg > 0) {
7817             sprintf(buf, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7818                     textColors[(int)cc].fg, textColors[(int)cc].bg);
7819         } else {
7820             sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7821                     textColors[(int)cc].bg);
7822         }
7823     } else {
7824         if (textColors[(int)cc].fg > 0) {
7825             sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7826                     textColors[(int)cc].fg);
7827         } else {
7828             sprintf(buf, "\033[0;%dm", textColors[(int)cc].attr);
7829         }
7830     }
7831     count = strlen(buf);
7832     outCount = OutputToProcess(NoProc, buf, count, &error);
7833     if (outCount < count) {
7834         DisplayFatalError(_("Error writing to display"), error, 1);
7835     }
7836
7837     if (continuation) return;
7838     switch (cc) {
7839     case ColorShout:
7840       PlaySound(appData.soundShout);
7841       break;
7842     case ColorSShout:
7843       PlaySound(appData.soundSShout);
7844       break;
7845     case ColorChannel1:
7846       PlaySound(appData.soundChannel1);
7847       break;
7848     case ColorChannel:
7849       PlaySound(appData.soundChannel);
7850       break;
7851     case ColorKibitz:
7852       PlaySound(appData.soundKibitz);
7853       break;
7854     case ColorTell:
7855       PlaySound(appData.soundTell);
7856       break;
7857     case ColorChallenge:
7858       PlaySound(appData.soundChallenge);
7859       break;
7860     case ColorRequest:
7861       PlaySound(appData.soundRequest);
7862       break;
7863     case ColorSeek:
7864       PlaySound(appData.soundSeek);
7865       break;
7866     case ColorNormal:
7867     case ColorNone:
7868     default:
7869       break;
7870     }
7871 }
7872
7873 char *UserName()
7874 {
7875     return getpwuid(getuid())->pw_name;
7876 }
7877
7878 static char *ExpandPathName(path)
7879      char *path;
7880 {
7881     static char static_buf[2000];
7882     char *d, *s, buf[2000];
7883     struct passwd *pwd;
7884
7885     s = path;
7886     d = static_buf;
7887
7888     while (*s && isspace(*s))
7889       ++s;
7890
7891     if (!*s) {
7892         *d = 0;
7893         return static_buf;
7894     }
7895
7896     if (*s == '~') {
7897         if (*(s+1) == '/') {
7898             strcpy(d, getpwuid(getuid())->pw_dir);
7899             strcat(d, s+1);
7900         }
7901         else {
7902             strcpy(buf, s+1);
7903             *strchr(buf, '/') = 0;
7904             pwd = getpwnam(buf);
7905             if (!pwd)
7906               {
7907                   fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7908                           buf, path);
7909                   return NULL;
7910               }
7911             strcpy(d, pwd->pw_dir);
7912             strcat(d, strchr(s+1, '/'));
7913         }
7914     }
7915     else
7916       strcpy(d, s);
7917
7918     return static_buf;
7919 }
7920
7921 char *HostName()
7922 {
7923     static char host_name[MSG_SIZ];
7924
7925 #if HAVE_GETHOSTNAME
7926     gethostname(host_name, MSG_SIZ);
7927     return host_name;
7928 #else  /* not HAVE_GETHOSTNAME */
7929 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7930     sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7931     return host_name;
7932 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7933     return "localhost";
7934 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7935 #endif /* not HAVE_GETHOSTNAME */
7936 }
7937
7938 XtIntervalId delayedEventTimerXID = 0;
7939 DelayedEventCallback delayedEventCallback = 0;
7940
7941 void
7942 FireDelayedEvent()
7943 {
7944     delayedEventTimerXID = 0;
7945     delayedEventCallback();
7946 }
7947
7948 void
7949 ScheduleDelayedEvent(cb, millisec)
7950      DelayedEventCallback cb; long millisec;
7951 {
7952     delayedEventCallback = cb;
7953     delayedEventTimerXID =
7954       XtAppAddTimeOut(appContext, millisec,
7955                       (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7956 }
7957
7958 DelayedEventCallback
7959 GetDelayedEvent()
7960 {
7961   if (delayedEventTimerXID) {
7962     return delayedEventCallback;
7963   } else {
7964     return NULL;
7965   }
7966 }
7967
7968 void
7969 CancelDelayedEvent()
7970 {
7971   if (delayedEventTimerXID) {
7972     XtRemoveTimeOut(delayedEventTimerXID);
7973     delayedEventTimerXID = 0;
7974   }
7975 }
7976
7977 XtIntervalId loadGameTimerXID = 0;
7978
7979 int LoadGameTimerRunning()
7980 {
7981     return loadGameTimerXID != 0;
7982 }
7983
7984 int StopLoadGameTimer()
7985 {
7986     if (loadGameTimerXID != 0) {
7987         XtRemoveTimeOut(loadGameTimerXID);
7988         loadGameTimerXID = 0;
7989         return TRUE;
7990     } else {
7991         return FALSE;
7992     }
7993 }
7994
7995 void
7996 LoadGameTimerCallback(arg, id)
7997      XtPointer arg;
7998      XtIntervalId *id;
7999 {
8000     loadGameTimerXID = 0;
8001     AutoPlayGameLoop();
8002 }
8003
8004 void
8005 StartLoadGameTimer(millisec)
8006      long millisec;
8007 {
8008     loadGameTimerXID =
8009       XtAppAddTimeOut(appContext, millisec,
8010                       (XtTimerCallbackProc) LoadGameTimerCallback,
8011                       (XtPointer) 0);
8012 }
8013
8014 XtIntervalId analysisClockXID = 0;
8015
8016 void
8017 AnalysisClockCallback(arg, id)
8018      XtPointer arg;
8019      XtIntervalId *id;
8020 {
8021     if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
8022          || appData.icsEngineAnalyze) { // [DM]
8023         AnalysisPeriodicEvent(0);
8024         StartAnalysisClock();
8025     }
8026 }
8027
8028 void
8029 StartAnalysisClock()
8030 {
8031     analysisClockXID =
8032       XtAppAddTimeOut(appContext, 2000,
8033                       (XtTimerCallbackProc) AnalysisClockCallback,
8034                       (XtPointer) 0);
8035 }
8036
8037 XtIntervalId clockTimerXID = 0;
8038
8039 int ClockTimerRunning()
8040 {
8041     return clockTimerXID != 0;
8042 }
8043
8044 int StopClockTimer()
8045 {
8046     if (clockTimerXID != 0) {
8047         XtRemoveTimeOut(clockTimerXID);
8048         clockTimerXID = 0;
8049         return TRUE;
8050     } else {
8051         return FALSE;
8052     }
8053 }
8054
8055 void
8056 ClockTimerCallback(arg, id)
8057      XtPointer arg;
8058      XtIntervalId *id;
8059 {
8060     clockTimerXID = 0;
8061     DecrementClocks();
8062 }
8063
8064 void
8065 StartClockTimer(millisec)
8066      long millisec;
8067 {
8068     clockTimerXID =
8069       XtAppAddTimeOut(appContext, millisec,
8070                       (XtTimerCallbackProc) ClockTimerCallback,
8071                       (XtPointer) 0);
8072 }
8073
8074 void
8075 DisplayTimerLabel(w, color, timer, highlight)
8076      Widget w;
8077      char *color;
8078      long timer;
8079      int highlight;
8080 {
8081     char buf[MSG_SIZ];
8082     Arg args[16];
8083
8084     if (appData.clockMode) {
8085         sprintf(buf, "%s: %s", color, TimeString(timer));
8086         XtSetArg(args[0], XtNlabel, buf);
8087     } else {
8088         sprintf(buf, "%s  ", color);
8089         XtSetArg(args[0], XtNlabel, buf);
8090     }
8091
8092     if (highlight) {
8093         XtSetArg(args[1], XtNbackground, timerForegroundPixel);
8094         XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
8095     } else {
8096         XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
8097         XtSetArg(args[2], XtNforeground, timerForegroundPixel);
8098     }
8099
8100     XtSetValues(w, args, 3);
8101 }
8102
8103 void
8104 DisplayWhiteClock(timeRemaining, highlight)
8105      long timeRemaining;
8106      int highlight;
8107 {
8108     Arg args[16];
8109
8110     if(appData.noGUI) return;
8111     DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
8112     if (highlight && iconPixmap == bIconPixmap) {
8113         iconPixmap = wIconPixmap;
8114         XtSetArg(args[0], XtNiconPixmap, iconPixmap);
8115         XtSetValues(shellWidget, args, 1);
8116     }
8117 }
8118
8119 void
8120 DisplayBlackClock(timeRemaining, highlight)
8121      long timeRemaining;
8122      int highlight;
8123 {
8124     Arg args[16];
8125
8126     if(appData.noGUI) return;
8127     DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
8128     if (highlight && iconPixmap == wIconPixmap) {
8129         iconPixmap = bIconPixmap;
8130         XtSetArg(args[0], XtNiconPixmap, iconPixmap);
8131         XtSetValues(shellWidget, args, 1);
8132     }
8133 }
8134
8135 #define CPNone 0
8136 #define CPReal 1
8137 #define CPComm 2
8138 #define CPSock 3
8139 #define CPLoop 4
8140 typedef int CPKind;
8141
8142 typedef struct {
8143     CPKind kind;
8144     int pid;
8145     int fdTo, fdFrom;
8146 } ChildProc;
8147
8148
8149 int StartChildProcess(cmdLine, dir, pr)
8150      char *cmdLine;
8151      char *dir;
8152      ProcRef *pr;
8153 {
8154     char *argv[64], *p;
8155     int i, pid;
8156     int to_prog[2], from_prog[2];
8157     ChildProc *cp;
8158     char buf[MSG_SIZ];
8159
8160     if (appData.debugMode) {
8161         fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
8162     }
8163
8164     /* We do NOT feed the cmdLine to the shell; we just
8165        parse it into blank-separated arguments in the
8166        most simple-minded way possible.
8167        */
8168     i = 0;
8169     strcpy(buf, cmdLine);
8170     p = buf;
8171     for (;;) {
8172         argv[i++] = p;
8173         p = strchr(p, ' ');
8174         if (p == NULL) break;
8175         *p++ = NULLCHAR;
8176     }
8177     argv[i] = NULL;
8178
8179     SetUpChildIO(to_prog, from_prog);
8180
8181     if ((pid = fork()) == 0) {
8182         /* Child process */
8183         // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
8184         close(to_prog[1]);     // first close the unused pipe ends
8185         close(from_prog[0]);
8186         dup2(to_prog[0], 0);   // to_prog was created first, nd is the only one to use 0 or 1
8187         dup2(from_prog[1], 1);
8188         if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
8189         close(from_prog[1]);                   // and closing again loses one of the pipes!
8190         if(fileno(stderr) >= 2) // better safe than sorry...
8191                 dup2(1, fileno(stderr)); /* force stderr to the pipe */
8192
8193         if (dir[0] != NULLCHAR && chdir(dir) != 0) {
8194             perror(dir);
8195             exit(1);
8196         }
8197
8198         nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
8199
8200         execvp(argv[0], argv);
8201
8202         /* If we get here, exec failed */
8203         perror(argv[0]);
8204         exit(1);
8205     }
8206
8207     /* Parent process */
8208     close(to_prog[0]);
8209     close(from_prog[1]);
8210
8211     cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8212     cp->kind = CPReal;
8213     cp->pid = pid;
8214     cp->fdFrom = from_prog[0];
8215     cp->fdTo = to_prog[1];
8216     *pr = (ProcRef) cp;
8217     return 0;
8218 }
8219
8220 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
8221 static RETSIGTYPE AlarmCallBack(int n)
8222 {
8223     return;
8224 }
8225
8226 void
8227 DestroyChildProcess(pr, signalType)
8228      ProcRef pr;
8229      int signalType;
8230 {
8231     ChildProc *cp = (ChildProc *) pr;
8232
8233     if (cp->kind != CPReal) return;
8234     cp->kind = CPNone;
8235     if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
8236         signal(SIGALRM, AlarmCallBack);
8237         alarm(3);
8238         if(wait((int *) 0) == -1) { // process does not terminate on its own accord
8239             kill(cp->pid, SIGKILL); // kill it forcefully
8240             wait((int *) 0);        // and wait again
8241         }
8242     } else {
8243         if (signalType) {
8244             kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
8245         }
8246         /* Process is exiting either because of the kill or because of
8247            a quit command sent by the backend; either way, wait for it to die.
8248         */
8249         wait((int *) 0);
8250     }
8251     close(cp->fdFrom);
8252     close(cp->fdTo);
8253 }
8254
8255 void
8256 InterruptChildProcess(pr)
8257      ProcRef pr;
8258 {
8259     ChildProc *cp = (ChildProc *) pr;
8260
8261     if (cp->kind != CPReal) return;
8262     (void) kill(cp->pid, SIGINT); /* stop it thinking */
8263 }
8264
8265 int OpenTelnet(host, port, pr)
8266      char *host;
8267      char *port;
8268      ProcRef *pr;
8269 {
8270     char cmdLine[MSG_SIZ];
8271
8272     if (port[0] == NULLCHAR) {
8273         sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
8274     } else {
8275         sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
8276     }
8277     return StartChildProcess(cmdLine, "", pr);
8278 }
8279
8280 int OpenTCP(host, port, pr)
8281      char *host;
8282      char *port;
8283      ProcRef *pr;
8284 {
8285 #if OMIT_SOCKETS
8286     DisplayFatalError(_("Socket support is not configured in"), 0, 2);
8287 #else  /* !OMIT_SOCKETS */
8288     int s;
8289     struct sockaddr_in sa;
8290     struct hostent     *hp;
8291     unsigned short uport;
8292     ChildProc *cp;
8293
8294     if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
8295         return errno;
8296     }
8297
8298     memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
8299     sa.sin_family = AF_INET;
8300     sa.sin_addr.s_addr = INADDR_ANY;
8301     uport = (unsigned short) 0;
8302     sa.sin_port = htons(uport);
8303     if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
8304         return errno;
8305     }
8306
8307     memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
8308     if (!(hp = gethostbyname(host))) {
8309         int b0, b1, b2, b3;
8310         if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
8311             hp = (struct hostent *) calloc(1, sizeof(struct hostent));
8312             hp->h_addrtype = AF_INET;
8313             hp->h_length = 4;
8314             hp->h_addr_list = (char **) calloc(2, sizeof(char *));
8315             hp->h_addr_list[0] = (char *) malloc(4);
8316             hp->h_addr_list[0][0] = b0;
8317             hp->h_addr_list[0][1] = b1;
8318             hp->h_addr_list[0][2] = b2;
8319             hp->h_addr_list[0][3] = b3;
8320         } else {
8321             return ENOENT;
8322         }
8323     }
8324     sa.sin_family = hp->h_addrtype;
8325     uport = (unsigned short) atoi(port);
8326     sa.sin_port = htons(uport);
8327     memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
8328
8329     if (connect(s, (struct sockaddr *) &sa,
8330                 sizeof(struct sockaddr_in)) < 0) {
8331         return errno;
8332     }
8333
8334     cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8335     cp->kind = CPSock;
8336     cp->pid = 0;
8337     cp->fdFrom = s;
8338     cp->fdTo = s;
8339     *pr = (ProcRef) cp;
8340
8341 #endif /* !OMIT_SOCKETS */
8342
8343     return 0;
8344 }
8345
8346 int OpenCommPort(name, pr)
8347      char *name;
8348      ProcRef *pr;
8349 {
8350     int fd;
8351     ChildProc *cp;
8352
8353     fd = open(name, 2, 0);
8354     if (fd < 0) return errno;
8355
8356     cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8357     cp->kind = CPComm;
8358     cp->pid = 0;
8359     cp->fdFrom = fd;
8360     cp->fdTo = fd;
8361     *pr = (ProcRef) cp;
8362
8363     return 0;
8364 }
8365
8366 int OpenLoopback(pr)
8367      ProcRef *pr;
8368 {
8369     ChildProc *cp;
8370     int to[2], from[2];
8371
8372     SetUpChildIO(to, from);
8373
8374     cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8375     cp->kind = CPLoop;
8376     cp->pid = 0;
8377     cp->fdFrom = to[0];         /* note not from[0]; we are doing a loopback */
8378     cp->fdTo = to[1];
8379     *pr = (ProcRef) cp;
8380
8381     return 0;
8382 }
8383
8384 int OpenRcmd(host, user, cmd, pr)
8385      char *host, *user, *cmd;
8386      ProcRef *pr;
8387 {
8388     DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
8389     return -1;
8390 }
8391
8392 #define INPUT_SOURCE_BUF_SIZE 8192
8393
8394 typedef struct {
8395     CPKind kind;
8396     int fd;
8397     int lineByLine;
8398     char *unused;
8399     InputCallback func;
8400     XtInputId xid;
8401     char buf[INPUT_SOURCE_BUF_SIZE];
8402     VOIDSTAR closure;
8403 } InputSource;
8404
8405 void
8406 DoInputCallback(closure, source, xid)
8407      caddr_t closure;
8408      int *source;
8409      XtInputId *xid;
8410 {
8411     InputSource *is = (InputSource *) closure;
8412     int count;
8413     int error;
8414     char *p, *q;
8415
8416     if (is->lineByLine) {
8417         count = read(is->fd, is->unused,
8418                      INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
8419         if (count <= 0) {
8420             (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
8421             return;
8422         }
8423         is->unused += count;
8424         p = is->buf;
8425         while (p < is->unused) {
8426             q = memchr(p, '\n', is->unused - p);
8427             if (q == NULL) break;
8428             q++;
8429             (is->func)(is, is->closure, p, q - p, 0);
8430             p = q;
8431         }
8432         q = is->buf;
8433         while (p < is->unused) {
8434             *q++ = *p++;
8435         }
8436         is->unused = q;
8437     } else {
8438         count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8439         if (count == -1)
8440           error = errno;
8441         else
8442           error = 0;
8443         (is->func)(is, is->closure, is->buf, count, error);
8444     }
8445 }
8446
8447 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8448      ProcRef pr;
8449      int lineByLine;
8450      InputCallback func;
8451      VOIDSTAR closure;
8452 {
8453     InputSource *is;
8454     ChildProc *cp = (ChildProc *) pr;
8455
8456     is = (InputSource *) calloc(1, sizeof(InputSource));
8457     is->lineByLine = lineByLine;
8458     is->func = func;
8459     if (pr == NoProc) {
8460         is->kind = CPReal;
8461         is->fd = fileno(stdin);
8462     } else {
8463         is->kind = cp->kind;
8464         is->fd = cp->fdFrom;
8465     }
8466     if (lineByLine) {
8467         is->unused = is->buf;
8468     }
8469
8470     is->xid = XtAppAddInput(appContext, is->fd,
8471                             (XtPointer) (XtInputReadMask),
8472                             (XtInputCallbackProc) DoInputCallback,
8473                             (XtPointer) is);
8474     is->closure = closure;
8475     return (InputSourceRef) is;
8476 }
8477
8478 void
8479 RemoveInputSource(isr)
8480      InputSourceRef isr;
8481 {
8482     InputSource *is = (InputSource *) isr;
8483
8484     if (is->xid == 0) return;
8485     XtRemoveInput(is->xid);
8486     is->xid = 0;
8487 }
8488
8489 int OutputToProcess(pr, message, count, outError)
8490      ProcRef pr;
8491      char *message;
8492      int count;
8493      int *outError;
8494 {
8495     ChildProc *cp = (ChildProc *) pr;
8496     int outCount;
8497
8498     if (pr == NoProc)
8499       outCount = fwrite(message, 1, count, stdout);
8500     else
8501       outCount = write(cp->fdTo, message, count);
8502
8503     if (outCount == -1)
8504       *outError = errno;
8505     else
8506       *outError = 0;
8507
8508     return outCount;
8509 }
8510
8511 /* Output message to process, with "ms" milliseconds of delay
8512    between each character. This is needed when sending the logon
8513    script to ICC, which for some reason doesn't like the
8514    instantaneous send. */
8515 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8516      ProcRef pr;
8517      char *message;
8518      int count;
8519      int *outError;
8520      long msdelay;
8521 {
8522     ChildProc *cp = (ChildProc *) pr;
8523     int outCount = 0;
8524     int r;
8525
8526     while (count--) {
8527         r = write(cp->fdTo, message++, 1);
8528         if (r == -1) {
8529             *outError = errno;
8530             return outCount;
8531         }
8532         ++outCount;
8533         if (msdelay >= 0)
8534           TimeDelay(msdelay);
8535     }
8536
8537     return outCount;
8538 }
8539
8540 /****   Animation code by Hugh Fisher, DCS, ANU.
8541
8542         Known problem: if a window overlapping the board is
8543         moved away while a piece is being animated underneath,
8544         the newly exposed area won't be updated properly.
8545         I can live with this.
8546
8547         Known problem: if you look carefully at the animation
8548         of pieces in mono mode, they are being drawn as solid
8549         shapes without interior detail while moving. Fixing
8550         this would be a major complication for minimal return.
8551 ****/
8552
8553 /*      Masks for XPM pieces. Black and white pieces can have
8554         different shapes, but in the interest of retaining my
8555         sanity pieces must have the same outline on both light
8556         and dark squares, and all pieces must use the same
8557         background square colors/images.                */
8558
8559 static void
8560 CreateAnimMasks (pieceDepth)
8561      int pieceDepth;
8562 {
8563   ChessSquare   piece;
8564   Pixmap        buf;
8565   GC            bufGC, maskGC;
8566   int           kind, n;
8567   unsigned long plane;
8568   XGCValues     values;
8569
8570   /* Need a bitmap just to get a GC with right depth */
8571   buf = XCreatePixmap(xDisplay, xBoardWindow,
8572                         8, 8, 1);
8573   values.foreground = 1;
8574   values.background = 0;
8575   /* Don't use XtGetGC, not read only */
8576   maskGC = XCreateGC(xDisplay, buf,
8577                     GCForeground | GCBackground, &values);
8578   XFreePixmap(xDisplay, buf);
8579
8580   buf = XCreatePixmap(xDisplay, xBoardWindow,
8581                       squareSize, squareSize, pieceDepth);
8582   values.foreground = XBlackPixel(xDisplay, xScreen);
8583   values.background = XWhitePixel(xDisplay, xScreen);
8584   bufGC = XCreateGC(xDisplay, buf,
8585                     GCForeground | GCBackground, &values);
8586
8587   for (piece = WhitePawn; piece <= BlackKing; piece++) {
8588     /* Begin with empty mask */
8589     xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8590                                  squareSize, squareSize, 1);
8591     XSetFunction(xDisplay, maskGC, GXclear);
8592     XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8593                    0, 0, squareSize, squareSize);
8594
8595     /* Take a copy of the piece */
8596     if (White(piece))
8597       kind = 0;
8598     else
8599       kind = 2;
8600     XSetFunction(xDisplay, bufGC, GXcopy);
8601     XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8602               buf, bufGC,
8603               0, 0, squareSize, squareSize, 0, 0);
8604
8605     /* XOR the background (light) over the piece */
8606     XSetFunction(xDisplay, bufGC, GXxor);
8607     if (useImageSqs)
8608       XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8609                 0, 0, squareSize, squareSize, 0, 0);
8610     else {
8611       XSetForeground(xDisplay, bufGC, lightSquareColor);
8612       XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8613     }
8614
8615     /* We now have an inverted piece image with the background
8616        erased. Construct mask by just selecting all the non-zero
8617        pixels - no need to reconstruct the original image.      */
8618     XSetFunction(xDisplay, maskGC, GXor);
8619     plane = 1;
8620     /* Might be quicker to download an XImage and create bitmap
8621        data from it rather than this N copies per piece, but it
8622        only takes a fraction of a second and there is a much
8623        longer delay for loading the pieces.             */
8624     for (n = 0; n < pieceDepth; n ++) {
8625       XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8626                  0, 0, squareSize, squareSize,
8627                  0, 0, plane);
8628       plane = plane << 1;
8629     }
8630   }
8631   /* Clean up */
8632   XFreePixmap(xDisplay, buf);
8633   XFreeGC(xDisplay, bufGC);
8634   XFreeGC(xDisplay, maskGC);
8635 }
8636
8637 static void
8638 InitAnimState (anim, info)
8639   AnimState * anim;
8640   XWindowAttributes * info;
8641 {
8642   XtGCMask  mask;
8643   XGCValues values;
8644
8645   /* Each buffer is square size, same depth as window */
8646   anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8647                         squareSize, squareSize, info->depth);
8648   anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8649                         squareSize, squareSize, info->depth);
8650
8651   /* Create a plain GC for blitting */
8652   mask = GCForeground | GCBackground | GCFunction |
8653          GCPlaneMask | GCGraphicsExposures;
8654   values.foreground = XBlackPixel(xDisplay, xScreen);
8655   values.background = XWhitePixel(xDisplay, xScreen);
8656   values.function   = GXcopy;
8657   values.plane_mask = AllPlanes;
8658   values.graphics_exposures = False;
8659   anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8660
8661   /* Piece will be copied from an existing context at
8662      the start of each new animation/drag. */
8663   anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8664
8665   /* Outline will be a read-only copy of an existing */
8666   anim->outlineGC = None;
8667 }
8668
8669 static void
8670 CreateAnimVars ()
8671 {
8672   static int done = 0;
8673   XWindowAttributes info;
8674
8675   if (done) return;
8676   done = 1;
8677   XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8678
8679   InitAnimState(&game, &info);
8680   InitAnimState(&player, &info);
8681
8682   /* For XPM pieces, we need bitmaps to use as masks. */
8683   if (useImages)
8684     CreateAnimMasks(info.depth);
8685 }
8686
8687 #ifndef HAVE_USLEEP
8688
8689 static Boolean frameWaiting;
8690
8691 static RETSIGTYPE FrameAlarm (sig)
8692      int sig;
8693 {
8694   frameWaiting = False;
8695   /* In case System-V style signals.  Needed?? */
8696   signal(SIGALRM, FrameAlarm);
8697 }
8698
8699 static void
8700 FrameDelay (time)
8701      int time;
8702 {
8703   struct itimerval delay;
8704
8705   XSync(xDisplay, False);
8706
8707   if (time > 0) {
8708     frameWaiting = True;
8709     signal(SIGALRM, FrameAlarm);
8710     delay.it_interval.tv_sec =
8711       delay.it_value.tv_sec = time / 1000;
8712     delay.it_interval.tv_usec =
8713       delay.it_value.tv_usec = (time % 1000) * 1000;
8714     setitimer(ITIMER_REAL, &delay, NULL);
8715 #if 0
8716     /* Ugh -- busy-wait! --tpm */
8717     while (frameWaiting);
8718 #else
8719     while (frameWaiting) pause();
8720 #endif
8721     delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8722     delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8723     setitimer(ITIMER_REAL, &delay, NULL);
8724   }
8725 }
8726
8727 #else
8728
8729 static void
8730 FrameDelay (time)
8731      int time;
8732 {
8733   XSync(xDisplay, False);
8734   if (time > 0)
8735     usleep(time * 1000);
8736 }
8737
8738 #endif
8739
8740 /*      Convert board position to corner of screen rect and color       */
8741
8742 static void
8743 ScreenSquare(column, row, pt, color)
8744      int column; int row; XPoint * pt; int * color;
8745 {
8746   if (flipView) {
8747     pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8748     pt->y = lineGap + row * (squareSize + lineGap);
8749   } else {
8750     pt->x = lineGap + column * (squareSize + lineGap);
8751     pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8752   }
8753   *color = SquareColor(row, column);
8754 }
8755
8756 /*      Convert window coords to square                 */
8757
8758 static void
8759 BoardSquare(x, y, column, row)
8760      int x; int y; int * column; int * row;
8761 {
8762   *column = EventToSquare(x, BOARD_WIDTH);
8763   if (flipView && *column >= 0)
8764     *column = BOARD_WIDTH - 1 - *column;
8765   *row = EventToSquare(y, BOARD_HEIGHT);
8766   if (!flipView && *row >= 0)
8767     *row = BOARD_HEIGHT - 1 - *row;
8768 }
8769
8770 /*   Utilities  */
8771
8772 #undef Max  /* just in case */
8773 #undef Min
8774 #define Max(a, b) ((a) > (b) ? (a) : (b))
8775 #define Min(a, b) ((a) < (b) ? (a) : (b))
8776
8777 static void
8778 SetRect(rect, x, y, width, height)
8779      XRectangle * rect; int x; int y; int width; int height;
8780 {
8781   rect->x = x;
8782   rect->y = y;
8783   rect->width  = width;
8784   rect->height = height;
8785 }
8786
8787 /*      Test if two frames overlap. If they do, return
8788         intersection rect within old and location of
8789         that rect within new. */
8790
8791 static Boolean
8792 Intersect(old, new, size, area, pt)
8793      XPoint * old; XPoint * new;
8794      int size; XRectangle * area; XPoint * pt;
8795 {
8796   if (old->x > new->x + size || new->x > old->x + size ||
8797       old->y > new->y + size || new->y > old->y + size) {
8798     return False;
8799   } else {
8800     SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8801             size - abs(old->x - new->x), size - abs(old->y - new->y));
8802     pt->x = Max(old->x - new->x, 0);
8803     pt->y = Max(old->y - new->y, 0);
8804     return True;
8805   }
8806 }
8807
8808 /*      For two overlapping frames, return the rect(s)
8809         in the old that do not intersect with the new.   */
8810
8811 static void
8812 CalcUpdateRects(old, new, size, update, nUpdates)
8813      XPoint * old; XPoint * new; int size;
8814      XRectangle update[]; int * nUpdates;
8815 {
8816   int        count;
8817
8818   /* If old = new (shouldn't happen) then nothing to draw */
8819   if (old->x == new->x && old->y == new->y) {
8820     *nUpdates = 0;
8821     return;
8822   }
8823   /* Work out what bits overlap. Since we know the rects
8824      are the same size we don't need a full intersect calc. */
8825   count = 0;
8826   /* Top or bottom edge? */
8827   if (new->y > old->y) {
8828     SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8829     count ++;
8830   } else if (old->y > new->y) {
8831     SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8832                               size, old->y - new->y);
8833     count ++;
8834   }
8835   /* Left or right edge - don't overlap any update calculated above. */
8836   if (new->x > old->x) {
8837     SetRect(&(update[count]), old->x, Max(new->y, old->y),
8838                               new->x - old->x, size - abs(new->y - old->y));
8839     count ++;
8840   } else if (old->x > new->x) {
8841     SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8842                               old->x - new->x, size - abs(new->y - old->y));
8843     count ++;
8844   }
8845   /* Done */
8846   *nUpdates = count;
8847 }
8848
8849 /*      Generate a series of frame coords from start->mid->finish.
8850         The movement rate doubles until the half way point is
8851         reached, then halves back down to the final destination,
8852         which gives a nice slow in/out effect. The algorithmn
8853         may seem to generate too many intermediates for short
8854         moves, but remember that the purpose is to attract the
8855         viewers attention to the piece about to be moved and
8856         then to where it ends up. Too few frames would be less
8857         noticeable.                                             */
8858
8859 static void
8860 Tween(start, mid, finish, factor, frames, nFrames)
8861      XPoint * start; XPoint * mid;
8862      XPoint * finish; int factor;
8863      XPoint frames[]; int * nFrames;
8864 {
8865   int fraction, n, count;
8866
8867   count = 0;
8868
8869   /* Slow in, stepping 1/16th, then 1/8th, ... */
8870   fraction = 1;
8871   for (n = 0; n < factor; n++)
8872     fraction *= 2;
8873   for (n = 0; n < factor; n++) {
8874     frames[count].x = start->x + (mid->x - start->x) / fraction;
8875     frames[count].y = start->y + (mid->y - start->y) / fraction;
8876     count ++;
8877     fraction = fraction / 2;
8878   }
8879
8880   /* Midpoint */
8881   frames[count] = *mid;
8882   count ++;
8883
8884   /* Slow out, stepping 1/2, then 1/4, ... */
8885   fraction = 2;
8886   for (n = 0; n < factor; n++) {
8887     frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8888     frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8889     count ++;
8890     fraction = fraction * 2;
8891   }
8892   *nFrames = count;
8893 }
8894
8895 /*      Draw a piece on the screen without disturbing what's there      */
8896
8897 static void
8898 SelectGCMask(piece, clip, outline, mask)
8899      ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8900 {
8901   GC source;
8902
8903   /* Bitmap for piece being moved. */
8904   if (appData.monoMode) {
8905       *mask = *pieceToSolid(piece);
8906   } else if (useImages) {
8907 #if HAVE_LIBXPM
8908       *mask = xpmMask[piece];
8909 #else
8910       *mask = ximMaskPm[piece%(int)BlackPawn];
8911 #endif
8912   } else {
8913       *mask = *pieceToSolid(piece);
8914   }
8915
8916   /* GC for piece being moved. Square color doesn't matter, but
8917      since it gets modified we make a copy of the original. */
8918   if (White(piece)) {
8919     if (appData.monoMode)
8920       source = bwPieceGC;
8921     else
8922       source = wlPieceGC;
8923   } else {
8924     if (appData.monoMode)
8925       source = wbPieceGC;
8926     else
8927       source = blPieceGC;
8928   }
8929   XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8930
8931   /* Outline only used in mono mode and is not modified */
8932   if (White(piece))
8933     *outline = bwPieceGC;
8934   else
8935     *outline = wbPieceGC;
8936 }
8937
8938 static void
8939 OverlayPiece(piece, clip, outline,  dest)
8940      ChessSquare piece; GC clip; GC outline; Drawable dest;
8941 {
8942   int   kind;
8943
8944   if (!useImages) {
8945     /* Draw solid rectangle which will be clipped to shape of piece */
8946     XFillRectangle(xDisplay, dest, clip,
8947                    0, 0, squareSize, squareSize);
8948     if (appData.monoMode)
8949       /* Also draw outline in contrasting color for black
8950          on black / white on white cases                */
8951       XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8952                  0, 0, squareSize, squareSize, 0, 0, 1);
8953   } else {
8954     /* Copy the piece */
8955     if (White(piece))
8956       kind = 0;
8957     else
8958       kind = 2;
8959     XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8960               dest, clip,
8961               0, 0, squareSize, squareSize,
8962               0, 0);
8963   }
8964 }
8965
8966 /* Animate the movement of a single piece */
8967
8968 static void
8969 BeginAnimation(anim, piece, startColor, start)
8970      AnimState *anim;
8971      ChessSquare piece;
8972      int startColor;
8973      XPoint * start;
8974 {
8975   Pixmap mask;
8976
8977   /* The old buffer is initialised with the start square (empty) */
8978   BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8979   anim->prevFrame = *start;
8980
8981   /* The piece will be drawn using its own bitmap as a matte    */
8982   SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8983   XSetClipMask(xDisplay, anim->pieceGC, mask);
8984 }
8985
8986 static void
8987 AnimationFrame(anim, frame, piece)
8988      AnimState *anim;
8989      XPoint *frame;
8990      ChessSquare piece;
8991 {
8992   XRectangle updates[4];
8993   XRectangle overlap;
8994   XPoint     pt;
8995   int        count, i;
8996
8997   /* Save what we are about to draw into the new buffer */
8998   XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8999             frame->x, frame->y, squareSize, squareSize,
9000             0, 0);
9001
9002   /* Erase bits of the previous frame */
9003   if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
9004     /* Where the new frame overlapped the previous,
9005        the contents in newBuf are wrong. */
9006     XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
9007               overlap.x, overlap.y,
9008               overlap.width, overlap.height,
9009               pt.x, pt.y);
9010     /* Repaint the areas in the old that don't overlap new */
9011     CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
9012     for (i = 0; i < count; i++)
9013       XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
9014                 updates[i].x - anim->prevFrame.x,
9015                 updates[i].y - anim->prevFrame.y,
9016                 updates[i].width, updates[i].height,
9017                 updates[i].x, updates[i].y);
9018   } else {
9019     /* Easy when no overlap */
9020     XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
9021                   0, 0, squareSize, squareSize,
9022                   anim->prevFrame.x, anim->prevFrame.y);
9023   }
9024
9025   /* Save this frame for next time round */
9026   XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
9027                 0, 0, squareSize, squareSize,
9028                 0, 0);
9029   anim->prevFrame = *frame;
9030
9031   /* Draw piece over original screen contents, not current,
9032      and copy entire rect. Wipes out overlapping piece images. */
9033   OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
9034   XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
9035                 0, 0, squareSize, squareSize,
9036                 frame->x, frame->y);
9037 }
9038
9039 static void
9040 EndAnimation (anim, finish)
9041      AnimState *anim;
9042      XPoint *finish;
9043 {
9044   XRectangle updates[4];
9045   XRectangle overlap;
9046   XPoint     pt;
9047   int        count, i;
9048
9049   /* The main code will redraw the final square, so we
9050      only need to erase the bits that don't overlap.    */
9051   if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
9052     CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
9053     for (i = 0; i < count; i++)
9054       XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
9055                 updates[i].x - anim->prevFrame.x,
9056                 updates[i].y - anim->prevFrame.y,
9057                 updates[i].width, updates[i].height,
9058                 updates[i].x, updates[i].y);
9059   } else {
9060     XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
9061                 0, 0, squareSize, squareSize,
9062                 anim->prevFrame.x, anim->prevFrame.y);
9063   }
9064 }
9065
9066 static void
9067 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
9068      AnimState *anim;
9069      ChessSquare piece; int startColor;
9070      XPoint * start; XPoint * finish;
9071      XPoint frames[]; int nFrames;
9072 {
9073   int n;
9074
9075   BeginAnimation(anim, piece, startColor, start);
9076   for (n = 0; n < nFrames; n++) {
9077     AnimationFrame(anim, &(frames[n]), piece);
9078     FrameDelay(appData.animSpeed);
9079   }
9080   EndAnimation(anim, finish);
9081 }
9082
9083 /* Main control logic for deciding what to animate and how */
9084
9085 void
9086 AnimateMove(board, fromX, fromY, toX, toY)
9087      Board board;
9088      int fromX;
9089      int fromY;
9090      int toX;
9091      int toY;
9092 {
9093   ChessSquare piece;
9094   int hop;
9095   XPoint      start, finish, mid;
9096   XPoint      frames[kFactor * 2 + 1];
9097   int         nFrames, startColor, endColor;
9098
9099   /* Are we animating? */
9100   if (!appData.animate || appData.blindfold)
9101     return;
9102
9103   if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
9104   piece = board[fromY][fromX];
9105   if (piece >= EmptySquare) return;
9106
9107 #if DONT_HOP
9108   hop = FALSE;
9109 #else
9110   hop = (piece == WhiteKnight || piece == BlackKnight);
9111 #endif
9112
9113   if (appData.debugMode) {
9114       fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
9115                              _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
9116              piece, fromX, fromY, toX, toY);  }
9117
9118   ScreenSquare(fromX, fromY, &start, &startColor);
9119   ScreenSquare(toX, toY, &finish, &endColor);
9120
9121   if (hop) {
9122     /* Knight: make diagonal movement then straight */
9123     if (abs(toY - fromY) < abs(toX - fromX)) {
9124        mid.x = start.x + (finish.x - start.x) / 2;
9125        mid.y = finish.y;
9126      } else {
9127        mid.x = finish.x;
9128        mid.y = start.y + (finish.y - start.y) / 2;
9129      }
9130   } else {
9131     mid.x = start.x + (finish.x - start.x) / 2;
9132     mid.y = start.y + (finish.y - start.y) / 2;
9133   }
9134
9135   /* Don't use as many frames for very short moves */
9136   if (abs(toY - fromY) + abs(toX - fromX) <= 2)
9137     Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
9138   else
9139     Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
9140   FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
9141
9142   /* Be sure end square is redrawn */
9143   damage[toY][toX] = True;
9144 }
9145
9146 static void
9147 DragPieceBegin(x, y)
9148      int x; int y;
9149 {
9150     int  boardX, boardY, color;
9151     XPoint corner;
9152
9153     /* Are we animating? */
9154     if (!appData.animateDragging || appData.blindfold)
9155       return;
9156
9157     /* Figure out which square we start in and the
9158        mouse position relative to top left corner. */
9159     BoardSquare(x, y, &boardX, &boardY);
9160     player.startBoardX = boardX;
9161     player.startBoardY = boardY;
9162     ScreenSquare(boardX, boardY, &corner, &color);
9163     player.startSquare  = corner;
9164     player.startColor   = color;
9165 #if 0
9166     /* Start from exactly where the piece is.  This can be confusing
9167        if you start dragging far from the center of the square; most
9168        or all of the piece can be over a different square from the one
9169        the mouse pointer is in. */
9170     player.mouseDelta.x = x - corner.x;
9171     player.mouseDelta.y = y - corner.y;
9172 #else
9173     /* As soon as we start dragging, the piece will jump slightly to
9174        be centered over the mouse pointer. */
9175     player.mouseDelta.x = squareSize/2;
9176     player.mouseDelta.y = squareSize/2;
9177 #endif
9178     /* Initialise animation */
9179     player.dragPiece = PieceForSquare(boardX, boardY);
9180     /* Sanity check */
9181     if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
9182         player.dragActive = True;
9183         BeginAnimation(&player, player.dragPiece, color, &corner);
9184         /* Mark this square as needing to be redrawn. Note that
9185            we don't remove the piece though, since logically (ie
9186            as seen by opponent) the move hasn't been made yet. */
9187            if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
9188               boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
9189            XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
9190                      corner.x, corner.y, squareSize, squareSize,
9191                      0, 0); // [HGM] zh: unstack in stead of grab
9192         damage[boardY][boardX] = True;
9193     } else {
9194         player.dragActive = False;
9195     }
9196 }
9197
9198 static void
9199 DragPieceMove(x, y)
9200      int x; int y;
9201 {
9202     XPoint corner;
9203
9204     /* Are we animating? */
9205     if (!appData.animateDragging || appData.blindfold)
9206       return;
9207
9208     /* Sanity check */
9209     if (! player.dragActive)
9210       return;
9211     /* Move piece, maintaining same relative position
9212        of mouse within square    */
9213     corner.x = x - player.mouseDelta.x;
9214     corner.y = y - player.mouseDelta.y;
9215     AnimationFrame(&player, &corner, player.dragPiece);
9216 #if HIGHDRAG
9217     if (appData.highlightDragging) {
9218         int boardX, boardY;
9219         BoardSquare(x, y, &boardX, &boardY);
9220         SetHighlights(fromX, fromY, boardX, boardY);
9221     }
9222 #endif
9223 }
9224
9225 static void
9226 DragPieceEnd(x, y)
9227      int x; int y;
9228 {
9229     int boardX, boardY, color;
9230     XPoint corner;
9231
9232     /* Are we animating? */
9233     if (!appData.animateDragging || appData.blindfold)
9234       return;
9235
9236     /* Sanity check */
9237     if (! player.dragActive)
9238       return;
9239     /* Last frame in sequence is square piece is
9240        placed on, which may not match mouse exactly. */
9241     BoardSquare(x, y, &boardX, &boardY);
9242     ScreenSquare(boardX, boardY, &corner, &color);
9243     EndAnimation(&player, &corner);
9244
9245     /* Be sure end square is redrawn */
9246     damage[boardY][boardX] = True;
9247
9248     /* This prevents weird things happening with fast successive
9249        clicks which on my Sun at least can cause motion events
9250        without corresponding press/release. */
9251     player.dragActive = False;
9252 }
9253
9254 /* Handle expose event while piece being dragged */
9255
9256 static void
9257 DrawDragPiece ()
9258 {
9259   if (!player.dragActive || appData.blindfold)
9260     return;
9261
9262   /* What we're doing: logically, the move hasn't been made yet,
9263      so the piece is still in it's original square. But visually
9264      it's being dragged around the board. So we erase the square
9265      that the piece is on and draw it at the last known drag point. */
9266   BlankSquare(player.startSquare.x, player.startSquare.y,
9267                 player.startColor, EmptySquare, xBoardWindow);
9268   AnimationFrame(&player, &player.prevFrame, player.dragPiece);
9269   damage[player.startBoardY][player.startBoardX] = TRUE;
9270 }
9271
9272 void
9273 SetProgramStats( FrontEndProgramStats * stats )
9274 {
9275   // [HR] TODO
9276   // [HGM] done, but perhaps backend should call this directly?
9277     EngineOutputUpdate( stats );
9278 }