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