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