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