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