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