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