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