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