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