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