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