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