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