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