First step for a GTK version
[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, 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   Arg args[16];
2141   XtSetArg(args[0], XtNiconic, False);
2142   XtSetValues(shellWidget, args, 1);
2143
2144   XtPopup(shellWidget, XtGrabNone); /* Raise if lowered  */
2145 }
2146
2147 #ifdef IDSIZES
2148   // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
2149 #else
2150 #define BoardSize int
2151 void InitDrawingSizes(BoardSize boardSize, int flags)
2152 {   // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
2153     Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
2154     Arg args[16];
2155     XtGeometryResult gres;
2156     int i;
2157
2158     if(!formWidget) return;
2159
2160     /*
2161      * Enable shell resizing.
2162      */
2163 //    shellArgs[0].value = (XtArgVal) &w;
2164 //    shellArgs[1].value = (XtArgVal) &h;
2165 //    XtGetValues(shellWidget, shellArgs, 2);
2166 //
2167 //    shellArgs[4].value = 2*w; shellArgs[2].value = 10;
2168 //    shellArgs[5].value = 2*h; shellArgs[3].value = 10;
2169 //    XtSetValues(shellWidget, &shellArgs[2], 4);
2170 //
2171 //    XtSetArg(args[0], XtNdefaultDistance, &sep);
2172 //    XtGetValues(formWidget, args, 1);
2173
2174     boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
2175     boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
2176     CreateGrid();
2177
2178 //    XtSetArg(args[0], XtNwidth, boardWidth);
2179 //    XtSetArg(args[1], XtNheight, boardHeight);
2180 //    XtSetValues(boardWidget, args, 2);
2181
2182     timerWidth = (boardWidth - sep) / 2;
2183 //    XtSetArg(args[0], XtNwidth, timerWidth);
2184 //    XtSetValues(whiteTimerWidget, args, 1);
2185 //    XtSetValues(blackTimerWidget, args, 1);
2186 //
2187 //    XawFormDoLayout(formWidget, False);
2188
2189     if (appData.titleInWindow) {
2190         i = 0;
2191 //      XtSetArg(args[i], XtNborderWidth, &bor); i++;
2192 //      XtSetArg(args[i], XtNheight, &h);  i++;
2193 //      XtGetValues(titleWidget, args, i);
2194         if (smallLayout) {
2195             w = boardWidth - 2*bor;
2196         } else {
2197 //          XtSetArg(args[0], XtNwidth, &w);
2198 //          XtGetValues(menuBarWidget, args, 1);
2199             w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
2200         }
2201
2202 //      gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2203 //      if (gres != XtGeometryYes && appData.debugMode) {
2204 //          fprintf(stderr,
2205 //                  _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2206 //                  programName, gres, w, h, wr, hr);
2207 //      }
2208     }
2209
2210     //    XawFormDoLayout(formWidget, True);
2211
2212     /*
2213      * Inhibit shell resizing.
2214      */
2215     shellArgs[0].value = w = (XtArgVal) boardWidth + marginW;
2216     shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
2217     shellArgs[4].value = shellArgs[2].value = w;
2218     shellArgs[5].value = shellArgs[3].value = h;
2219     //    XtSetValues(shellWidget, &shellArgs[0], 6);
2220
2221     // [HGM] pieces: tailor piece bitmaps to needs of specific variant
2222     // (only for xpm)
2223     if(useImages) {
2224       for(i=0; i<4; i++) {
2225         int p;
2226         for(p=0; p<=(int)WhiteKing; p++)
2227            xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
2228         if(gameInfo.variant == VariantShogi) {
2229            xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
2230            xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
2231            xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
2232            xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
2233            xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
2234         }
2235 #ifdef GOTHIC
2236         if(gameInfo.variant == VariantGothic) {
2237            xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
2238         }
2239 #endif
2240 #if !HAVE_LIBXPM
2241         // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
2242         for(p=0; p<=(int)WhiteKing; p++)
2243            ximMaskPm[p] = ximMaskPm2[p]; // defaults
2244         if(gameInfo.variant == VariantShogi) {
2245            ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
2246            ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
2247            ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
2248            ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
2249            ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
2250         }
2251 #ifdef GOTHIC
2252         if(gameInfo.variant == VariantGothic) {
2253            ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[i][(int)WhiteSilver];
2254         }
2255 #endif
2256 #endif
2257       }
2258     } else {
2259       for(i=0; i<2; i++) {
2260         int p;
2261         for(p=0; p<=(int)WhiteKing; p++)
2262            pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
2263         if(gameInfo.variant == VariantShogi) {
2264            pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
2265            pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
2266            pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
2267            pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
2268            pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
2269         }
2270 #ifdef GOTHIC
2271         if(gameInfo.variant == VariantGothic) {
2272            pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
2273         }
2274 #endif
2275       }
2276     }
2277 #if HAVE_LIBXPM
2278     CreateAnimVars();
2279 #endif
2280 }
2281 #endif
2282
2283 int
2284 main(argc, argv)
2285      int argc;
2286      char **argv;
2287 {
2288     int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
2289     XSetWindowAttributes window_attributes;
2290     Arg args[16];
2291     Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
2292     XrmValue vFrom, vTo;
2293     XtGeometryResult gres;
2294     char *p;
2295     XrmDatabase xdb;
2296     int forceMono = False;
2297 #define INDIRECTION
2298 #ifdef INDIRECTION
2299     // [HGM] before anything else, expand any indirection files amongst options
2300     char *argvCopy[1000]; // 1000 seems enough
2301     char newArgs[10000];  // holds actual characters
2302     int k = 0;
2303
2304     srandom(time(0)); // [HGM] book: make random truly random
2305
2306     j = 0;
2307     for(i=0; i<argc; i++) {
2308         if(j >= 1000-2) { printf(_("too many arguments\n")); exit(-1); }
2309 //fprintf(stderr, "arg %s\n", argv[i]);
2310         if(argv[i][0] != '@') argvCopy[j++] = argv[i]; else {
2311             char c;
2312             FILE *f = fopen(argv[i]+1, "rb");
2313             if(f == NULL) { fprintf(stderr, _("ignore %s\n"), argv[i]); continue; } // do not expand non-existing
2314             argvCopy[j++] = newArgs + k; // get ready for first argument from file
2315             while((c = fgetc(f)) != EOF) { // each line of file inserts 1 argument in the list
2316                 if(c == '\n') {
2317                     if(j >= 1000-2) { printf(_("too many arguments\n")); exit(-1); }
2318                     newArgs[k++] = 0;  // terminate current arg
2319                     if(k >= 10000-1) { printf(_("too long arguments\n")); exit(-1); }
2320                     argvCopy[j++] = newArgs + k; // get ready for next
2321                 } else {
2322                     if(k >= 10000-1) { printf(_("too long arguments\n")); exit(-1); }
2323                     newArgs[k++] = c;
2324                 }
2325             }
2326             newArgs[k] = 0;
2327             j--;
2328             fclose(f);
2329         }
2330     }
2331     argvCopy[j] = NULL;
2332     argv = argvCopy;
2333     argc = j;
2334 #if 0
2335     if(appData.debugMode,1) { // OK, appData is not initialized here yet...
2336         for(i=0; i<argc; i++) fprintf(stderr, "argv[%2d] = '%s'\n", i, argv[i]);
2337     }
2338 #endif
2339 #endif
2340
2341
2342     setbuf(stdout, NULL);
2343     setbuf(stderr, NULL);
2344     debugFP = stderr;
2345
2346     programName = strrchr(argv[0], '/');
2347     if (programName == NULL)
2348       programName = argv[0];
2349     else
2350       programName++;
2351
2352 #ifdef ENABLE_NLS
2353     XtSetLanguageProc(NULL, NULL, NULL);
2354     bindtextdomain(PACKAGE, LOCALEDIR);
2355     textdomain(PACKAGE);
2356 #endif
2357
2358     shellWidget =
2359       XtAppInitialize(&appContext, "XBoard", shellOptions,
2360                       XtNumber(shellOptions),
2361                       &argc, argv, xboardResources, NULL, 0);
2362
2363     gtk_init (&argc, &argv);
2364
2365     /* parse glade file */
2366
2367     builder = gtk_builder_new ();
2368     gtk_builder_add_from_file (builder, "gtk-interface.xml", NULL);
2369
2370     GUI_Window = GTK_WIDGET (gtk_builder_get_object (builder, "MainWindow"));
2371     if(!GUI_Window) printf("Error: gtk_builder didn't work!\n");
2372     GUI_Board  = GTK_WIDGET (gtk_builder_get_object (builder, "Board"));
2373     if(!GUI_Board) printf("Error: gtk_builder didn't work!\n");
2374     GUI_Whiteclock  = GTK_WIDGET (gtk_builder_get_object (builder, "WhiteClock"));
2375     if(!GUI_Whiteclock) printf("Error: gtk_builder didn't work!\n");
2376     GUI_Blackclock  = GTK_WIDGET (gtk_builder_get_object (builder, "BlackClock"));
2377     if(!GUI_Blackclock) printf("Error: gtk_builder didn't work!\n");
2378
2379     gtk_builder_connect_signals (builder, NULL);
2380     // don't unref the builder, since we use it to get references to widgets
2381     //    g_object_unref (G_OBJECT (builder));
2382
2383     printf("DEBUG:finished building gtk\n");
2384     /* end parse glade file */
2385
2386     if (argc > 1) {
2387         fprintf(stderr, _("%s: unrecognized argument %s\n"),
2388                 programName, argv[1]);
2389         fprintf(stderr, "Recognized options:\n");
2390         for(i = 0; i < XtNumber(shellOptions); i++) {
2391             j = fprintf(stderr, "  %s%s", shellOptions[i].option,
2392                         (shellOptions[i].argKind == XrmoptionSepArg
2393                          ? " ARG" : ""));
2394             if (i++ < XtNumber(shellOptions)) {
2395                 fprintf(stderr, "%*c%s%s\n", 40 - j, ' ',
2396                         shellOptions[i].option,
2397                         (shellOptions[i].argKind == XrmoptionSepArg
2398                          ? " ARG" : ""));
2399             } else {
2400                 fprintf(stderr, "\n");
2401             }
2402         }
2403         exit(2);
2404     }
2405
2406     if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
2407         chessDir = ".";
2408     } else {
2409         if (chdir(chessDir) != 0) {
2410             fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
2411             perror(chessDir);
2412             exit(1);
2413         }
2414     }
2415
2416     p = getenv("HOME");
2417     if (p == NULL) p = "/tmp";
2418     i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
2419     gameCopyFilename = (char*) malloc(i);
2420     gamePasteFilename = (char*) malloc(i);
2421     snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
2422     snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
2423
2424     XtGetApplicationResources(shellWidget, (XtPointer) &appData,
2425                               clientResources, XtNumber(clientResources),
2426                               NULL, 0);
2427
2428     if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
2429         /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
2430         if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL)  {
2431            printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
2432            exit(errno);
2433         }
2434         setbuf(debugFP, NULL);
2435     }
2436
2437     /* [HGM,HR] make sure board size is acceptable */
2438     if(appData.NrFiles > BOARD_SIZE ||
2439        appData.NrRanks > BOARD_SIZE   )
2440          DisplayFatalError(_("Recompile with BOARD_SIZE > 12, to support this size"), 0, 2);
2441
2442 #if !HIGHDRAG
2443     /* This feature does not work; animation needs a rewrite */
2444     appData.highlightDragging = FALSE;
2445 #endif
2446     InitBackEnd1();
2447
2448     xDisplay = XtDisplay(shellWidget);
2449     xScreen = DefaultScreen(xDisplay);
2450     wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
2451
2452         gameInfo.variant = StringToVariant(appData.variant);
2453         InitPosition(FALSE);
2454 #if 0
2455     /*
2456      * Determine boardSize
2457      */
2458     gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] boardsize: make sure we start as 8x8
2459
2460 //#ifndef IDSIZE
2461     // [HGM] as long as we have not created the possibility to change size while running, start with requested size
2462     gameInfo.boardWidth    = appData.NrFiles > 0 ? appData.NrFiles : 8;
2463     gameInfo.boardHeight   = appData.NrRanks > 0 ? appData.NrRanks : 8;
2464     gameInfo.holdingsWidth = appData.holdingsSize > 0 ? 2 : 0;
2465 #endif
2466
2467
2468 #ifdef IDSIZE
2469     InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
2470 #else
2471     if (isdigit(appData.boardSize[0])) {
2472         i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
2473                    &lineGap, &clockFontPxlSize, &coordFontPxlSize,
2474                    &fontPxlSize, &smallLayout, &tinyLayout);
2475         if (i == 0) {
2476             fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
2477                     programName, appData.boardSize);
2478             exit(2);
2479         }
2480         if (i < 7) {
2481             /* Find some defaults; use the nearest known size */
2482             SizeDefaults *szd, *nearest;
2483             int distance = 99999;
2484             nearest = szd = sizeDefaults;
2485             while (szd->name != NULL) {
2486                 if (abs(szd->squareSize - squareSize) < distance) {
2487                     nearest = szd;
2488                     distance = abs(szd->squareSize - squareSize);
2489                     if (distance == 0) break;
2490                 }
2491                 szd++;
2492             }
2493             if (i < 2) lineGap = nearest->lineGap;
2494             if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
2495             if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
2496             if (i < 5) fontPxlSize = nearest->fontPxlSize;
2497             if (i < 6) smallLayout = nearest->smallLayout;
2498             if (i < 7) tinyLayout = nearest->tinyLayout;
2499         }
2500     } else {
2501         SizeDefaults *szd = sizeDefaults;
2502         if (*appData.boardSize == NULLCHAR) {
2503             while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
2504                    DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
2505               szd++;
2506             }
2507             if (szd->name == NULL) szd--;
2508         } else {
2509             while (szd->name != NULL &&
2510                    StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
2511             if (szd->name == NULL) {
2512                 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
2513                         programName, appData.boardSize);
2514                 exit(2);
2515             }
2516         }
2517         squareSize = szd->squareSize;
2518         lineGap = szd->lineGap;
2519         clockFontPxlSize = szd->clockFontPxlSize;
2520         coordFontPxlSize = szd->coordFontPxlSize;
2521         fontPxlSize = szd->fontPxlSize;
2522         smallLayout = szd->smallLayout;
2523         tinyLayout = szd->tinyLayout;
2524     }
2525
2526     /* Now, using squareSize as a hint, find a good XPM/XIM set size */
2527     if (strlen(appData.pixmapDirectory) > 0) {
2528         p = ExpandPathName(appData.pixmapDirectory);
2529         if (!p) {
2530             fprintf(stderr, _("Error expanding path name \"%s\"\n"),
2531                    appData.pixmapDirectory);
2532             exit(1);
2533         }
2534         if (appData.debugMode) {
2535           fprintf(stderr, _("\
2536 XBoard square size (hint): %d\n\
2537 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
2538         }
2539         squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
2540         if (appData.debugMode) {
2541             fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
2542         }
2543     }
2544
2545     /* [HR] height treated separately (hacked) */
2546     boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
2547     boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
2548     if (appData.showJail == 1) {
2549         /* Jail on top and bottom */
2550         XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2551         XtSetArg(boardArgs[2], XtNheight,
2552                  boardHeight + 2*(lineGap + squareSize));
2553     } else if (appData.showJail == 2) {
2554         /* Jail on sides */
2555         XtSetArg(boardArgs[1], XtNwidth,
2556                  boardWidth + 2*(lineGap + squareSize));
2557         XtSetArg(boardArgs[2], XtNheight, boardHeight);
2558     } else {
2559         /* No jail */
2560         XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2561         XtSetArg(boardArgs[2], XtNheight, boardHeight);
2562     }
2563
2564     /*
2565      * Determine what fonts to use.
2566      */
2567     appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2568     clockFontID = XLoadFont(xDisplay, appData.clockFont);
2569     clockFontStruct = XQueryFont(xDisplay, clockFontID);
2570     appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2571     coordFontID = XLoadFont(xDisplay, appData.coordFont);
2572     coordFontStruct = XQueryFont(xDisplay, coordFontID);
2573     appData.font = FindFont(appData.font, fontPxlSize);
2574     countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
2575     countFontStruct = XQueryFont(xDisplay, countFontID);
2576 //    appData.font = FindFont(appData.font, fontPxlSize);
2577
2578     xdb = XtDatabase(xDisplay);
2579     XrmPutStringResource(&xdb, "*font", appData.font);
2580
2581     /*
2582      * Detect if there are not enough colors available and adapt.
2583      */
2584     if (DefaultDepth(xDisplay, xScreen) <= 2) {
2585       appData.monoMode = True;
2586     }
2587
2588     if (!appData.monoMode) {
2589         vFrom.addr = (caddr_t) appData.lightSquareColor;
2590         vFrom.size = strlen(appData.lightSquareColor);
2591         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2592         if (vTo.addr == NULL) {
2593           appData.monoMode = True;
2594           forceMono = True;
2595         } else {
2596           lightSquareColor = *(Pixel *) vTo.addr;
2597         }
2598     }
2599     if (!appData.monoMode) {
2600         vFrom.addr = (caddr_t) appData.darkSquareColor;
2601         vFrom.size = strlen(appData.darkSquareColor);
2602         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2603         if (vTo.addr == NULL) {
2604           appData.monoMode = True;
2605           forceMono = True;
2606         } else {
2607           darkSquareColor = *(Pixel *) vTo.addr;
2608         }
2609     }
2610     if (!appData.monoMode) {
2611         vFrom.addr = (caddr_t) appData.whitePieceColor;
2612         vFrom.size = strlen(appData.whitePieceColor);
2613         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2614         if (vTo.addr == NULL) {
2615           appData.monoMode = True;
2616           forceMono = True;
2617         } else {
2618           whitePieceColor = *(Pixel *) vTo.addr;
2619         }
2620     }
2621     if (!appData.monoMode) {
2622         vFrom.addr = (caddr_t) appData.blackPieceColor;
2623         vFrom.size = strlen(appData.blackPieceColor);
2624         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2625         if (vTo.addr == NULL) {
2626           appData.monoMode = True;
2627           forceMono = True;
2628         } else {
2629           blackPieceColor = *(Pixel *) vTo.addr;
2630         }
2631     }
2632
2633     if (!appData.monoMode) {
2634         vFrom.addr = (caddr_t) appData.highlightSquareColor;
2635         vFrom.size = strlen(appData.highlightSquareColor);
2636         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2637         if (vTo.addr == NULL) {
2638           appData.monoMode = True;
2639           forceMono = True;
2640         } else {
2641           highlightSquareColor = *(Pixel *) vTo.addr;
2642         }
2643     }
2644
2645     if (!appData.monoMode) {
2646         vFrom.addr = (caddr_t) appData.premoveHighlightColor;
2647         vFrom.size = strlen(appData.premoveHighlightColor);
2648         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2649         if (vTo.addr == NULL) {
2650           appData.monoMode = True;
2651           forceMono = True;
2652         } else {
2653           premoveHighlightColor = *(Pixel *) vTo.addr;
2654         }
2655     }
2656
2657     if (forceMono) {
2658       fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2659               programName);
2660       
2661       if (appData.bitmapDirectory == NULL ||
2662               appData.bitmapDirectory[0] == NULLCHAR)
2663             appData.bitmapDirectory = DEF_BITMAP_DIR;
2664     }
2665
2666     if (appData.lowTimeWarning && !appData.monoMode) {
2667       vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2668       vFrom.size = strlen(appData.lowTimeWarningColor);
2669       XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2670       if (vTo.addr == NULL) 
2671                 appData.monoMode = True;
2672       else
2673                 lowTimeWarningColor = *(Pixel *) vTo.addr;
2674     }
2675
2676     if (appData.monoMode && appData.debugMode) {
2677         fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2678                 (unsigned long) XWhitePixel(xDisplay, xScreen),
2679                 (unsigned long) XBlackPixel(xDisplay, xScreen));
2680     }
2681
2682     if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2683         parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2684         parse_cpair(ColorChannel1, appData.colorChannel1) < 0  ||
2685         parse_cpair(ColorChannel, appData.colorChannel) < 0  ||
2686         parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2687         parse_cpair(ColorTell, appData.colorTell) < 0 ||
2688         parse_cpair(ColorChallenge, appData.colorChallenge) < 0  ||
2689         parse_cpair(ColorRequest, appData.colorRequest) < 0  ||
2690         parse_cpair(ColorSeek, appData.colorSeek) < 0  ||
2691         parse_cpair(ColorNormal, appData.colorNormal) < 0)
2692       {
2693           if (appData.colorize) {
2694               fprintf(stderr,
2695                       _("%s: can't parse color names; disabling colorization\n"),
2696                       programName);
2697           }
2698           appData.colorize = FALSE;
2699       }
2700     textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2701     textColors[ColorNone].attr = 0;
2702
2703     printf("DEBUG: I'm here 0\n");
2704
2705     //    XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2706
2707     /*
2708      * widget hierarchy
2709      */
2710     if (tinyLayout) {
2711         layoutName = "tinyLayout";
2712     } else if (smallLayout) {
2713         layoutName = "smallLayout";
2714     } else {
2715         layoutName = "normalLayout";
2716     }
2717     /* Outer layoutWidget is there only to provide a name for use in
2718        resources that depend on the layout style */
2719     layoutWidget =
2720       XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2721                             layoutArgs, XtNumber(layoutArgs));
2722     formWidget =
2723       XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2724                             formArgs, XtNumber(formArgs));
2725     XtSetArg(args[0], XtNdefaultDistance, &sep);
2726     XtGetValues(formWidget, args, 1);
2727
2728     j = 0;
2729     widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2730     XtSetArg(args[0], XtNtop,    XtChainTop);
2731     XtSetArg(args[1], XtNbottom, XtChainTop);
2732     XtSetValues(menuBarWidget, args, 2);
2733
2734     widgetList[j++] = whiteTimerWidget =
2735       XtCreateWidget("whiteTime", labelWidgetClass,
2736                      formWidget, timerArgs, XtNumber(timerArgs));
2737     XtSetArg(args[0], XtNfont, clockFontStruct);
2738     XtSetArg(args[1], XtNtop,    XtChainTop);
2739     XtSetArg(args[2], XtNbottom, XtChainTop);
2740     XtSetValues(whiteTimerWidget, args, 3);
2741
2742     widgetList[j++] = blackTimerWidget =
2743       XtCreateWidget("blackTime", labelWidgetClass,
2744                      formWidget, timerArgs, XtNumber(timerArgs));
2745     XtSetArg(args[0], XtNfont, clockFontStruct);
2746     XtSetArg(args[1], XtNtop,    XtChainTop);
2747     XtSetArg(args[2], XtNbottom, XtChainTop);
2748     XtSetValues(blackTimerWidget, args, 3);
2749     printf("DEBUG: I'm here 1\n");
2750
2751     if (appData.titleInWindow) {
2752         widgetList[j++] = titleWidget =
2753           XtCreateWidget("title", labelWidgetClass, formWidget,
2754                          titleArgs, XtNumber(titleArgs));
2755         XtSetArg(args[0], XtNtop,    XtChainTop);
2756         XtSetArg(args[1], XtNbottom, XtChainTop);
2757         XtSetValues(titleWidget, args, 2);
2758     }
2759
2760     if (appData.showButtonBar) {
2761       widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2762       XtSetArg(args[0], XtNleft,  XtChainRight); // [HGM] glue to right window edge
2763       XtSetArg(args[1], XtNright, XtChainRight); //       for good run-time sizing
2764       XtSetArg(args[2], XtNtop,    XtChainTop);
2765       XtSetArg(args[3], XtNbottom, XtChainTop);
2766       XtSetValues(buttonBarWidget, args, 4);
2767     }
2768
2769 //    widgetList[j++] = messageWidget =
2770 //      XtCreateWidget("message", labelWidgetClass, formWidget,
2771 //                   messageArgs, XtNumber(messageArgs));
2772 //    XtSetArg(args[0], XtNtop,    XtChainTop);
2773 //    XtSetArg(args[1], XtNbottom, XtChainTop);
2774 //    XtSetValues(messageWidget, args, 2);
2775 //
2776 //    widgetList[j++] = boardWidget =
2777 //      XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2778 //                   XtNumber(boardArgs));
2779 //
2780 //    XtManageChildren(widgetList, j);
2781 //
2782 //    timerWidth = (boardWidth - sep) / 2;
2783 //    XtSetArg(args[0], XtNwidth, timerWidth);
2784 //    XtSetValues(whiteTimerWidget, args, 1);
2785 //    XtSetValues(blackTimerWidget, args, 1);
2786 //
2787 //    XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2788 //    XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2789 //    XtGetValues(whiteTimerWidget, args, 2);
2790 //
2791 //    if (appData.showButtonBar) {
2792 //      XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2793 //      XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2794 //      XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2795 //    }
2796 //
2797
2798     /*
2799      *  gtk set properties of widgets
2800      */
2801
2802     /* set board size */
2803     gtk_widget_set_size_request(GTK_WIDGET(GUI_Board),
2804                                 boardWidth,boardHeight);
2805
2806     /* end gtk set properties of widgets */
2807
2808     printf("DEBUG: made it.\n");
2809
2810     /*
2811      * formWidget uses these constraints but they are stored
2812      * in the children.
2813      */
2814 //    i = 0;
2815 //    XtSetArg(args[i], XtNfromHoriz, 0); i++;
2816 //    XtSetValues(menuBarWidget, args, i);
2817 //    if (appData.titleInWindow) {
2818 //      if (smallLayout) {
2819 //    printf("DEBUG: made it a.\n");
2820 //          i = 0;
2821 //          XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2822 //          XtSetValues(whiteTimerWidget, args, i);
2823 //          i = 0;
2824 //          XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2825 //          XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2826 //          XtSetValues(blackTimerWidget, args, i);
2827 //          i = 0;
2828 //          XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2829 //            XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2830 //          XtSetValues(titleWidget, args, i);
2831 //          i = 0;
2832 //          XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2833 //          XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2834 //          XtSetValues(messageWidget, args, i);
2835 //          if (appData.showButtonBar) {
2836 //            i = 0;
2837 //            XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2838 //            XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2839 //            XtSetValues(buttonBarWidget, args, i);
2840 //          }
2841 //      } else {
2842 //    printf("DEBUG: made it b.\n");
2843 //          i = 0;
2844 //          XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2845 //          XtSetValues(whiteTimerWidget, args, i);
2846 //          i = 0;
2847 //          XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2848 //          XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2849 //          XtSetValues(blackTimerWidget, args, i);
2850 //          i = 0;
2851 //          XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2852 //          XtSetValues(titleWidget, args, i);
2853 //          i = 0;
2854 //          XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2855 //          XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2856 //          XtSetValues(messageWidget, args, i);
2857 //          if (appData.showButtonBar) {
2858 //            i = 0;
2859 //            XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2860 //            XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2861 //            XtSetValues(buttonBarWidget, args, i);
2862 //          }
2863 //      }
2864 //    } else {    printf("DEBUG: made it c.\n");
2865 //
2866 //      i = 0;
2867 //      XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2868 //      XtSetValues(whiteTimerWidget, args, i);
2869 //      i = 0;
2870 //      XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2871 //      XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2872 //      XtSetValues(blackTimerWidget, args, i);
2873 //      i = 0;
2874 //      XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2875 //      XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2876 //      XtSetValues(messageWidget, args, i);
2877 //      if (appData.showButtonBar) {
2878 //        i = 0;
2879 //        XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2880 //        XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2881 //        XtSetValues(buttonBarWidget, args, i);
2882 //      }
2883 //    }
2884 //    printf("DEBUG: made it 1.\n");
2885 //    i = 0;
2886 //    XtSetArg(args[0], XtNfromVert, messageWidget);
2887 //    XtSetArg(args[1], XtNtop,    XtChainTop);
2888 //    XtSetArg(args[2], XtNbottom, XtChainBottom);
2889 //    XtSetArg(args[3], XtNleft,   XtChainLeft);
2890 //    XtSetArg(args[4], XtNright,  XtChainRight);
2891 //    XtSetValues(boardWidget, args, 5);
2892 //
2893 //    XtRealizeWidget(shellWidget);
2894 //
2895     printf("DEBUG: made it 2.\n");
2896
2897     /*
2898      * Correct the width of the message and title widgets.
2899      * It is not known why some systems need the extra fudge term.
2900      * The value "2" is probably larger than needed.
2901      */
2902     //    XawFormDoLayout(formWidget, False);
2903
2904 #define WIDTH_FUDGE 2
2905 //    i = 0;
2906 //    XtSetArg(args[i], XtNborderWidth, &bor);  i++;
2907 //    XtSetArg(args[i], XtNheight, &h);  i++;
2908 //    XtGetValues(messageWidget, args, i);
2909     if (appData.showButtonBar) {
2910 //      i = 0;
2911 //      XtSetArg(args[i], XtNwidth, &w);  i++;
2912 //      XtGetValues(buttonBarWidget, args, i);
2913 //      w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2914     } else {
2915 //      w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2916     }
2917 //
2918 //    gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2919     if (gres != XtGeometryYes && appData.debugMode) {
2920       fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2921               programName, gres, w, h, wr, hr);
2922     }
2923
2924     /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2925     /* The size used for the child widget in layout lags one resize behind
2926        its true size, so we resize a second time, 1 pixel smaller.  Yeech! */
2927     w--;
2928 //    gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2929     if (gres != XtGeometryYes && appData.debugMode) {
2930       fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2931               programName, gres, w, h, wr, hr);
2932     }
2933     /* !! end hack */
2934 //    XtSetArg(args[0], XtNleft,  XtChainLeft);  // [HGM] glue ends for good run-time sizing
2935 //    XtSetArg(args[1], XtNright, XtChainRight);
2936 //    XtSetValues(messageWidget, args, 2);
2937 //
2938     if (appData.titleInWindow) {
2939         i = 0;
2940 //      XtSetArg(args[i], XtNborderWidth, &bor); i++;
2941 //      XtSetArg(args[i], XtNheight, &h);  i++;
2942 //      XtGetValues(titleWidget, args, i);
2943         if (smallLayout) {
2944             w = boardWidth - 2*bor;
2945         } else {
2946 //          XtSetArg(args[0], XtNwidth, &w);
2947 //          XtGetValues(menuBarWidget, args, 1);
2948 //          w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2949         }
2950
2951 //      gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2952         if (gres != XtGeometryYes && appData.debugMode) {
2953             fprintf(stderr,
2954                     _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2955                     programName, gres, w, h, wr, hr);
2956         }
2957     }
2958 //    XawFormDoLayout(formWidget, True);
2959 //
2960 //    xBoardWindow = XtWindow(boardWidget);
2961 //
2962     // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2963     //       not need to go into InitDrawingSizes().
2964 #endif
2965
2966     if (appData.alwaysPromoteToQueen) {
2967       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Always Queen")),TRUE);
2968     }
2969     if (appData.animateDragging) {
2970       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Animate Dragging")),TRUE);
2971     }
2972     if (appData.animate) {
2973       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Animate Moving")),TRUE);
2974     }
2975     if (appData.autoComment) {
2976       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Auto Comment")),TRUE);
2977     }
2978     if (appData.autoCallFlag) {
2979       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Auto Flag")),TRUE);
2980     }
2981     if (appData.autoFlipView) {
2982       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Auto Flip View")),TRUE);
2983     }
2984     if (appData.autoObserve) {
2985       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Auto Observe")),TRUE);
2986     }
2987     if (appData.autoRaiseBoard) {
2988       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Auto Raise Board")),TRUE);
2989     }
2990     if (appData.autoSaveGames) {
2991       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Auto Save")),TRUE);
2992     }
2993     if (appData.saveGameFile[0] != NULLCHAR) {
2994       /* Can't turn this off from menu */
2995       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Auto Save")),TRUE);
2996       gtk_action_set_sensitive(GTK_ACTION (gtk_builder_get_object (builder, "menuOptions.Auto Save")),FALSE);
2997     }
2998     if (appData.blindfold) {
2999       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Blindfold")),TRUE);
3000     }
3001     if (appData.flashCount > 0) {
3002       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Flash Moves")),TRUE);
3003     }
3004     if (appData.getMoveList) {
3005       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Get Move List")),TRUE);
3006     }
3007 #if HIGHDRAG
3008     if (appData.highlightDragging) {
3009       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Highlight Dragging")),TRUE);
3010     }
3011 #endif
3012     if (appData.highlightLastMove) {
3013       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Highlight Last Move")),TRUE);
3014     }
3015     if (appData.icsAlarm) {
3016       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.ICS Alarm")),TRUE);
3017     }
3018     if (appData.ringBellAfterMoves) {
3019       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Move Sound")),TRUE);
3020     }
3021     if (appData.oldSaveStyle) {
3022       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Old Save Style")),TRUE);
3023     }
3024     if (appData.periodicUpdates) {
3025       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Periodic Updates")),TRUE);
3026     }
3027     if (appData.ponderNextMove) {
3028       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Ponder Next Move")),TRUE);
3029     }
3030     if (appData.popupExitMessage) {
3031       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Popup Exit Message")),TRUE);
3032     }
3033     if (appData.popupMoveErrors) {
3034       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Popup Move Errors")),TRUE);
3035     }
3036     if (appData.premove) {
3037       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Premove")),TRUE);
3038     }
3039     if (appData.quietPlay) {
3040       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Quit Play")),TRUE);
3041     }
3042     if (appData.showCoords) {
3043       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Show Coords")),TRUE);
3044     }
3045     if (appData.showThinking) {
3046       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Show Thinking")),TRUE);
3047     }
3048     if (appData.testLegality) {
3049       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Test Legality")),TRUE);
3050     }
3051
3052     /*
3053      * Create an icon.
3054      */
3055 //    ReadBitmap(&wIconPixmap, "icon_white.bm",
3056 //             icon_white_bits, icon_white_width, icon_white_height);
3057 //    ReadBitmap(&bIconPixmap, "icon_black.bm",
3058 //             icon_black_bits, icon_black_width, icon_black_height);
3059 //    iconPixmap = wIconPixmap;
3060 //    i = 0;
3061 //    XtSetArg(args[i], XtNiconPixmap, iconPixmap);  i++;
3062 //    XtSetValues(shellWidget, args, i);
3063 //
3064
3065     printf("DEBUG: creating svgs.\n");
3066
3067     /* load square colors */
3068     SVGLightSquare   = load_pixbuf("svg/LightSquare.svg");
3069     SVGDarkSquare    = load_pixbuf("svg/DarkSquare.svg");
3070     SVGNeutralSquare = load_pixbuf("svg/NeutralSquare.svg");
3071
3072     /* use two icons to indicate if it is white's or black's turn */
3073     WhiteIcon  = load_pixbuf("svg/icon_white.svg");
3074     BlackIcon  = load_pixbuf("svg/icon_black.svg");
3075     WindowIcon = WhiteIcon;
3076     gtk_window_set_icon(GTK_WINDOW(GUI_Window),WindowIcon);
3077
3078     /* do resizing to a fixed aspect ratio */
3079     GdkGeometry hints;
3080     hints.min_aspect = 0.8;
3081     hints.max_aspect = 0.8;
3082     gtk_window_set_geometry_hints (GTK_WINDOW (GUI_Window),
3083                                    GTK_WIDGET (GUI_Window),
3084                                    &hints,
3085                                    GDK_HINT_ASPECT);
3086
3087     /* realize window */
3088     gtk_widget_show (GUI_Window);
3089
3090     CreateGCs();
3091     CreateGrid();
3092     CreatePieces();
3093
3094     CreatePieceMenus();
3095
3096     if (appData.animate || appData.animateDragging)
3097       CreateAnimVars();
3098
3099     printf("DEBUG: created stuff.\n");
3100
3101
3102 //    XtAugmentTranslations(formWidget,
3103 //                        XtParseTranslationTable(globalTranslations));
3104 //    XtAugmentTranslations(boardWidget,
3105 //                        XtParseTranslationTable(boardTranslations));
3106 //    XtAugmentTranslations(whiteTimerWidget,
3107 //                        XtParseTranslationTable(whiteTranslations));
3108 //    XtAugmentTranslations(blackTimerWidget,
3109 //                        XtParseTranslationTable(blackTranslations));
3110 //
3111     InitBackEnd2();
3112
3113     printf("DEBUG: back end initiated.\n");
3114
3115     if (errorExitStatus == -1) {
3116         if (appData.icsActive) {
3117             /* We now wait until we see "login:" from the ICS before
3118                sending the logon script (problems with timestamp otherwise) */
3119             /*ICSInitScript();*/
3120             if (appData.icsInputBox) ICSInputBoxPopUp();
3121         }
3122
3123         signal(SIGINT, IntSigHandler);
3124         signal(SIGTERM, IntSigHandler);
3125         if (*appData.cmailGameName != NULLCHAR) {
3126             signal(SIGUSR1, CmailSigHandler);
3127         }
3128     }
3129     gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
3130     InitPosition(TRUE);
3131
3132     /*
3133      * Create a cursor for the board widget.
3134      * (This needs to be called after the window has been created to have access to board-window)
3135      */
3136
3137     BoardCursor = gdk_cursor_new(GDK_HAND2);
3138     gdk_window_set_cursor(GUI_Board->window, BoardCursor);
3139     gdk_cursor_destroy(BoardCursor);
3140
3141     /* end cursor */
3142     printf("DEBUG: going into main.\n");
3143
3144     gtk_main ();
3145
3146     if (appData.debugMode) fclose(debugFP); // [DM] debug
3147     return 0;
3148 }
3149
3150 void
3151 ShutDownFrontEnd()
3152 {
3153     if (appData.icsActive && oldICSInteractionTitle != NULL) {
3154         DisplayIcsInteractionTitle(oldICSInteractionTitle);
3155     }
3156     unlink(gameCopyFilename);
3157     unlink(gamePasteFilename);
3158 }
3159
3160 RETSIGTYPE
3161 IntSigHandler(sig)
3162      int sig;
3163 {
3164     ExitEvent(sig);
3165 }
3166
3167 RETSIGTYPE
3168 CmailSigHandler(sig)
3169      int sig;
3170 {
3171     int dummy = 0;
3172     int error;
3173
3174     signal(SIGUSR1, SIG_IGN);   /* suspend handler     */
3175
3176     /* Activate call-back function CmailSigHandlerCallBack()             */
3177     OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
3178
3179     signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
3180 }
3181
3182 void
3183 CmailSigHandlerCallBack(isr, closure, message, count, error)
3184      InputSourceRef isr;
3185      VOIDSTAR closure;
3186      char *message;
3187      int count;
3188      int error;
3189 {
3190     BoardToTop();
3191     ReloadCmailMsgEvent(TRUE);  /* Reload cmail msg  */
3192 }
3193 /**** end signal code ****/
3194
3195
3196 void
3197 ICSInitScript()
3198 {
3199     FILE *f;
3200     char buf[MSG_SIZ];
3201     char *p;
3202
3203     f = fopen(appData.icsLogon, "r");
3204     if (f == NULL) {
3205         p = getenv("HOME");
3206         if (p != NULL) {
3207             strcpy(buf, p);
3208             strcat(buf, "/");
3209             strcat(buf, appData.icsLogon);
3210             f = fopen(buf, "r");
3211         }
3212     }
3213     if (f != NULL)
3214       ProcessICSInitScript(f);
3215 }
3216
3217 void
3218 ResetFrontEnd()
3219 {
3220     CommentPopDown();
3221     EditCommentPopDown();
3222     TagsPopDown();
3223     return;
3224 }
3225
3226 typedef struct {
3227     char *name;
3228     gboolean value;
3229 } Enables;
3230
3231 void
3232 SetMenuEnables(enab)
3233      Enables *enab;
3234 {
3235   GObject *o;
3236
3237   if (!builder) return;
3238   while (enab->name != NULL) {
3239     o = gtk_builder_get_object(builder, enab->name);
3240     if(GTK_IS_WIDGET(o))
3241       gtk_widget_set_sensitive(GTK_WIDGET (o),enab->value);
3242     else
3243       {
3244         if(GTK_IS_ACTION(o))
3245           gtk_action_set_sensitive(GTK_ACTION (o),enab->value);
3246         else
3247           DisplayError(enab->name, 0);
3248       }
3249     enab++;
3250   }
3251 }
3252
3253 Enables icsEnables[] = {
3254     { "menuFile.Mail Move", False },
3255     { "menuFile.Reload CMail Message", False },
3256     { "menuMode.Machine Black", False },
3257     { "menuMode.Machine White", False },
3258     { "menuMode.Analysis Mode", False },
3259     { "menuMode.Analyze File", False },
3260     { "menuMode.Two Machines", False },
3261 #ifndef ZIPPY
3262     { "menuHelp.Hint", False },
3263     { "menuHelp.Book", False },
3264     { "menuStep.Move Now", False },
3265     { "menuOptions.Periodic Updates", False },
3266     { "menuOptions.Hide Thinking", False },
3267     { "menuOptions.Ponder Next Move", False },
3268 #endif
3269     { NULL, False }
3270 };
3271
3272 Enables ncpEnables[] = {
3273     { "menuFile.Mail Move", False },
3274     { "menuFile.Reload CMail Message", False },
3275     { "menuMode.Machine White", False },
3276     { "menuMode.Machine Black", False },
3277     { "menuMode.Analysis Mode", False },
3278     { "menuMode.Analyze File", False },
3279     { "menuMode.Two Machines", False },
3280     { "menuMode.ICS Client", False },
3281     { "menuMode.ICS Input Box", False },
3282     { "Action", False },
3283     { "menuStep.Revert", False },
3284     { "menuStep.Move Now", False },
3285     { "menuStep.Retract Move", False },
3286     { "menuOptions.Auto Comment", False },
3287     { "menuOptions.Auto Flag", False },
3288     { "menuOptions.Auto Flip View", False },
3289     { "menuOptions.Auto Observe", False },
3290     { "menuOptions.Auto Raise Board", False },
3291     { "menuOptions.Get Move List", False },
3292     { "menuOptions.ICS Alarm", False },
3293     { "menuOptions.Move Sound", False },
3294     { "menuOptions.Quiet Play", False },
3295     { "menuOptions.Hide Thinking", False },
3296     { "menuOptions.Periodic Updates", False },
3297     { "menuOptions.Ponder Next Move", False },
3298     { "menuHelp.Hint", False },
3299     { "menuHelp.Book", False },
3300     { NULL, False }
3301 };
3302
3303 Enables gnuEnables[] = {
3304     { "menuMode.ICS Client", False },
3305     { "menuMode.ICS Input Box", False },
3306     { "menuAction.Accept", False },
3307     { "menuAction.Decline", False },
3308     { "menuAction.Rematch", False },
3309     { "menuAction.Adjourn", False },
3310     { "menuAction.Stop Examining", False },
3311     { "menuAction.Stop Observing", False },
3312     { "menuStep.Revert", False },
3313     { "menuOptions.Auto Comment", False },
3314     { "menuOptions.Auto Observe", False },
3315     { "menuOptions.Auto Raise Board", False },
3316     { "menuOptions.Get Move List", False },
3317     { "menuOptions.Premove", False },
3318     { "menuOptions.Quiet Play", False },
3319
3320     /* The next two options rely on SetCmailMode being called *after*    */
3321     /* SetGNUMode so that when GNU is being used to give hints these     */
3322     /* menu options are still available                                  */
3323
3324     { "menuFile.Mail Move", False },
3325     { "menuFile.Reload CMail Message", False },
3326     { NULL, False }
3327 };
3328
3329 Enables cmailEnables[] = {
3330     { "Action", True },
3331     { "menuAction.Call Flag", False },
3332     { "menuAction.Draw", True },
3333     { "menuAction.Adjourn", False },
3334     { "menuAction.Abort", False },
3335     { "menuAction.Stop Observing", False },
3336     { "menuAction.Stop Examining", False },
3337     { "menuFile.Mail Move", True },
3338     { "menuFile.Reload CMail Message", True },
3339     { NULL, False }
3340 };
3341
3342 Enables trainingOnEnables[] = {
3343   { "menuMode.Edit Comment", False },
3344   { "menuMode.Pause", False },
3345   { "menuStep.Forward", False },
3346   { "menuStep.Backward", False },
3347   { "menuStep.Forward to End", False },
3348   { "menuStep.Back to Start", False },
3349   { "menuStep.Move Now", False },
3350   { "menuStep.Truncate Game", False },
3351   { NULL, False }
3352 };
3353
3354 Enables trainingOffEnables[] = {
3355   { "menuMode.Edit Comment", True },
3356   { "menuMode.Pause", True },
3357   { "menuStep.Forward", True },
3358   { "menuStep.Backward", True },
3359   { "menuStep.Forward to End", True },
3360   { "menuStep.Back to Start", True },
3361   { "menuStep.Move Now", True },
3362   { "menuStep.Truncate Game", True },
3363   { NULL, False }
3364 };
3365
3366 Enables machineThinkingEnables[] = {
3367   { "menuFile.Load Game", False },
3368   { "menuFile.Load Next Game", False },
3369   { "menuFile.Load Previous Game", False },
3370   { "menuFile.Reload Same Game", False },
3371   { "menuFile.Paste Game", False },
3372   { "menuFile.Load Position", False },
3373   { "menuFile.Load Next Position", False },
3374   { "menuFile.Load Previous Position", False },
3375   { "menuFile.Reload Same Position", False },
3376   { "menuFile.Paste Position", False },
3377   { "menuMode.Machine White", False },
3378   { "menuMode.Machine Black", False },
3379   { "menuMode.Two Machines", False },
3380   { "menuStep.Retract Move", False },
3381   { NULL, False }
3382 };
3383
3384 Enables userThinkingEnables[] = {
3385   { "menuFile.Load Game", True },
3386   { "menuFile.Load Next Game", True },
3387   { "menuFile.Load Previous Game", True },
3388   { "menuFile.Reload Same Game", True },
3389   { "menuFile.Paste Game", True },
3390   { "menuFile.Load Position", True },
3391   { "menuFile.Load Next Position", True },
3392   { "menuFile.Load Previous Position", True },
3393   { "menuFile.Reload Same Position", True },
3394   { "menuFile.Paste Position", True },
3395   { "menuMode.Machine White", True },
3396   { "menuMode.Machine Black", True },
3397   { "menuMode.Two Machines", True },
3398   { "menuStep.Retract Move", True },
3399   { NULL, False }
3400 };
3401
3402 void SetICSMode()
3403 {
3404   SetMenuEnables(icsEnables);
3405
3406 #ifdef ZIPPY
3407   if (appData.zippyPlay && !appData.noChessProgram)   /* [DM] icsEngineAnalyze */
3408      XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
3409 #endif
3410 }
3411
3412 void
3413 SetNCPMode()
3414 {
3415   SetMenuEnables(ncpEnables);
3416 }
3417
3418 void
3419 SetGNUMode()
3420 {
3421   SetMenuEnables(gnuEnables);
3422 }
3423
3424 void
3425 SetCmailMode()
3426 {
3427   SetMenuEnables(cmailEnables);
3428 }
3429
3430 void
3431 SetTrainingModeOn()
3432 {
3433   SetMenuEnables(trainingOnEnables);
3434   if (appData.showButtonBar) {
3435     XtSetSensitive(buttonBarWidget, False);
3436   }
3437   CommentPopDown();
3438 }
3439
3440 void
3441 SetTrainingModeOff()
3442 {
3443   SetMenuEnables(trainingOffEnables);
3444   if (appData.showButtonBar) {
3445     XtSetSensitive(buttonBarWidget, True);
3446   }
3447 }
3448
3449 void
3450 SetUserThinkingEnables()
3451 {
3452   if (appData.noChessProgram) return;
3453   SetMenuEnables(userThinkingEnables);
3454 }
3455
3456 void
3457 SetMachineThinkingEnables()
3458 {
3459   if (appData.noChessProgram) return;
3460   SetMenuEnables(machineThinkingEnables);
3461   switch (gameMode) {
3462   case MachinePlaysBlack:
3463   case MachinePlaysWhite:
3464   case TwoMachinesPlay:
3465     XtSetSensitive(XtNameToWidget(menuBarWidget,
3466                                   ModeToWidgetName(gameMode)), True);
3467     break;
3468   default:
3469     break;
3470   }
3471 }
3472
3473 #define Abs(n) ((n)<0 ? -(n) : (n))
3474
3475 /*
3476  * Find a font that matches "pattern" that is as close as
3477  * possible to the targetPxlSize.  Prefer fonts that are k
3478  * pixels smaller to fonts that are k pixels larger.  The
3479  * pattern must be in the X Consortium standard format,
3480  * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3481  * The return value should be freed with XtFree when no
3482  * longer needed.
3483  */
3484 char *FindFont(pattern, targetPxlSize)
3485      char *pattern;
3486      int targetPxlSize;
3487 {
3488     char **fonts, *p, *best, *scalable, *scalableTail;
3489     int i, j, nfonts, minerr, err, pxlSize;
3490
3491 #ifdef ENABLE_NLS
3492     char **missing_list;
3493     int missing_count;
3494     char *def_string, *base_fnt_lst, strInt[3];
3495     XFontSet fntSet;
3496     XFontStruct **fnt_list;
3497
3498     base_fnt_lst = calloc(1, strlen(pattern) + 3);
3499     sprintf(strInt, "%d", targetPxlSize);
3500     p = strstr(pattern, "--");
3501     strncpy(base_fnt_lst, pattern, p - pattern + 2);
3502     strcat(base_fnt_lst, strInt);
3503     strcat(base_fnt_lst, strchr(p + 2, '-'));
3504
3505     if ((fntSet = XCreateFontSet(xDisplay,
3506                                  base_fnt_lst,
3507                                  &missing_list,
3508                                  &missing_count,
3509                                  &def_string)) == NULL) {
3510
3511        fprintf(stderr, _("Unable to create font set.\n"));
3512        exit (2);
3513     }
3514
3515     nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3516 #else
3517     fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3518     if (nfonts < 1) {
3519         fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3520                 programName, pattern);
3521         exit(2);
3522     }
3523 #endif
3524
3525     best = fonts[0];
3526     scalable = NULL;
3527     minerr = 999999;
3528     for (i=0; i<nfonts; i++) {
3529         j = 0;
3530         p = fonts[i];
3531         if (*p != '-') continue;
3532         while (j < 7) {
3533             if (*p == NULLCHAR) break;
3534             if (*p++ == '-') j++;
3535         }
3536         if (j < 7) continue;
3537         pxlSize = atoi(p);
3538         if (pxlSize == 0) {
3539             scalable = fonts[i];
3540             scalableTail = p;
3541         } else {
3542             err = pxlSize - targetPxlSize;
3543             if (Abs(err) < Abs(minerr) ||
3544                 (minerr > 0 && err < 0 && -err == minerr)) {
3545                 best = fonts[i];
3546                 minerr = err;
3547             }
3548         }
3549     }
3550     if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3551         /* If the error is too big and there is a scalable font,
3552            use the scalable font. */
3553         int headlen = scalableTail - scalable;
3554         p = (char *) XtMalloc(strlen(scalable) + 10);
3555         while (isdigit(*scalableTail)) scalableTail++;
3556         sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3557     } else {
3558         p = (char *) XtMalloc(strlen(best) + 1);
3559         strcpy(p, best);
3560     }
3561     if (appData.debugMode) {
3562         fprintf(debugFP, _("resolved %s at pixel size %d\n  to %s\n"),
3563                 pattern, targetPxlSize, p);
3564     }
3565 #ifdef ENABLE_NLS
3566     if (missing_count > 0)
3567        XFreeStringList(missing_list);
3568     XFreeFontSet(xDisplay, fntSet);
3569 #else
3570      XFreeFontNames(fonts);
3571 #endif
3572     return p;
3573 }
3574
3575 void CreateGCs()
3576 {
3577     XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3578       | GCBackground | GCFunction | GCPlaneMask;
3579     XGCValues gc_values;
3580     GC copyInvertedGC;
3581
3582     gc_values.plane_mask = AllPlanes;
3583     gc_values.line_width = lineGap;
3584     gc_values.line_style = LineSolid;
3585     gc_values.function = GXcopy;
3586
3587     gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3588     gc_values.background = XBlackPixel(xDisplay, xScreen);
3589     lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3590
3591     gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3592     gc_values.background = XWhitePixel(xDisplay, xScreen);
3593     coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3594     XSetFont(xDisplay, coordGC, coordFontID);
3595
3596     // [HGM] make font for holdings counts (white on black0
3597     gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3598     gc_values.background = XBlackPixel(xDisplay, xScreen);
3599     countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3600     XSetFont(xDisplay, countGC, countFontID);
3601
3602     if (appData.monoMode) {
3603         gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3604         gc_values.background = XWhitePixel(xDisplay, xScreen);
3605         highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3606
3607         gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3608         gc_values.background = XBlackPixel(xDisplay, xScreen);
3609         lightSquareGC = wbPieceGC
3610           = XtGetGC(shellWidget, value_mask, &gc_values);
3611
3612         gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3613         gc_values.background = XWhitePixel(xDisplay, xScreen);
3614         darkSquareGC = bwPieceGC
3615           = XtGetGC(shellWidget, value_mask, &gc_values);
3616
3617         if (DefaultDepth(xDisplay, xScreen) == 1) {
3618             /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3619             gc_values.function = GXcopyInverted;
3620             copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3621             gc_values.function = GXcopy;
3622             if (XBlackPixel(xDisplay, xScreen) == 1) {
3623                 bwPieceGC = darkSquareGC;
3624                 wbPieceGC = copyInvertedGC;
3625             } else {
3626                 bwPieceGC = copyInvertedGC;
3627                 wbPieceGC = lightSquareGC;
3628             }
3629         }
3630     } else {
3631         gc_values.foreground = highlightSquareColor;
3632         gc_values.background = highlightSquareColor;
3633         highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3634
3635         gc_values.foreground = premoveHighlightColor;
3636         gc_values.background = premoveHighlightColor;
3637         prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3638
3639         gc_values.foreground = lightSquareColor;
3640         gc_values.background = darkSquareColor;
3641         lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3642
3643         gc_values.foreground = darkSquareColor;
3644         gc_values.background = lightSquareColor;
3645         darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3646
3647         gc_values.foreground = jailSquareColor;
3648         gc_values.background = jailSquareColor;
3649         jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3650
3651         gc_values.foreground = whitePieceColor;
3652         gc_values.background = darkSquareColor;
3653         wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3654
3655         gc_values.foreground = whitePieceColor;
3656         gc_values.background = lightSquareColor;
3657         wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3658
3659         gc_values.foreground = whitePieceColor;
3660         gc_values.background = jailSquareColor;
3661         wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3662
3663         gc_values.foreground = blackPieceColor;
3664         gc_values.background = darkSquareColor;
3665         bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3666
3667         gc_values.foreground = blackPieceColor;
3668         gc_values.background = lightSquareColor;
3669         blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3670
3671         gc_values.foreground = blackPieceColor;
3672         gc_values.background = jailSquareColor;
3673         bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3674     }
3675 }
3676
3677 void CreatePieces()
3678 {
3679   /* order of pieces
3680   WhitePawn, WhiteKnight, WhiteBishop, WhiteRook, WhiteQueen, WhiteKing,
3681   BlackPawn, BlackKnight, BlackBishop, BlackRook, BlackQueen, BlackKing,
3682   */
3683
3684   SVGpieces[WhitePawn]   = load_pixbuf("svg/WhitePawn.svg");
3685   SVGpieces[WhiteKnight] = load_pixbuf("svg/WhiteKnight.svg");
3686   SVGpieces[WhiteBishop] = load_pixbuf("svg/WhiteBishop.svg");
3687   SVGpieces[WhiteRook]   = load_pixbuf("svg/WhiteRook.svg");
3688   SVGpieces[WhiteQueen]  = load_pixbuf("svg/WhiteQueen.svg");
3689   SVGpieces[WhiteKing]   = load_pixbuf("svg/WhiteKing.svg");
3690
3691   SVGpieces[BlackPawn]   = load_pixbuf("svg/BlackPawn.svg");
3692   SVGpieces[BlackKnight] = load_pixbuf("svg/BlackKnight.svg");
3693   SVGpieces[BlackBishop] = load_pixbuf("svg/BlackBishop.svg");
3694   SVGpieces[BlackRook]   = load_pixbuf("svg/BlackRook.svg");
3695   SVGpieces[BlackQueen]  = load_pixbuf("svg/BlackQueen.svg");
3696   SVGpieces[BlackKing]   = load_pixbuf("svg/BlackKing.svg");
3697
3698   return;
3699 }
3700
3701
3702 void CreateGrid()
3703 {
3704     int i, j;
3705
3706     if (lineGap == 0) return;
3707
3708     /* [HR] Split this into 2 loops for non-square boards. */
3709
3710     for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3711         gridSegments[i].x1 = 0;
3712         gridSegments[i].x2 =
3713           lineGap + BOARD_WIDTH * (squareSize + lineGap);
3714         gridSegments[i].y1 = gridSegments[i].y2
3715           = lineGap / 2 + (i * (squareSize + lineGap));
3716     }
3717
3718     for (j = 0; j < BOARD_WIDTH + 1; j++) {
3719         gridSegments[j + i].y1 = 0;
3720         gridSegments[j + i].y2 =
3721           lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3722         gridSegments[j + i].x1 = gridSegments[j + i].x2
3723           = lineGap / 2 + (j * (squareSize + lineGap));
3724     }
3725 }
3726
3727 static void MenuBarSelect(w, addr, index)
3728      Widget w;
3729      caddr_t addr;
3730      caddr_t index;
3731 {
3732     XtActionProc proc = (XtActionProc) addr;
3733
3734     (proc)(NULL, NULL, NULL, NULL);
3735 }
3736
3737 void CreateMenuBarPopup(parent, name, mb)
3738      Widget parent;
3739      String name;
3740      Menu *mb;
3741 {
3742     int j;
3743     Widget menu, entry;
3744     MenuItem *mi;
3745     Arg args[16];
3746
3747     menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3748                               parent, NULL, 0);
3749     j = 0;
3750     XtSetArg(args[j], XtNleftMargin, 20);   j++;
3751     XtSetArg(args[j], XtNrightMargin, 20);  j++;
3752     mi = mb->mi;
3753     while (mi->string != NULL) {
3754         if (strcmp(mi->string, "----") == 0) {
3755             entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3756                                           menu, args, j);
3757         } else {
3758           XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3759             entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3760                                           menu, args, j+1);
3761             XtAddCallback(entry, XtNcallback,
3762                           (XtCallbackProc) MenuBarSelect,
3763                           (caddr_t) mi->proc);
3764         }
3765         mi++;
3766     }
3767 }
3768
3769 Widget CreateMenuBar(mb)
3770      Menu *mb;
3771 {
3772     int j;
3773     Widget anchor, menuBar;
3774     Arg args[16];
3775     char menuName[MSG_SIZ];
3776
3777     j = 0;
3778     XtSetArg(args[j], XtNorientation, XtorientHorizontal);  j++;
3779     XtSetArg(args[j], XtNvSpace, 0);                        j++;
3780     XtSetArg(args[j], XtNborderWidth, 0);                   j++;
3781     menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3782                              formWidget, args, j);
3783
3784     while (mb->name != NULL) {
3785         strcpy(menuName, "menu");
3786         strcat(menuName, mb->name);
3787         j = 0;
3788         XtSetArg(args[j], XtNmenuName, XtNewString(menuName));  j++;
3789         if (tinyLayout) {
3790             char shortName[2];
3791             shortName[0] = _(mb->name)[0];
3792             shortName[1] = NULLCHAR;
3793             XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3794         }
3795       else {
3796           XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3797       }
3798
3799         XtSetArg(args[j], XtNborderWidth, 0);                   j++;
3800         anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3801                                        menuBar, args, j);
3802         CreateMenuBarPopup(menuBar, menuName, mb);
3803         mb++;
3804     }
3805     return menuBar;
3806 }
3807
3808 Widget CreateButtonBar(mi)
3809      MenuItem *mi;
3810 {
3811     int j;
3812     Widget button, buttonBar;
3813     Arg args[16];
3814
3815     j = 0;
3816     XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3817     if (tinyLayout) {
3818         XtSetArg(args[j], XtNhSpace, 0); j++;
3819     }
3820     XtSetArg(args[j], XtNborderWidth, 0); j++;
3821     XtSetArg(args[j], XtNvSpace, 0);                        j++;
3822     buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3823                                formWidget, args, j);
3824
3825     while (mi->string != NULL) {
3826         j = 0;
3827         if (tinyLayout) {
3828             XtSetArg(args[j], XtNinternalWidth, 2); j++;
3829             XtSetArg(args[j], XtNborderWidth, 0); j++;
3830         }
3831       XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3832         button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3833                                        buttonBar, args, j);
3834         XtAddCallback(button, XtNcallback,
3835                       (XtCallbackProc) MenuBarSelect,
3836                       (caddr_t) mi->proc);
3837         mi++;
3838     }
3839     return buttonBar;
3840 }
3841
3842 Widget
3843 CreatePieceMenu(name, color)
3844      char *name;
3845      int color;
3846 {
3847     int i;
3848     Widget entry, menu;
3849     Arg args[16];
3850     ChessSquare selection;
3851
3852     menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3853                               boardWidget, args, 0);
3854
3855     for (i = 0; i < PIECE_MENU_SIZE; i++) {
3856         String item = pieceMenuStrings[color][i];
3857
3858         if (strcmp(item, "----") == 0) {
3859             entry = XtCreateManagedWidget(item, smeLineObjectClass,
3860                                           menu, NULL, 0);
3861         } else {
3862           XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3863             entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3864                                 menu, args, 1);
3865             selection = pieceMenuTranslation[color][i];
3866             XtAddCallback(entry, XtNcallback,
3867                           (XtCallbackProc) PieceMenuSelect,
3868                           (caddr_t) selection);
3869             if (selection == WhitePawn || selection == BlackPawn) {
3870                 XtSetArg(args[0], XtNpopupOnEntry, entry);
3871                 XtSetValues(menu, args, 1);
3872             }
3873         }
3874     }
3875     return menu;
3876 }
3877
3878 void
3879 CreatePieceMenus()
3880 {
3881     int i;
3882     Widget entry;
3883     Arg args[16];
3884     ChessSquare selection;
3885
3886 //    whitePieceMenu = CreatePieceMenu("menuW", 0);
3887 //    blackPieceMenu = CreatePieceMenu("menuB", 1);
3888 //
3889 //    XtRegisterGrabAction(PieceMenuPopup, True,
3890 //                       (unsigned)(ButtonPressMask|ButtonReleaseMask),
3891 //                       GrabModeAsync, GrabModeAsync);
3892 //
3893 //    XtSetArg(args[0], XtNlabel, _("Drop"));
3894 //    dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3895 //                                boardWidget, args, 1);
3896 //    for (i = 0; i < DROP_MENU_SIZE; i++) {
3897 //      String item = dropMenuStrings[i];
3898 //
3899 //      if (strcmp(item, "----") == 0) {
3900 //          entry = XtCreateManagedWidget(item, smeLineObjectClass,
3901 //                                        dropMenu, NULL, 0);
3902 //      } else {
3903 //          XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3904 //          entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3905 //                                dropMenu, args, 1);
3906 //          selection = dropMenuTranslation[i];
3907 //          XtAddCallback(entry, XtNcallback,
3908 //                        (XtCallbackProc) DropMenuSelect,
3909 //                        (caddr_t) selection);
3910 //      }
3911 //    }
3912 }
3913
3914 void SetupDropMenu()
3915 {
3916     int i, j, count;
3917     char label[32];
3918     Arg args[16];
3919     Widget entry;
3920     char* p;
3921
3922     for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3923         entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3924         p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3925                    dmEnables[i].piece);
3926         XtSetSensitive(entry, p != NULL || !appData.testLegality
3927                        /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3928                                        && !appData.icsActive));
3929         count = 0;
3930         while (p && *p++ == dmEnables[i].piece) count++;
3931         snprintf(label, sizeof(label), "%s  %d", dmEnables[i].widget, count);
3932         j = 0;
3933         XtSetArg(args[j], XtNlabel, label); j++;
3934         XtSetValues(entry, args, j);
3935     }
3936 }
3937
3938 void PieceMenuPopup(w, event, params, num_params)
3939      Widget w;
3940      XEvent *event;
3941      String *params;
3942      Cardinal *num_params;
3943 {
3944     String whichMenu;
3945     if (event->type != ButtonPress) return;
3946     if (errorUp) ErrorPopDown();
3947     switch (gameMode) {
3948       case EditPosition:
3949       case IcsExamining:
3950         whichMenu = params[0];
3951         break;
3952       case IcsPlayingWhite:
3953       case IcsPlayingBlack:
3954       case EditGame:
3955       case MachinePlaysWhite:
3956       case MachinePlaysBlack:
3957         if (appData.testLegality &&
3958             gameInfo.variant != VariantBughouse &&
3959             gameInfo.variant != VariantCrazyhouse) return;
3960         SetupDropMenu();
3961         whichMenu = "menuD";
3962         break;
3963       default:
3964         return;
3965     }
3966
3967     if (((pmFromX = EventToSquare(event->xbutton.x, BOARD_WIDTH)) < 0) ||
3968         ((pmFromY = EventToSquare(event->xbutton.y, BOARD_HEIGHT)) < 0)) {
3969         pmFromX = pmFromY = -1;
3970         return;
3971     }
3972     if (flipView)
3973       pmFromX = BOARD_WIDTH - 1 - pmFromX;
3974     else
3975       pmFromY = BOARD_HEIGHT - 1 - pmFromY;
3976
3977     XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3978 }
3979
3980 static void PieceMenuSelect(w, piece, junk)
3981      Widget w;
3982      ChessSquare piece;
3983      caddr_t junk;
3984 {
3985     if (pmFromX < 0 || pmFromY < 0) return;
3986     EditPositionMenuEvent(piece, pmFromX, pmFromY);
3987 }
3988
3989 static void DropMenuSelect(w, piece, junk)
3990      Widget w;
3991      ChessSquare piece;
3992      caddr_t junk;
3993 {
3994     if (pmFromX < 0 || pmFromY < 0) return;
3995     DropMenuEvent(piece, pmFromX, pmFromY);
3996 }
3997
3998 void WhiteClock(w, event, prms, nprms)
3999      Widget w;
4000      XEvent *event;
4001      String *prms;
4002      Cardinal *nprms;
4003 {
4004     if (gameMode == EditPosition || gameMode == IcsExamining) {
4005         SetWhiteToPlayEvent();
4006     } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
4007         CallFlagEvent();
4008     }
4009 }
4010
4011 void BlackClock(w, event, prms, nprms)
4012      Widget w;
4013      XEvent *event;
4014      String *prms;
4015      Cardinal *nprms;
4016 {
4017     if (gameMode == EditPosition || gameMode == IcsExamining) {
4018         SetBlackToPlayEvent();
4019     } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
4020         CallFlagEvent();
4021     }
4022 }
4023
4024
4025 /*
4026  * If the user selects on a border boundary, return -1; if off the board,
4027  *   return -2.  Otherwise map the event coordinate to the square.
4028  */
4029 int EventToSquare(x, limit)
4030      int x;
4031 {
4032     if (x <= 0)
4033       return -2;
4034     if (x < lineGap)
4035       return -1;
4036     x -= lineGap;
4037     if ((x % (squareSize + lineGap)) >= squareSize)
4038       return -1;
4039     x /= (squareSize + lineGap);
4040     if (x >= limit)
4041       return -2;
4042     return x;
4043 }
4044
4045 static void do_flash_delay(msec)
4046      unsigned long msec;
4047 {
4048     TimeDelay(msec);
4049 }
4050
4051 static void drawHighlight(file, rank, gc)
4052      int file, rank;
4053      GC gc;
4054 {
4055     int x, y;
4056
4057     if (lineGap == 0 || appData.blindfold) return;
4058
4059     if (flipView) {
4060         x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
4061           (squareSize + lineGap);
4062         y = lineGap/2 + rank * (squareSize + lineGap);
4063     } else {
4064         x = lineGap/2 + file * (squareSize + lineGap);
4065         y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
4066           (squareSize + lineGap);
4067     }
4068
4069     XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
4070                    squareSize+lineGap, squareSize+lineGap);
4071 }
4072
4073 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
4074 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4075
4076 void
4077 SetHighlights(fromX, fromY, toX, toY)
4078      int fromX, fromY, toX, toY;
4079 {
4080     if (hi1X != fromX || hi1Y != fromY) {
4081         if (hi1X >= 0 && hi1Y >= 0) {
4082             drawHighlight(hi1X, hi1Y, lineGC);
4083         }
4084         if (fromX >= 0 && fromY >= 0) {
4085             drawHighlight(fromX, fromY, highlineGC);
4086         }
4087     }
4088     if (hi2X != toX || hi2Y != toY) {
4089         if (hi2X >= 0 && hi2Y >= 0) {
4090             drawHighlight(hi2X, hi2Y, lineGC);
4091         }
4092         if (toX >= 0 && toY >= 0) {
4093             drawHighlight(toX, toY, highlineGC);
4094         }
4095     }
4096     hi1X = fromX;
4097     hi1Y = fromY;
4098     hi2X = toX;
4099     hi2Y = toY;
4100 }
4101
4102 void
4103 ClearHighlights()
4104 {
4105     SetHighlights(-1, -1, -1, -1);
4106 }
4107
4108
4109 void
4110 SetPremoveHighlights(fromX, fromY, toX, toY)
4111      int fromX, fromY, toX, toY;
4112 {
4113     if (pm1X != fromX || pm1Y != fromY) {
4114         if (pm1X >= 0 && pm1Y >= 0) {
4115             drawHighlight(pm1X, pm1Y, lineGC);
4116         }
4117         if (fromX >= 0 && fromY >= 0) {
4118             drawHighlight(fromX, fromY, prelineGC);
4119         }
4120     }
4121     if (pm2X != toX || pm2Y != toY) {
4122         if (pm2X >= 0 && pm2Y >= 0) {
4123             drawHighlight(pm2X, pm2Y, lineGC);
4124         }
4125         if (toX >= 0 && toY >= 0) {
4126             drawHighlight(toX, toY, prelineGC);
4127         }
4128     }
4129     pm1X = fromX;
4130     pm1Y = fromY;
4131     pm2X = toX;
4132     pm2Y = toY;
4133 }
4134
4135 void
4136 ClearPremoveHighlights()
4137 {
4138   SetPremoveHighlights(-1, -1, -1, -1);
4139 }
4140
4141 static void BlankSquare(x, y, color, piece, dest)
4142      int x, y, color;
4143      ChessSquare piece;
4144      Drawable dest;
4145 {
4146     if (useImages && useImageSqs) {
4147       GdkPixbuf *pb;
4148       switch (color) {
4149       case 1: /* light */
4150         pb = SVGLightSquare;
4151         break;
4152       case 0: /* dark */
4153         pb = SVGDarkSquare;
4154         break;
4155       case 2: /* neutral */
4156       default:
4157         pb = SVGNeutralSquare;
4158         break;
4159       }
4160       gdk_draw_pixbuf(GDK_WINDOW(GUI_Board->window),NULL,pb,0,0,x,y,-1,-1, GDK_RGB_DITHER_NORMAL, 0, 0);
4161     } else {
4162       GdkGC *gc;
4163       GdkColor tmp;
4164       
4165       gc = gdk_gc_new(GDK_WINDOW(GUI_Board->window));
4166       
4167       switch (color) {
4168       case 1: /* light */
4169         //      gc = lightSquareGC;
4170         tmp.green=60000;
4171         tmp.red=63330;
4172         tmp.blue=60000;
4173         gdk_gc_set_rgb_fg_color(gc, &tmp);
4174         break;
4175       case 0: /* dark */
4176         //      gc = darkSquareGC;
4177         tmp.green=10000;
4178         tmp.red=13330;
4179         tmp.blue=1234;
4180         gdk_gc_set_rgb_fg_color(gc, &tmp);
4181         break;
4182       case 2: /* neutral */
4183       default:
4184         //      gc = jailSquareGC;
4185         tmp.green=30000;
4186         tmp.red=33330;
4187         tmp.blue=30234;
4188         gdk_gc_set_rgb_fg_color(gc, &tmp);
4189         break;
4190       }
4191       gdk_draw_rectangle(GDK_WINDOW(GUI_Board->window),gc,1,x,y,squareSize,squareSize);
4192       
4193     }
4194 }
4195
4196 /*
4197    I split out the routines to draw a piece so that I could
4198    make a generic flash routine.
4199 */
4200 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4201      ChessSquare piece;
4202      int square_color, x, y;
4203      Drawable dest;
4204 {
4205     /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4206     switch (square_color) {
4207       case 1: /* light */
4208       case 2: /* neutral */
4209       default:
4210         XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4211                   ? *pieceToOutline(piece)
4212                   : *pieceToSolid(piece),
4213                   dest, bwPieceGC, 0, 0,
4214                   squareSize, squareSize, x, y);
4215         break;
4216       case 0: /* dark */
4217         XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4218                   ? *pieceToSolid(piece)
4219                   : *pieceToOutline(piece),
4220                   dest, wbPieceGC, 0, 0,
4221                   squareSize, squareSize, x, y);
4222         break;
4223     }
4224 }
4225
4226 static void monoDrawPiece(piece, square_color, x, y, dest)
4227      ChessSquare piece;
4228      int square_color, x, y;
4229      Drawable dest;
4230 {
4231     switch (square_color) {
4232       case 1: /* light */
4233       case 2: /* neutral */
4234       default:
4235         XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4236                    ? *pieceToOutline(piece)
4237                    : *pieceToSolid(piece),
4238                    dest, bwPieceGC, 0, 0,
4239                    squareSize, squareSize, x, y, 1);
4240         break;
4241       case 0: /* dark */
4242         XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4243                    ? *pieceToSolid(piece)
4244                    : *pieceToOutline(piece),
4245                    dest, wbPieceGC, 0, 0,
4246                    squareSize, squareSize, x, y, 1);
4247         break;
4248     }
4249 }
4250
4251 static void colorDrawPiece(piece, square_color, x, y, dest)
4252      ChessSquare piece;
4253      int square_color, x, y;
4254      Drawable dest;
4255 {
4256     if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4257     switch (square_color) {
4258       case 1: /* light */
4259         XCopyPlane(xDisplay, *pieceToSolid(piece),
4260                    dest, (int) piece < (int) BlackPawn
4261                    ? wlPieceGC : blPieceGC, 0, 0,
4262                    squareSize, squareSize, x, y, 1);
4263         break;
4264       case 0: /* dark */
4265         XCopyPlane(xDisplay, *pieceToSolid(piece),
4266                    dest, (int) piece < (int) BlackPawn
4267                    ? wdPieceGC : bdPieceGC, 0, 0,
4268                    squareSize, squareSize, x, y, 1);
4269         break;
4270       case 2: /* neutral */
4271       default:
4272         XCopyPlane(xDisplay, *pieceToSolid(piece),
4273                    dest, (int) piece < (int) BlackPawn
4274                    ? wjPieceGC : bjPieceGC, 0, 0,
4275                    squareSize, squareSize, x, y, 1);
4276         break;
4277     }
4278 }
4279
4280 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4281      ChessSquare piece;
4282      int square_color, x, y;
4283      Drawable dest;
4284 {
4285     int kind;
4286
4287     switch (square_color) {
4288       case 1: /* light */
4289       case 2: /* neutral */
4290       default:
4291         if ((int)piece < (int) BlackPawn) {
4292             kind = 0;
4293         } else {
4294             kind = 2;
4295             piece -= BlackPawn;
4296         }
4297         break;
4298       case 0: /* dark */
4299         if ((int)piece < (int) BlackPawn) {
4300             kind = 1;
4301         } else {
4302             kind = 3;
4303             piece -= BlackPawn;
4304         }
4305         break;
4306     }
4307     XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4308               dest, wlPieceGC, 0, 0,
4309               squareSize, squareSize, x, y);
4310 }
4311
4312 typedef void (*DrawFunc)();
4313
4314 DrawFunc ChooseDrawFunc()
4315 {
4316     if (appData.monoMode) {
4317         if (DefaultDepth(xDisplay, xScreen) == 1) {
4318             return monoDrawPiece_1bit;
4319         } else {
4320             return monoDrawPiece;
4321         }
4322     } else {
4323         if (useImages)
4324           return colorDrawPieceImage;
4325         else
4326           return colorDrawPiece;
4327     }
4328 }
4329
4330 /* [HR] determine square color depending on chess variant. */
4331 static int SquareColor(row, column)
4332      int row, column;
4333 {
4334     int square_color;
4335
4336     if (gameInfo.variant == VariantXiangqi) {
4337         if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4338             square_color = 1;
4339         } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4340             square_color = 0;
4341         } else if (row <= 4) {
4342             square_color = 0;
4343         } else {
4344             square_color = 1;
4345         }
4346     } else {
4347         square_color = ((column + row) % 2) == 1;
4348     }
4349
4350     /* [hgm] holdings: next line makes all holdings squares light */
4351     if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4352
4353     return square_color;
4354 }
4355
4356 void DrawSquare(row, column, piece, do_flash)
4357      int row, column, do_flash;
4358      ChessSquare piece;
4359 {
4360     int square_color, x, y, direction, font_ascent, font_descent;
4361     int i;
4362     char string[2];
4363     XCharStruct overall;
4364     DrawFunc drawfunc;
4365     int flash_delay;
4366
4367     /* Calculate delay in milliseconds (2-delays per complete flash) */
4368     flash_delay = 500 / appData.flashRate;
4369
4370     if (flipView) {
4371         x = lineGap + ((BOARD_WIDTH-1)-column) *
4372           (squareSize + lineGap);
4373         y = lineGap + row * (squareSize + lineGap);
4374     } else {
4375         x = lineGap + column * (squareSize + lineGap);
4376         y = lineGap + ((BOARD_HEIGHT-1)-row) *
4377           (squareSize + lineGap);
4378     }
4379
4380     square_color = SquareColor(row, column);
4381
4382     if ( // [HGM] holdings: blank out area between board and holdings
4383                  column == BOARD_LEFT-1 ||  column == BOARD_RGHT
4384               || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4385                   || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4386                         BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4387
4388                         // [HGM] print piece counts next to holdings
4389                         string[1] = NULLCHAR;
4390                         if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4391                             string[0] = '0' + piece;
4392                             XTextExtents(countFontStruct, string, 1, &direction,
4393                                  &font_ascent, &font_descent, &overall);
4394                             if (appData.monoMode) {
4395                                 XDrawImageString(xDisplay, xBoardWindow, countGC,
4396                                                  x + squareSize - overall.width - 2,
4397                                                  y + font_ascent + 1, string, 1);
4398                             } else {
4399                                 XDrawString(xDisplay, xBoardWindow, countGC,
4400                                             x + squareSize - overall.width - 2,
4401                                             y + font_ascent + 1, string, 1);
4402                             }
4403                         }
4404                         if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4405                             string[0] = '0' + piece;
4406                             XTextExtents(countFontStruct, string, 1, &direction,
4407                                          &font_ascent, &font_descent, &overall);
4408                             if (appData.monoMode) {
4409                                 XDrawImageString(xDisplay, xBoardWindow, countGC,
4410                                                  x + 2, y + font_ascent + 1, string, 1);
4411                             } else {
4412                                 XDrawString(xDisplay, xBoardWindow, countGC,
4413                                             x + 2, y + font_ascent + 1, string, 1);
4414                             }
4415                         }
4416     } else {
4417             if (piece == EmptySquare || appData.blindfold) {
4418                         BlankSquare(x, y, square_color, piece, xBoardWindow);
4419             } else {
4420                         drawfunc = ChooseDrawFunc();
4421                         if (do_flash && appData.flashCount > 0) {
4422                             for (i=0; i<appData.flashCount; ++i) {
4423
4424                                         drawfunc(piece, square_color, x, y, xBoardWindow);
4425                                         XSync(xDisplay, False);
4426                                         do_flash_delay(flash_delay);
4427
4428                                         BlankSquare(x, y, square_color, piece, xBoardWindow);
4429                                         XSync(xDisplay, False);
4430                                         do_flash_delay(flash_delay);
4431                             }
4432                         }
4433                         drawfunc(piece, square_color, x, y, xBoardWindow);
4434         }
4435         }
4436
4437     string[1] = NULLCHAR;
4438     if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4439                 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4440         string[0] = 'a' + column - BOARD_LEFT;
4441         XTextExtents(coordFontStruct, string, 1, &direction,
4442                      &font_ascent, &font_descent, &overall);
4443         if (appData.monoMode) {
4444             XDrawImageString(xDisplay, xBoardWindow, coordGC,
4445                              x + squareSize - overall.width - 2,
4446                              y + squareSize - font_descent - 1, string, 1);
4447         } else {
4448             XDrawString(xDisplay, xBoardWindow, coordGC,
4449                         x + squareSize - overall.width - 2,
4450                         y + squareSize - font_descent - 1, string, 1);
4451         }
4452     }
4453     if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4454         string[0] = ONE + row;
4455         XTextExtents(coordFontStruct, string, 1, &direction,
4456                      &font_ascent, &font_descent, &overall);
4457         if (appData.monoMode) {
4458             XDrawImageString(xDisplay, xBoardWindow, coordGC,
4459                              x + 2, y + font_ascent + 1, string, 1);
4460         } else {
4461             XDrawString(xDisplay, xBoardWindow, coordGC,
4462                         x + 2, y + font_ascent + 1, string, 1);
4463         }
4464     }
4465 }
4466
4467
4468 /* Returns 1 if there are "too many" differences between b1 and b2
4469    (i.e. more than 1 move was made) */
4470 static int too_many_diffs(b1, b2)
4471      Board b1, b2;
4472 {
4473     int i, j;
4474     int c = 0;
4475
4476     for (i=0; i<BOARD_HEIGHT; ++i) {
4477         for (j=0; j<BOARD_WIDTH; ++j) {
4478             if (b1[i][j] != b2[i][j]) {
4479                 if (++c > 4)    /* Castling causes 4 diffs */
4480                   return 1;
4481             }
4482         }
4483     }
4484
4485     return 0;
4486 }
4487
4488 /* Matrix describing castling maneuvers */
4489 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4490 static int castling_matrix[4][5] = {
4491     { 0, 0, 4, 3, 2 },          /* 0-0-0, white */
4492     { 0, 7, 4, 5, 6 },          /* 0-0,   white */
4493     { 7, 0, 4, 3, 2 },          /* 0-0-0, black */
4494     { 7, 7, 4, 5, 6 }           /* 0-0,   black */
4495 };
4496
4497 /* Checks whether castling occurred. If it did, *rrow and *rcol
4498    are set to the destination (row,col) of the rook that moved.
4499
4500    Returns 1 if castling occurred, 0 if not.
4501
4502    Note: Only handles a max of 1 castling move, so be sure
4503    to call too_many_diffs() first.
4504    */
4505 static int check_castle_draw(newb, oldb, rrow, rcol)
4506      Board newb, oldb;
4507      int *rrow, *rcol;
4508 {
4509     int i, *r, j;
4510     int match;
4511
4512     /* For each type of castling... */
4513     for (i=0; i<4; ++i) {
4514         r = castling_matrix[i];
4515
4516         /* Check the 4 squares involved in the castling move */
4517         match = 0;
4518         for (j=1; j<=4; ++j) {
4519             if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4520                 match = 1;
4521                 break;
4522             }
4523         }
4524
4525         if (!match) {
4526             /* All 4 changed, so it must be a castling move */
4527             *rrow = r[0];
4528             *rcol = r[3];
4529             return 1;
4530         }
4531     }
4532     return 0;
4533 }
4534
4535 static int damage[BOARD_SIZE][BOARD_SIZE];
4536
4537 /*
4538  * event handler for redrawing the board
4539  */
4540 void DrawPosition( repaint, board)
4541      /*Boolean*/int repaint;
4542      Board board;
4543 {
4544     int i, j, do_flash;
4545     static int lastFlipView = 0;
4546     static int lastBoardValid = 0;
4547     static Board lastBoard;
4548     Arg args[16];
4549     int rrow, rcol;
4550
4551     printf ("DEBUG: in draw position\n");
4552
4553
4554     if (board == NULL) {
4555         if (!lastBoardValid) return;
4556         board = lastBoard;
4557     }
4558     if (!lastBoardValid || lastFlipView != flipView) {
4559         XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4560         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4561                     args, 1);
4562     }
4563
4564     /*
4565      * It would be simpler to clear the window with XClearWindow()
4566      * but this causes a very distracting flicker.
4567      */
4568
4569     printf ("DEBUG: in draw position 0.1\n");
4570
4571
4572     if (!repaint && lastBoardValid && lastFlipView == flipView) {
4573
4574     printf ("DEBUG: in draw position 0.1a\n");
4575         /* If too much changes (begin observing new game, etc.), don't
4576            do flashing */
4577         do_flash = too_many_diffs(board, lastBoard) ? 0 : 1;
4578
4579         /* Special check for castling so we don't flash both the king
4580            and the rook (just flash the king). */
4581         if (do_flash) {
4582             if (check_castle_draw(board, lastBoard, &rrow, &rcol)) {
4583                 /* Draw rook with NO flashing. King will be drawn flashing later */
4584                 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4585                 lastBoard[rrow][rcol] = board[rrow][rcol];
4586             }
4587         }
4588
4589         /* First pass -- Draw (newly) empty squares and repair damage.
4590            This prevents you from having a piece show up twice while it
4591            is flashing on its new square */
4592         for (i = 0; i < BOARD_HEIGHT; i++)
4593           for (j = 0; j < BOARD_WIDTH; j++)
4594             if ((board[i][j] != lastBoard[i][j] && board[i][j] == EmptySquare)
4595                 || damage[i][j]) {
4596                 DrawSquare(i, j, board[i][j], 0);
4597                 damage[i][j] = False;
4598             }
4599
4600         /* Second pass -- Draw piece(s) in new position and flash them */
4601         for (i = 0; i < BOARD_HEIGHT; i++)
4602           for (j = 0; j < BOARD_WIDTH; j++)
4603             if (board[i][j] != lastBoard[i][j]) {
4604                 DrawSquare(i, j, board[i][j], do_flash);
4605             }
4606     } else {
4607         if (lineGap > 0)
4608           {
4609             /* todo move GC to setupgc */
4610             GdkGC *gtklineGC=NULL;
4611             GdkColor tmp;
4612
4613             gtklineGC = gdk_gc_new(GDK_WINDOW(GUI_Board->window));
4614
4615             tmp.green=60000;
4616             tmp.red=0;
4617             tmp.blue=1234;
4618             gdk_gc_set_rgb_fg_color(gtklineGC, &tmp);
4619
4620             tmp.green=60000;
4621             tmp.red=60000;
4622             tmp.blue=61234;
4623             gdk_gc_set_rgb_bg_color(gtklineGC, &tmp);
4624
4625             gdk_draw_segments(GUI_Board->window,gtklineGC,
4626                               gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2 );
4627           }
4628
4629         for (i = 0; i < BOARD_HEIGHT; i++)
4630           for (j = 0; j < BOARD_WIDTH; j++) {
4631               DrawSquare(i, j, board[i][j], 0);
4632               damage[i][j] = False;
4633           }
4634     }
4635
4636     CopyBoard(lastBoard, board);
4637     lastBoardValid = 1;
4638     lastFlipView = flipView;
4639
4640     /* Draw highlights */
4641     if (pm1X >= 0 && pm1Y >= 0) {
4642       drawHighlight(pm1X, pm1Y, prelineGC);
4643     }
4644     if (pm2X >= 0 && pm2Y >= 0) {
4645       drawHighlight(pm2X, pm2Y, prelineGC);
4646     }
4647     if (hi1X >= 0 && hi1Y >= 0) {
4648       drawHighlight(hi1X, hi1Y, highlineGC);
4649     }
4650     if (hi2X >= 0 && hi2Y >= 0) {
4651       drawHighlight(hi2X, hi2Y, highlineGC);
4652     }
4653
4654     /* If piece being dragged around board, must redraw that too */
4655     DrawDragPiece();
4656
4657     //    XSync(xDisplay, False);
4658 }
4659
4660
4661 /*
4662  * event handler for redrawing the board
4663  */
4664 void DrawPositionProc(w, event, prms, nprms)
4665      Widget w;
4666      XEvent *event;
4667      String *prms;
4668      Cardinal *nprms;
4669 {
4670     DrawPosition(True, NULL);
4671 }
4672
4673
4674 /*
4675  * event handler for parsing user moves
4676  */
4677 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4678 //       way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4679 //       it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4680 //       should be made to use the new way, of calling UserMoveTest early  to determine the legality of the
4681 //       move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4682 //       and at the end FinishMove() to perform the move after optional promotion popups.
4683 //       For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4684 void HandleUserMove(w, event, prms, nprms)
4685      Widget w;
4686      XEvent *event;
4687      String *prms;
4688      Cardinal *nprms;
4689 {
4690     int x, y;
4691     Boolean saveAnimate;
4692     static int second = 0;
4693
4694     if (w != boardWidget || errorExitStatus != -1) return;
4695
4696     if (event->type == ButtonPress) ErrorPopDown();
4697
4698     if (promotionUp) {
4699         if (event->type == ButtonPress) {
4700             XtPopdown(promotionShell);
4701             XtDestroyWidget(promotionShell);
4702             promotionUp = False;
4703             ClearHighlights();
4704             fromX = fromY = -1;
4705         } else {
4706             return;
4707         }
4708     }
4709
4710     x = EventToSquare(event->xbutton.x, BOARD_WIDTH);
4711     y = EventToSquare(event->xbutton.y, BOARD_HEIGHT);
4712     if (!flipView && y >= 0) {
4713         y = BOARD_HEIGHT - 1 - y;
4714     }
4715     if (flipView && x >= 0) {
4716         x = BOARD_WIDTH - 1 - x;
4717     }
4718
4719     /* [HGM] holdings: next 5 lines: ignore all clicks between board and holdings */
4720     if(event->type == ButtonPress
4721             && ( x == BOARD_LEFT-1 || x == BOARD_RGHT
4722               || x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize
4723               || x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize) )
4724         return;
4725
4726     if (fromX == -1) {
4727         if (event->type == ButtonPress) {
4728             /* First square */
4729             if (OKToStartUserMove(x, y)) {
4730                 fromX = x;
4731                 fromY = y;
4732                 second = 0;
4733                 DragPieceBegin(event->xbutton.x, event->xbutton.y);
4734                 if (appData.highlightDragging) {
4735                     SetHighlights(x, y, -1, -1);
4736                 }
4737             }
4738         }
4739         return;
4740     }
4741
4742     /* fromX != -1 */
4743     if (event->type == ButtonPress && gameMode != EditPosition &&
4744         x >= 0 && y >= 0) {
4745         ChessSquare fromP;
4746         ChessSquare toP;
4747
4748         /* Check if clicking again on the same color piece */
4749         fromP = boards[currentMove][fromY][fromX];
4750         toP = boards[currentMove][y][x];
4751         if ((WhitePawn <= fromP && fromP < WhiteKing && // [HGM] this test should go, as UserMoveTest now does it.
4752              WhitePawn <= toP && toP <= WhiteKing) ||   //       For now I made it less critical by exempting King
4753             (BlackPawn <= fromP && fromP < BlackKing && //       moves, to not interfere with FRC castlings.
4754              BlackPawn <= toP && toP <= BlackKing)) {
4755             /* Clicked again on same color piece -- changed his mind */
4756             second = (x == fromX && y == fromY);
4757             if (appData.highlightDragging) {
4758                 SetHighlights(x, y, -1, -1);
4759             } else {
4760                 ClearHighlights();
4761             }
4762             if (OKToStartUserMove(x, y)) {
4763                 fromX = x;
4764                 fromY = y;
4765                 DragPieceBegin(event->xbutton.x, event->xbutton.y);
4766             }
4767             return;
4768         }
4769     }
4770
4771     if (event->type == ButtonRelease && x == fromX && y == fromY) {
4772         DragPieceEnd(event->xbutton.x, event->xbutton.y);
4773         if (appData.animateDragging) {
4774             /* Undo animation damage if any */
4775             DrawPosition(FALSE, NULL);
4776         }
4777         if (second) {
4778             /* Second up/down in same square; just abort move */
4779             second = 0;
4780             fromX = fromY = -1;
4781             ClearHighlights();
4782             gotPremove = 0;
4783             ClearPremoveHighlights();
4784         } else {
4785             /* First upclick in same square; start click-click mode */
4786             SetHighlights(x, y, -1, -1);
4787         }
4788         return;
4789     }
4790
4791     /* Completed move */
4792     toX = x;
4793     toY = y;
4794     saveAnimate = appData.animate;
4795     if (event->type == ButtonPress) {
4796         /* Finish clickclick move */
4797         if (appData.animate || appData.highlightLastMove) {
4798             SetHighlights(fromX, fromY, toX, toY);
4799         } else {
4800             ClearHighlights();
4801         }
4802     } else {
4803         /* Finish drag move */
4804         if (appData.highlightLastMove) {
4805             SetHighlights(fromX, fromY, toX, toY);
4806         } else {
4807             ClearHighlights();
4808         }
4809         DragPieceEnd(event->xbutton.x, event->xbutton.y);
4810         /* Don't animate move and drag both */
4811         appData.animate = FALSE;
4812     }
4813     if (IsPromotion(fromX, fromY, toX, toY)) {
4814         if (appData.alwaysPromoteToQueen) {
4815             UserMoveEvent(fromX, fromY, toX, toY, 'q');
4816             if (!appData.highlightLastMove || gotPremove) ClearHighlights();
4817             if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
4818             fromX = fromY = -1;
4819         } else {
4820             SetHighlights(fromX, fromY, toX, toY);
4821             PromotionPopUp();
4822         }
4823     } else {
4824         UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR);
4825         if (!appData.highlightLastMove || gotPremove) ClearHighlights();
4826         if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
4827         fromX = fromY = -1;
4828     }
4829     appData.animate = saveAnimate;
4830     if (appData.animate || appData.animateDragging) {
4831         /* Undo animation damage if needed */
4832         DrawPosition(FALSE, NULL);
4833     }
4834 }
4835
4836 void AnimateUserMove (Widget w, XEvent * event,
4837                       String * params, Cardinal * nParams)
4838 {
4839     DragPieceMove(event->xmotion.x, event->xmotion.y);
4840 }
4841
4842 Widget CommentCreate(name, text, mutable, callback, lines)
4843      char *name, *text;
4844      int /*Boolean*/ mutable;
4845      XtCallbackProc callback;
4846      int lines;
4847 {
4848     Arg args[16];
4849     Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4850     Dimension bw_width;
4851     int j;
4852
4853     j = 0;
4854     XtSetArg(args[j], XtNwidth, &bw_width);  j++;
4855     XtGetValues(boardWidget, args, j);
4856
4857     j = 0;
4858     XtSetArg(args[j], XtNresizable, True);  j++;
4859 #if TOPLEVEL
4860     shell =
4861       XtCreatePopupShell(name, topLevelShellWidgetClass,
4862                          shellWidget, args, j);
4863 #else
4864     shell =
4865       XtCreatePopupShell(name, transientShellWidgetClass,
4866                          shellWidget, args, j);
4867 #endif
4868     layout =
4869       XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4870                             layoutArgs, XtNumber(layoutArgs));
4871     form =
4872       XtCreateManagedWidget("form", formWidgetClass, layout,
4873                             formArgs, XtNumber(formArgs));
4874
4875     j = 0;
4876     if (mutable) {
4877         XtSetArg(args[j], XtNeditType, XawtextEdit);  j++;
4878         XtSetArg(args[j], XtNuseStringInPlace, False);  j++;
4879     }
4880     XtSetArg(args[j], XtNstring, text);  j++;
4881     XtSetArg(args[j], XtNtop, XtChainTop);  j++;
4882     XtSetArg(args[j], XtNbottom, XtChainBottom);  j++;
4883     XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
4884     XtSetArg(args[j], XtNright, XtChainRight);  j++;
4885     XtSetArg(args[j], XtNresizable, True);  j++;
4886     XtSetArg(args[j], XtNwidth, bw_width);  j++; /*force wider than buttons*/
4887 #if 0
4888     XtSetArg(args[j], XtNscrollVertical, XawtextScrollWhenNeeded);  j++;
4889 #else
4890     /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4891     XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways);  j++;
4892 #endif
4893     XtSetArg(args[j], XtNautoFill, True);  j++;
4894     XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4895     edit =
4896       XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4897
4898     if (mutable) {
4899         j = 0;
4900         XtSetArg(args[j], XtNfromVert, edit);  j++;
4901         XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4902         XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4903         XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4904         XtSetArg(args[j], XtNright, XtChainLeft); j++;
4905         b_ok =
4906           XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4907         XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4908
4909         j = 0;
4910         XtSetArg(args[j], XtNfromVert, edit);  j++;
4911         XtSetArg(args[j], XtNfromHoriz, b_ok);  j++;
4912         XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4913         XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4914         XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4915         XtSetArg(args[j], XtNright, XtChainLeft); j++;
4916         b_cancel =
4917           XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4918         XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4919
4920         j = 0;
4921         XtSetArg(args[j], XtNfromVert, edit);  j++;
4922         XtSetArg(args[j], XtNfromHoriz, b_cancel);  j++;
4923         XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4924         XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4925         XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4926         XtSetArg(args[j], XtNright, XtChainLeft); j++;
4927         b_clear =
4928           XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4929         XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4930     } else {
4931         j = 0;
4932         XtSetArg(args[j], XtNfromVert, edit);  j++;
4933         XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4934         XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4935         XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4936         XtSetArg(args[j], XtNright, XtChainLeft); j++;
4937         b_close =
4938           XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4939         XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4940
4941         j = 0;
4942         XtSetArg(args[j], XtNfromVert, edit);  j++;
4943         XtSetArg(args[j], XtNfromHoriz, b_close);  j++;
4944         XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4945         XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4946         XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4947         XtSetArg(args[j], XtNright, XtChainLeft); j++;
4948         b_edit =
4949           XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4950         XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4951     }
4952
4953     XtRealizeWidget(shell);
4954
4955     if (commentX == -1) {
4956         int xx, yy;
4957         Window junk;
4958         Dimension pw_height;
4959         Dimension ew_height;
4960
4961         j = 0;
4962         XtSetArg(args[j], XtNheight, &ew_height);  j++;
4963         XtGetValues(edit, args, j);
4964
4965         j = 0;
4966         XtSetArg(args[j], XtNheight, &pw_height);  j++;
4967         XtGetValues(shell, args, j);
4968         commentH = pw_height + (lines - 1) * ew_height;
4969         commentW = bw_width - 16;
4970
4971         XSync(xDisplay, False);
4972 #ifdef NOTDEF
4973         /* This code seems to tickle an X bug if it is executed too soon
4974            after xboard starts up.  The coordinates get transformed as if
4975            the main window was positioned at (0, 0).
4976            */
4977         XtTranslateCoords(shellWidget,
4978                           (bw_width - commentW) / 2, 0 - commentH / 2,
4979                           &commentX, &commentY);
4980 #else  /*!NOTDEF*/
4981         XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4982                               RootWindowOfScreen(XtScreen(shellWidget)),
4983                               (bw_width - commentW) / 2, 0 - commentH / 2,
4984                               &xx, &yy, &junk);
4985         commentX = xx;
4986         commentY = yy;
4987 #endif /*!NOTDEF*/
4988         if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4989     }
4990     j = 0;
4991     XtSetArg(args[j], XtNheight, commentH);  j++;
4992     XtSetArg(args[j], XtNwidth, commentW);  j++;
4993     XtSetArg(args[j], XtNx, commentX);  j++;
4994     XtSetArg(args[j], XtNy, commentY);  j++;
4995     XtSetValues(shell, args, j);
4996     XtSetKeyboardFocus(shell, edit);
4997
4998     return shell;
4999 }
5000
5001 /* Used for analysis window and ICS input window */
5002 Widget MiscCreate(name, text, mutable, callback, lines)
5003      char *name, *text;
5004      int /*Boolean*/ mutable;
5005      XtCallbackProc callback;
5006      int lines;
5007 {
5008     Arg args[16];
5009     Widget shell, layout, form, edit;
5010     Position x, y;
5011     Dimension bw_width, pw_height, ew_height, w, h;
5012     int j;
5013     int xx, yy;
5014     Window junk;
5015
5016     j = 0;
5017     XtSetArg(args[j], XtNresizable, True);  j++;
5018 #if TOPLEVEL
5019     shell =
5020       XtCreatePopupShell(name, topLevelShellWidgetClass,
5021                          shellWidget, args, j);
5022 #else
5023     shell =
5024       XtCreatePopupShell(name, transientShellWidgetClass,
5025                          shellWidget, args, j);
5026 #endif
5027     layout =
5028       XtCreateManagedWidget(layoutName, formWidgetClass, shell,
5029                             layoutArgs, XtNumber(layoutArgs));
5030     form =
5031       XtCreateManagedWidget("form", formWidgetClass, layout,
5032                             formArgs, XtNumber(formArgs));
5033
5034     j = 0;
5035     if (mutable) {
5036         XtSetArg(args[j], XtNeditType, XawtextEdit);  j++;
5037         XtSetArg(args[j], XtNuseStringInPlace, False);  j++;
5038     }
5039     XtSetArg(args[j], XtNstring, text);  j++;
5040     XtSetArg(args[j], XtNtop, XtChainTop);  j++;
5041     XtSetArg(args[j], XtNbottom, XtChainBottom);  j++;
5042     XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
5043     XtSetArg(args[j], XtNright, XtChainRight);  j++;
5044     XtSetArg(args[j], XtNresizable, True);  j++;
5045 #if 0
5046     XtSetArg(args[j], XtNscrollVertical, XawtextScrollWhenNeeded);  j++;
5047 #else
5048     /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
5049     XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways);  j++;
5050 #endif
5051     XtSetArg(args[j], XtNautoFill, True);  j++;
5052     XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
5053     edit =
5054       XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
5055
5056     XtRealizeWidget(shell);
5057
5058     j = 0;
5059     XtSetArg(args[j], XtNwidth, &bw_width);  j++;
5060     XtGetValues(boardWidget, args, j);
5061
5062     j = 0;
5063     XtSetArg(args[j], XtNheight, &ew_height);  j++;
5064     XtGetValues(edit, args, j);
5065
5066     j = 0;
5067     XtSetArg(args[j], XtNheight, &pw_height);  j++;
5068     XtGetValues(shell, args, j);
5069     h = pw_height + (lines - 1) * ew_height;
5070     w = bw_width - 16;
5071
5072     XSync(xDisplay, False);
5073 #ifdef NOTDEF
5074     /* This code seems to tickle an X bug if it is executed too soon
5075        after xboard starts up.  The coordinates get transformed as if
5076        the main window was positioned at (0, 0).
5077     */
5078     XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
5079 #else  /*!NOTDEF*/
5080     XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
5081                           RootWindowOfScreen(XtScreen(shellWidget)),
5082                           (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
5083 #endif /*!NOTDEF*/
5084     x = xx;
5085     y = yy;
5086     if (y < 0) y = 0; /*avoid positioning top offscreen*/
5087
5088     j = 0;
5089     XtSetArg(args[j], XtNheight, h);  j++;
5090     XtSetArg(args[j], XtNwidth, w);  j++;
5091     XtSetArg(args[j], XtNx, x);  j++;
5092     XtSetArg(args[j], XtNy, y);  j++;
5093     XtSetValues(shell, args, j);
5094
5095     return shell;
5096 }
5097
5098
5099 static int savedIndex;  /* gross that this is global */
5100
5101 void EditCommentPopUp(index, title, text)
5102      int index;
5103      char *title, *text;
5104 {
5105     Widget edit;
5106     Arg args[16];
5107     int j;
5108
5109     savedIndex = index;
5110     if (text == NULL) text = "";
5111
5112     if (editShell == NULL) {
5113         editShell =
5114           CommentCreate(title, text, True, EditCommentCallback, 4);
5115         XtRealizeWidget(editShell);
5116         CatchDeleteWindow(editShell, "EditCommentPopDown");
5117     } else {
5118         edit = XtNameToWidget(editShell, "*form.text");
5119         j = 0;
5120         XtSetArg(args[j], XtNstring, text); j++;
5121         XtSetValues(edit, args, j);
5122         j = 0;
5123         XtSetArg(args[j], XtNiconName, (XtArgVal) title);   j++;
5124         XtSetArg(args[j], XtNtitle, (XtArgVal) title);      j++;
5125         XtSetValues(editShell, args, j);
5126     }
5127
5128     XtPopup(editShell, XtGrabNone);
5129
5130     editUp = True;
5131     j = 0;
5132     XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5133     XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
5134                 args, j);
5135 }
5136
5137 void EditCommentCallback(w, client_data, call_data)
5138      Widget w;
5139      XtPointer client_data, call_data;
5140 {
5141     String name, val;
5142     Arg args[16];
5143     int j;
5144     Widget edit;
5145
5146     j = 0;
5147     XtSetArg(args[j], XtNlabel, &name);  j++;
5148     XtGetValues(w, args, j);
5149
5150     if (strcmp(name, _("ok")) == 0) {
5151         edit = XtNameToWidget(editShell, "*form.text");
5152         j = 0;
5153         XtSetArg(args[j], XtNstring, &val); j++;
5154         XtGetValues(edit, args, j);
5155         ReplaceComment(savedIndex, val);
5156         EditCommentPopDown();
5157     } else if (strcmp(name, _("cancel")) == 0) {
5158         EditCommentPopDown();
5159     } else if (strcmp(name, _("clear")) == 0) {
5160         edit = XtNameToWidget(editShell, "*form.text");
5161         XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5162         XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5163     }
5164 }
5165
5166 void EditCommentPopDown()
5167 {
5168     Arg args[16];
5169     int j;
5170
5171     if (!editUp) return;
5172     j = 0;
5173     XtSetArg(args[j], XtNx, &commentX); j++;
5174     XtSetArg(args[j], XtNy, &commentY); j++;
5175     XtSetArg(args[j], XtNheight, &commentH); j++;
5176     XtSetArg(args[j], XtNwidth, &commentW); j++;
5177     XtGetValues(editShell, args, j);
5178     XtPopdown(editShell);
5179     editUp = False;
5180     j = 0;
5181     XtSetArg(args[j], XtNleftBitmap, None); j++;
5182     XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
5183                 args, j);
5184 }
5185
5186 void ICSInputBoxPopUp()
5187 {
5188     Widget edit;
5189     Arg args[16];
5190     int j;
5191     char *title = _("ICS Input");
5192     XtTranslations tr;
5193
5194     if (ICSInputShell == NULL) {
5195         ICSInputShell = MiscCreate(title, "", True, NULL, 1);
5196         tr = XtParseTranslationTable(ICSInputTranslations);
5197         edit = XtNameToWidget(ICSInputShell, "*form.text");
5198         XtOverrideTranslations(edit, tr);
5199         XtRealizeWidget(ICSInputShell);
5200         CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
5201
5202     } else {
5203         edit = XtNameToWidget(ICSInputShell, "*form.text");
5204         j = 0;
5205         XtSetArg(args[j], XtNstring, ""); j++;
5206         XtSetValues(edit, args, j);
5207         j = 0;
5208         XtSetArg(args[j], XtNiconName, (XtArgVal) title);   j++;
5209         XtSetArg(args[j], XtNtitle, (XtArgVal) title);      j++;
5210         XtSetValues(ICSInputShell, args, j);
5211     }
5212
5213     XtPopup(ICSInputShell, XtGrabNone);
5214     XtSetKeyboardFocus(ICSInputShell, edit);
5215
5216     ICSInputBoxUp = True;
5217     j = 0;
5218     XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5219     XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
5220                 args, j);
5221 }
5222
5223 void ICSInputSendText()
5224 {
5225     Widget edit;
5226     int j;
5227     Arg args[16];
5228     String val;
5229
5230     edit = XtNameToWidget(ICSInputShell, "*form.text");
5231     j = 0;
5232     XtSetArg(args[j], XtNstring, &val); j++;
5233     XtGetValues(edit, args, j);
5234     SendMultiLineToICS(val);
5235     XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5236     XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5237 }
5238
5239 void ICSInputBoxPopDown()
5240 {
5241     Arg args[16];
5242     int j;
5243
5244     if (!ICSInputBoxUp) return;
5245     j = 0;
5246     XtPopdown(ICSInputShell);
5247     ICSInputBoxUp = False;
5248     j = 0;
5249     XtSetArg(args[j], XtNleftBitmap, None); j++;
5250     XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
5251                 args, j);
5252 }
5253
5254 void CommentPopUp(title, text)
5255      char *title, *text;
5256 {
5257     Arg args[16];
5258     int j;
5259     Widget edit;
5260
5261     if (commentShell == NULL) {
5262         commentShell =
5263           CommentCreate(title, text, False, CommentCallback, 4);
5264         XtRealizeWidget(commentShell);
5265         CatchDeleteWindow(commentShell, "CommentPopDown");
5266     } else {
5267         edit = XtNameToWidget(commentShell, "*form.text");
5268         j = 0;
5269         XtSetArg(args[j], XtNstring, text); j++;
5270         XtSetValues(edit, args, j);
5271         j = 0;
5272         XtSetArg(args[j], XtNiconName, (XtArgVal) title);   j++;
5273         XtSetArg(args[j], XtNtitle, (XtArgVal) title);      j++;
5274         XtSetValues(commentShell, args, j);
5275     }
5276
5277     XtPopup(commentShell, XtGrabNone);
5278     XSync(xDisplay, False);
5279
5280     commentUp = True;
5281 }
5282
5283 void AnalysisPopUp(title, text)
5284      char *title, *text;
5285 {
5286     Arg args[16];
5287     int j;
5288     Widget edit;
5289
5290     if (analysisShell == NULL) {
5291         analysisShell = MiscCreate(title, text, False, NULL, 4);
5292         XtRealizeWidget(analysisShell);
5293         CatchDeleteWindow(analysisShell, "AnalysisPopDown");
5294
5295     } else {
5296         edit = XtNameToWidget(analysisShell, "*form.text");
5297         j = 0;
5298         XtSetArg(args[j], XtNstring, text); j++;
5299         XtSetValues(edit, args, j);
5300         j = 0;
5301         XtSetArg(args[j], XtNiconName, (XtArgVal) title);   j++;
5302         XtSetArg(args[j], XtNtitle, (XtArgVal) title);      j++;
5303         XtSetValues(analysisShell, args, j);
5304     }
5305
5306     if (!analysisUp) {
5307         XtPopup(analysisShell, XtGrabNone);
5308     }
5309     XSync(xDisplay, False);
5310
5311     analysisUp = True;
5312 }
5313
5314 void CommentCallback(w, client_data, call_data)
5315      Widget w;
5316      XtPointer client_data, call_data;
5317 {
5318     String name;
5319     Arg args[16];
5320     int j;
5321
5322     j = 0;
5323     XtSetArg(args[j], XtNlabel, &name);  j++;
5324     XtGetValues(w, args, j);
5325
5326     if (strcmp(name, _("close")) == 0) {
5327         CommentPopDown();
5328     } else if (strcmp(name, _("edit")) == 0) {
5329         CommentPopDown();
5330         EditCommentEvent();
5331     }
5332 }
5333
5334
5335 void CommentPopDown()
5336 {
5337     Arg args[16];
5338     int j;
5339
5340     if (!commentUp) return;
5341     j = 0;
5342     XtSetArg(args[j], XtNx, &commentX); j++;
5343     XtSetArg(args[j], XtNy, &commentY); j++;
5344     XtSetArg(args[j], XtNwidth, &commentW); j++;
5345     XtSetArg(args[j], XtNheight, &commentH); j++;
5346     XtGetValues(commentShell, args, j);
5347     XtPopdown(commentShell);
5348     XSync(xDisplay, False);
5349     commentUp = False;
5350 }
5351
5352 void AnalysisPopDown()
5353 {
5354     if (!analysisUp) return;
5355     XtPopdown(analysisShell);
5356     XSync(xDisplay, False);
5357     analysisUp = False;
5358     if (appData.icsEngineAnalyze) ExitAnalyzeMode();    /* [DM] icsEngineAnalyze */
5359 }
5360
5361
5362 void FileNamePopUp(label, def, proc, openMode)
5363      char *label;
5364      char *def;
5365      FileProc proc;
5366      char *openMode;
5367 {
5368     Arg args[16];
5369     Widget popup, layout, dialog, edit;
5370     Window root, child;
5371     int x, y, i;
5372     int win_x, win_y;
5373     unsigned int mask;
5374
5375     fileProc = proc;            /* I can't see a way not */
5376     fileOpenMode = openMode;    /*   to use globals here */
5377
5378     i = 0;
5379     XtSetArg(args[i], XtNresizable, True); i++;
5380     XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
5381     XtSetArg(args[i], XtNtitle, XtNewString(_("File name prompt"))); i++;
5382     fileNameShell = popup =
5383       XtCreatePopupShell("File name prompt", transientShellWidgetClass,
5384                          shellWidget, args, i);
5385
5386     layout =
5387       XtCreateManagedWidget(layoutName, formWidgetClass, popup,
5388                             layoutArgs, XtNumber(layoutArgs));
5389
5390     i = 0;
5391     XtSetArg(args[i], XtNlabel, label); i++;
5392     XtSetArg(args[i], XtNvalue, def); i++;
5393     XtSetArg(args[i], XtNborderWidth, 0); i++;
5394     dialog = XtCreateManagedWidget("fileName", dialogWidgetClass,
5395                                    layout, args, i);
5396
5397     XawDialogAddButton(dialog, _("ok"), FileNameCallback, (XtPointer) dialog);
5398     XawDialogAddButton(dialog, _("cancel"), FileNameCallback,
5399                        (XtPointer) dialog);
5400
5401     XtRealizeWidget(popup);
5402     CatchDeleteWindow(popup, "FileNamePopDown");
5403
5404     XQueryPointer(xDisplay, xBoardWindow, &root, &child,
5405                   &x, &y, &win_x, &win_y, &mask);
5406
5407     XtSetArg(args[0], XtNx, x - 10);
5408     XtSetArg(args[1], XtNy, y - 30);
5409     XtSetValues(popup, args, 2);
5410
5411     XtPopup(popup, XtGrabExclusive);
5412     filenameUp = True;
5413
5414     edit = XtNameToWidget(dialog, "*value");
5415     XtSetKeyboardFocus(popup, edit);
5416 }
5417
5418 void FileNamePopDown()
5419 {
5420     if (!filenameUp) return;
5421     XtPopdown(fileNameShell);
5422     XtDestroyWidget(fileNameShell);
5423     filenameUp = False;
5424     ModeHighlight();
5425 }
5426
5427 void FileNameCallback(w, client_data, call_data)
5428      Widget w;
5429      XtPointer client_data, call_data;
5430 {
5431     String name;
5432     Arg args[16];
5433
5434     XtSetArg(args[0], XtNlabel, &name);
5435     XtGetValues(w, args, 1);
5436
5437     if (strcmp(name, _("cancel")) == 0) {
5438         FileNamePopDown();
5439         return;
5440     }
5441
5442     FileNameAction(w, NULL, NULL, NULL);
5443 }
5444
5445 void FileNameAction(w, event, prms, nprms)
5446      Widget w;
5447      XEvent *event;
5448      String *prms;
5449      Cardinal *nprms;
5450 {
5451     char buf[MSG_SIZ];
5452     String name;
5453     FILE *f;
5454     char *p, *fullname;
5455     int index;
5456
5457     name = XawDialogGetValueString(w = XtParent(w));
5458
5459     if ((name != NULL) && (*name != NULLCHAR)) {
5460         strcpy(buf, name);
5461         XtPopdown(w = XtParent(XtParent(w)));
5462         XtDestroyWidget(w);
5463         filenameUp = False;
5464
5465         p = strrchr(buf, ' ');
5466         if (p == NULL) {
5467             index = 0;
5468         } else {
5469             *p++ = NULLCHAR;
5470             index = atoi(p);
5471         }
5472         fullname = ExpandPathName(buf);
5473         if (!fullname) {
5474             ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5475         }
5476         else {
5477             f = fopen(fullname, fileOpenMode);
5478             if (f == NULL) {
5479                 DisplayError(_("Failed to open file"), errno);
5480             } else {
5481                 (void) (*fileProc)(f, index, buf);
5482             }
5483         }
5484         ModeHighlight();
5485         return;
5486     }
5487
5488     XtPopdown(w = XtParent(XtParent(w)));
5489     XtDestroyWidget(w);
5490     filenameUp = False;
5491     ModeHighlight();
5492 }
5493
5494 void PromotionPopUp()
5495 {
5496     Arg args[16];
5497     Widget dialog, layout;
5498     Position x, y;
5499     Dimension bw_width, pw_width;
5500     int j;
5501
5502     j = 0;
5503     XtSetArg(args[j], XtNwidth, &bw_width); j++;
5504     XtGetValues(boardWidget, args, j);
5505
5506     j = 0;
5507     XtSetArg(args[j], XtNresizable, True); j++;
5508     XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5509     promotionShell =
5510       XtCreatePopupShell("Promotion", transientShellWidgetClass,
5511                          shellWidget, args, j);
5512     layout =
5513       XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5514                             layoutArgs, XtNumber(layoutArgs));
5515
5516     j = 0;
5517     XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5518     XtSetArg(args[j], XtNborderWidth, 0); j++;
5519     dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5520                                    layout, args, j);
5521
5522   if(gameInfo.variant != VariantShogi) {
5523     XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5524                        (XtPointer) dialog);
5525     XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5526                        (XtPointer) dialog);
5527     XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5528                        (XtPointer) dialog);
5529     XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5530                        (XtPointer) dialog);
5531     if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5532         gameInfo.variant == VariantGiveaway) {
5533       XawDialogAddButton(dialog, _("King"), PromotionCallback,
5534                          (XtPointer) dialog);
5535     }
5536     if(gameInfo.variant == VariantCapablanca || 
5537        gameInfo.variant == VariantGothic || 
5538        gameInfo.variant == VariantCapaRandom) {
5539       XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5540                          (XtPointer) dialog);
5541       XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5542                          (XtPointer) dialog);
5543     }
5544   } else // [HGM] shogi
5545   {
5546       XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5547                          (XtPointer) dialog);
5548       XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5549                          (XtPointer) dialog);
5550   }
5551     XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5552                        (XtPointer) dialog);
5553
5554     XtRealizeWidget(promotionShell);
5555     CatchDeleteWindow(promotionShell, "PromotionPopDown");
5556
5557     j = 0;
5558     XtSetArg(args[j], XtNwidth, &pw_width); j++;
5559     XtGetValues(promotionShell, args, j);
5560
5561     XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5562                       lineGap + squareSize/3 +
5563                       ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5564                        0 : 6*(squareSize + lineGap)), &x, &y);
5565
5566     j = 0;
5567     XtSetArg(args[j], XtNx, x); j++;
5568     XtSetArg(args[j], XtNy, y); j++;
5569     XtSetValues(promotionShell, args, j);
5570
5571     XtPopup(promotionShell, XtGrabNone);
5572
5573     promotionUp = True;
5574 }
5575
5576 void PromotionPopDown()
5577 {
5578     if (!promotionUp) return;
5579     XtPopdown(promotionShell);
5580     XtDestroyWidget(promotionShell);
5581     promotionUp = False;
5582 }
5583
5584 void PromotionCallback(w, client_data, call_data)
5585      Widget w;
5586      XtPointer client_data, call_data;
5587 {
5588     String name;
5589     Arg args[16];
5590     int promoChar;
5591
5592     XtSetArg(args[0], XtNlabel, &name);
5593     XtGetValues(w, args, 1);
5594
5595     PromotionPopDown();
5596
5597     if (fromX == -1) return;
5598
5599     if (strcmp(name, _("cancel")) == 0) {
5600         fromX = fromY = -1;
5601         ClearHighlights();
5602         return;
5603     } else if (strcmp(name, _("Knight")) == 0) {
5604         promoChar = 'n';
5605     } else if (strcmp(name, _("Promote")) == 0) {
5606         promoChar = '+';
5607     } else if (strcmp(name, _("Defer")) == 0) {
5608         promoChar = '=';
5609     } else {
5610         promoChar = ToLower(name[0]);
5611     }
5612
5613     UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5614
5615     if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5616     if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5617     fromX = fromY = -1;
5618 }
5619
5620
5621 void ErrorCallback(w, client_data, call_data)
5622      Widget w;
5623      XtPointer client_data, call_data;
5624 {
5625     errorUp = False;
5626     XtPopdown(w = XtParent(XtParent(XtParent(w))));
5627     XtDestroyWidget(w);
5628     if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5629 }
5630
5631
5632 void ErrorPopDown()
5633 {
5634     if (!errorUp) return;
5635     errorUp = False;
5636     XtPopdown(errorShell);
5637     XtDestroyWidget(errorShell);
5638     if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5639 }
5640
5641 void ErrorPopUp(title, label, modal)
5642      char *title, *label;
5643      int modal;
5644 {
5645   GtkWidget *dialog;
5646  
5647   printf ("DEBUG: error %s %s\n\n",title,label);
5648   
5649   dialog = gtk_message_dialog_new(GTK_WINDOW(GUI_Window),
5650                                   GTK_DIALOG_DESTROY_WITH_PARENT,
5651                                   GTK_MESSAGE_ERROR,
5652                                   GTK_BUTTONS_CLOSE,
5653                                   (gchar *)label);
5654   
5655   gtk_window_set_title(GTK_WINDOW(dialog),(gchar *) title);
5656   if(modal)
5657     {
5658       gtk_dialog_run(GTK_DIALOG(dialog));
5659       gtk_widget_destroy(GTK_WIDGET(dialog));
5660     }
5661   else
5662     {
5663       g_signal_connect_swapped (dialog, "response",
5664                                 G_CALLBACK (ErrorPopDownProc),
5665                                 dialog);
5666       errorUp = True;
5667       gtk_widget_show(GTK_WIDGET(dialog));
5668     }
5669 }
5670
5671 /* Disable all user input other than deleting the window */
5672 static int frozen = 0;
5673 void FreezeUI()
5674 {
5675   if (frozen) return;
5676   /* Grab by a widget that doesn't accept input */
5677   //  XtAddGrab(messageWidget, TRUE, FALSE);
5678   frozen = 1;
5679 }
5680
5681 /* Undo a FreezeUI */
5682 void ThawUI()
5683 {
5684   if (!frozen) return;
5685   XtRemoveGrab(messageWidget);
5686   frozen = 0;
5687 }
5688
5689 char *ModeToWidgetName(mode)
5690      GameMode mode;
5691 {
5692     switch (mode) {
5693       case BeginningOfGame:
5694         if (appData.icsActive)
5695           return "menuMode.ICS Client";
5696         else if (appData.noChessProgram ||
5697                  *appData.cmailGameName != NULLCHAR)
5698           return "menuMode.Edit Game";
5699         else
5700           return "menuMode.Machine Black";
5701       case MachinePlaysBlack:
5702         return "menuMode.Machine Black";
5703       case MachinePlaysWhite:
5704         return "menuMode.Machine White";
5705       case AnalyzeMode:
5706         return "menuMode.Analysis Mode";
5707       case AnalyzeFile:
5708         return "menuMode.Analyze File";
5709       case TwoMachinesPlay:
5710         return "menuMode.Two Machines";
5711       case EditGame:
5712         return "menuMode.Edit Game";
5713       case PlayFromGameFile:
5714         return "menuFile.Load Game";
5715       case EditPosition:
5716         return "menuMode.Edit Position";
5717       case Training:
5718         return "menuMode.Training";
5719       case IcsPlayingWhite:
5720       case IcsPlayingBlack:
5721       case IcsObserving:
5722       case IcsIdle:
5723       case IcsExamining:
5724         return "menuMode.ICS Client";
5725       default:
5726       case EndOfGame:
5727         return NULL;
5728     }
5729 }
5730
5731 void ModeHighlight()
5732 {
5733     Arg args[16];
5734     static int oldPausing = FALSE;
5735     static GameMode oldmode = (GameMode) -1;
5736     char *wname;
5737
5738     if (!boardWidget || !XtIsRealized(boardWidget)) return;
5739
5740     if (pausing != oldPausing) {
5741         oldPausing = pausing;
5742         if (pausing) {
5743             XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5744         } else {
5745             XtSetArg(args[0], XtNleftBitmap, None);
5746         }
5747         XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5748                     args, 1);
5749
5750         if (appData.showButtonBar) {
5751 #if 0
5752           if (pausing) {
5753             XtSetArg(args[0], XtNbackground, buttonForegroundPixel);
5754             XtSetArg(args[1], XtNforeground, buttonBackgroundPixel);
5755           } else {
5756             XtSetArg(args[0], XtNbackground, buttonBackgroundPixel);
5757             XtSetArg(args[1], XtNforeground, buttonForegroundPixel);
5758           }
5759 #else
5760           /* Always toggle, don't set.  Previous code messes up when
5761              invoked while the button is pressed, as releasing it
5762              toggles the state again. */
5763           {
5764             Pixel oldbg, oldfg;
5765             XtSetArg(args[0], XtNbackground, &oldbg);
5766             XtSetArg(args[1], XtNforeground, &oldfg);
5767             XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5768                         args, 2);
5769             XtSetArg(args[0], XtNbackground, oldfg);
5770             XtSetArg(args[1], XtNforeground, oldbg);
5771           }
5772 #endif
5773           XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5774         }
5775     }
5776
5777     wname = ModeToWidgetName(oldmode);
5778     if (wname != NULL) {
5779         XtSetArg(args[0], XtNleftBitmap, None);
5780         XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5781     }
5782     wname = ModeToWidgetName(gameMode);
5783     if (wname != NULL) {
5784         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5785         XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5786     }
5787     oldmode = gameMode;
5788
5789     /* Maybe all the enables should be handled here, not just this one */
5790     XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5791                    gameMode == Training || gameMode == PlayFromGameFile);
5792 }
5793
5794
5795 /*
5796  * Button/menu procedures
5797  */
5798
5799 int LoadGamePopUp(f, gameNumber, title)
5800      FILE *f;
5801      int gameNumber;
5802      char *title;
5803 {
5804     cmailMsgLoaded = FALSE;
5805     if (gameNumber == 0) {
5806         int error = GameListBuild(f);
5807         if (error) {
5808             DisplayError(_("Cannot build game list"), error);
5809         } else if (!ListEmpty(&gameList) &&
5810                    ((ListGame *) gameList.tailPred)->number > 1) {
5811             GameListPopUp(f, title);
5812             return TRUE;
5813         }
5814         GameListDestroy();
5815         gameNumber = 1;
5816     }
5817     return LoadGame(f, gameNumber, title, FALSE);
5818 }
5819
5820
5821 void LoadNextPositionProc(w, event, prms, nprms)
5822      Widget w;
5823      XEvent *event;
5824      String *prms;
5825      Cardinal *nprms;
5826 {
5827     ReloadPosition(1);
5828 }
5829
5830 void LoadPrevPositionProc(w, event, prms, nprms)
5831      Widget w;
5832      XEvent *event;
5833      String *prms;
5834      Cardinal *nprms;
5835 {
5836     ReloadPosition(-1);
5837 }
5838
5839 void ReloadPositionProc(w, event, prms, nprms)
5840      Widget w;
5841      XEvent *event;
5842      String *prms;
5843      Cardinal *nprms;
5844 {
5845     ReloadPosition(0);
5846 }
5847
5848 void LoadPositionProc(w, event, prms, nprms)
5849      Widget w;
5850      XEvent *event;
5851      String *prms;
5852      Cardinal *nprms;
5853 {
5854     if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5855         Reset(FALSE, TRUE);
5856     }
5857     FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5858 }
5859
5860 void SaveGameProc(w, event, prms, nprms)
5861      Widget w;
5862      XEvent *event;
5863      String *prms;
5864      Cardinal *nprms;
5865 {
5866     FileNamePopUp(_("Save game file name?"),
5867                   DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5868                   SaveGame, "a");
5869 }
5870
5871 void SavePositionProc(w, event, prms, nprms)
5872      Widget w;
5873      XEvent *event;
5874      String *prms;
5875      Cardinal *nprms;
5876 {
5877     FileNamePopUp(_("Save position file name?"),
5878                   DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5879                   SavePosition, "a");
5880 }
5881
5882 void ReloadCmailMsgProc(w, event, prms, nprms)
5883      Widget w;
5884      XEvent *event;
5885      String *prms;
5886      Cardinal *nprms;
5887 {
5888     ReloadCmailMsgEvent(FALSE);
5889 }
5890
5891 void MailMoveProc(w, event, prms, nprms)
5892      Widget w;
5893      XEvent *event;
5894      String *prms;
5895      Cardinal *nprms;
5896 {
5897     MailMoveEvent();
5898 }
5899
5900 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5901 static char *selected_fen_position=NULL;
5902
5903 static Boolean
5904 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5905                  Atom *type_return, XtPointer *value_return,
5906                  unsigned long *length_return, int *format_return)
5907 {
5908   char *selection_tmp;
5909
5910   if (!selected_fen_position) return False; /* should never happen */
5911   if (*target == XA_STRING){
5912     /* note: since no XtSelectionDoneProc was registered, Xt will
5913      * automatically call XtFree on the value returned.  So have to
5914      * make a copy of it allocated with XtMalloc */
5915     selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5916     strcpy(selection_tmp, selected_fen_position);
5917
5918     *value_return=selection_tmp;
5919     *length_return=strlen(selection_tmp);
5920     *type_return=XA_STRING;
5921     *format_return = 8; /* bits per byte */
5922     return True;
5923   } else {
5924     return False;
5925   }
5926 }
5927
5928 /* note: when called from menu all parameters are NULL, so no clue what the
5929  * Widget which was clicked on was, or what the click event was
5930  */
5931 void CopyPositionProc(w, event, prms, nprms)
5932   Widget w;
5933   XEvent *event;
5934   String *prms;
5935   Cardinal *nprms;
5936   {
5937     int ret;
5938
5939     if (selected_fen_position) free(selected_fen_position);
5940     selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5941     if (!selected_fen_position) return;
5942     ret = XtOwnSelection(menuBarWidget, XA_PRIMARY,
5943                          CurrentTime,
5944                          SendPositionSelection,
5945                          NULL/* lose_ownership_proc */ ,
5946                          NULL/* transfer_done_proc */);
5947     if (!ret) {
5948       free(selected_fen_position);
5949       selected_fen_position=NULL;
5950     }
5951   }
5952
5953 /* function called when the data to Paste is ready */
5954 static void
5955 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5956            Atom *type, XtPointer value, unsigned long *len, int *format)
5957 {
5958   char *fenstr=value;
5959   if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5960   fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5961   EditPositionPasteFEN(fenstr);
5962   XtFree(value);
5963 }
5964
5965 /* called when Paste Position button is pressed,
5966  * all parameters will be NULL */
5967 void PastePositionProc(w, event, prms, nprms)
5968   Widget w;
5969   XEvent *event;
5970   String *prms;
5971   Cardinal *nprms;
5972 {
5973     XtGetSelectionValue(menuBarWidget, XA_PRIMARY, XA_STRING,
5974       /* (XtSelectionCallbackProc) */ PastePositionCB,
5975       NULL, /* client_data passed to PastePositionCB */
5976
5977       /* better to use the time field from the event that triggered the
5978        * call to this function, but that isn't trivial to get
5979        */
5980       CurrentTime
5981     );
5982     return;
5983 }
5984
5985 static Boolean
5986 SendGameSelection(Widget w, Atom *selection, Atom *target,
5987                   Atom *type_return, XtPointer *value_return,
5988                   unsigned long *length_return, int *format_return)
5989 {
5990   char *selection_tmp;
5991
5992   if (*target == XA_STRING){
5993     FILE* f = fopen(gameCopyFilename, "r");
5994     long len;
5995     size_t count;
5996     if (f == NULL) return False;
5997     fseek(f, 0, 2);
5998     len = ftell(f);
5999     rewind(f);
6000     selection_tmp = XtMalloc(len + 1);
6001     count = fread(selection_tmp, 1, len, f);
6002     if (len != count) {
6003       XtFree(selection_tmp);
6004       return False;
6005     }
6006     selection_tmp[len] = NULLCHAR;
6007     *value_return = selection_tmp;
6008     *length_return = len;
6009     *type_return = XA_STRING;
6010     *format_return = 8; /* bits per byte */
6011     return True;
6012   } else {
6013     return False;
6014   }
6015 }
6016
6017 /* note: when called from menu all parameters are NULL, so no clue what the
6018  * Widget which was clicked on was, or what the click event was
6019  */
6020 void CopyGameProc(w, event, prms, nprms)
6021   Widget w;
6022   XEvent *event;
6023   String *prms;
6024   Cardinal *nprms;
6025 {
6026   int ret;
6027
6028   ret = SaveGameToFile(gameCopyFilename, FALSE);
6029   if (!ret) return;
6030
6031   ret = XtOwnSelection(menuBarWidget, XA_PRIMARY,
6032                        CurrentTime,
6033                        SendGameSelection,
6034                        NULL/* lose_ownership_proc */ ,
6035                        NULL/* transfer_done_proc */);
6036 }
6037
6038 /* function called when the data to Paste is ready */
6039 static void
6040 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
6041             Atom *type, XtPointer value, unsigned long *len, int *format)
6042 {
6043   FILE* f;
6044   if (value == NULL || *len == 0) {
6045     return; /* nothing had been selected to copy */
6046   }
6047   f = fopen(gamePasteFilename, "w");
6048   if (f == NULL) {
6049     DisplayError(_("Can't open temp file"), errno);
6050     return;
6051   }
6052   fwrite(value, 1, *len, f);
6053   fclose(f);
6054   XtFree(value);
6055   LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
6056 }
6057
6058 /* called when Paste Game button is pressed,
6059  * all parameters will be NULL */
6060 void PasteGameProc(w, event, prms, nprms)
6061   Widget w;
6062   XEvent *event;
6063   String *prms;
6064   Cardinal *nprms;
6065 {
6066     XtGetSelectionValue(menuBarWidget, XA_PRIMARY, XA_STRING,
6067       /* (XtSelectionCallbackProc) */ PasteGameCB,
6068       NULL, /* client_data passed to PasteGameCB */
6069
6070       /* better to use the time field from the event that triggered the
6071        * call to this function, but that isn't trivial to get
6072        */
6073       CurrentTime
6074     );
6075     return;
6076 }
6077
6078
6079 void AutoSaveGame()
6080 {
6081     SaveGameProc(NULL, NULL, NULL, NULL);
6082 }
6083
6084 void MachineBlackProc(w, event, prms, nprms)
6085      Widget w;
6086      XEvent *event;
6087      String *prms;
6088      Cardinal *nprms;
6089 {
6090     MachineBlackEvent();
6091 }
6092
6093 void MachineWhiteProc(w, event, prms, nprms)
6094      Widget w;
6095      XEvent *event;
6096      String *prms;
6097      Cardinal *nprms;
6098 {
6099     MachineWhiteEvent();
6100 }
6101
6102 void AnalyzeModeProc(w, event, prms, nprms)
6103      Widget w;
6104      XEvent *event;
6105      String *prms;
6106      Cardinal *nprms;
6107 {
6108     char buf[MSG_SIZ];
6109
6110     if (!first.analysisSupport) {
6111       snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6112       DisplayError(buf, 0);
6113       return;
6114     }
6115     /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
6116     if (appData.icsActive) {
6117         if (gameMode != IcsObserving) {
6118             sprintf(buf,_("You are not observing a game"));
6119             DisplayError(buf, 0);
6120             /* secure check */
6121             if (appData.icsEngineAnalyze) {
6122                 if (appData.debugMode)
6123                     fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
6124                 ExitAnalyzeMode();
6125                 ModeHighlight();
6126             }
6127             return;
6128         }
6129         /* if enable, use want disable icsEngineAnalyze */
6130         if (appData.icsEngineAnalyze) {
6131                 ExitAnalyzeMode();
6132                 ModeHighlight();
6133                 return;
6134         }
6135         appData.icsEngineAnalyze = TRUE;
6136         if (appData.debugMode)
6137             fprintf(debugFP, _("ICS engine analyze starting... \n"));
6138     }
6139     if (!appData.showThinking)
6140       ShowThinkingProc(w,event,prms,nprms);
6141
6142     AnalyzeModeEvent();
6143 }
6144
6145 void AnalyzeFileProc(w, event, prms, nprms)
6146      Widget w;
6147      XEvent *event;
6148      String *prms;
6149      Cardinal *nprms;
6150 {
6151     if (!first.analysisSupport) {
6152       char buf[MSG_SIZ];
6153       snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6154       DisplayError(buf, 0);
6155       return;
6156     }
6157     Reset(FALSE, TRUE);
6158
6159     if (!appData.showThinking)
6160       ShowThinkingProc(w,event,prms,nprms);
6161
6162     AnalyzeFileEvent();
6163     FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
6164     AnalysisPeriodicEvent(1);
6165 }
6166
6167 void TwoMachinesProc(w, event, prms, nprms)
6168      Widget w;
6169      XEvent *event;
6170      String *prms;
6171      Cardinal *nprms;
6172 {
6173     TwoMachinesEvent();
6174 }
6175
6176 void IcsClientProc(w, event, prms, nprms)
6177      Widget w;
6178      XEvent *event;
6179      String *prms;
6180      Cardinal *nprms;
6181 {
6182     IcsClientEvent();
6183 }
6184
6185 void EditGameProc(w, event, prms, nprms)
6186      Widget w;
6187      XEvent *event;
6188      String *prms;
6189      Cardinal *nprms;
6190 {
6191     EditGameEvent();
6192 }
6193
6194 void EditPositionProc(w, event, prms, nprms)
6195      Widget w;
6196      XEvent *event;
6197      String *prms;
6198      Cardinal *nprms;
6199 {
6200     EditPositionEvent();
6201 }
6202
6203 void TrainingProc(w, event, prms, nprms)
6204      Widget w;
6205      XEvent *event;
6206      String *prms;
6207      Cardinal *nprms;
6208 {
6209     TrainingEvent();
6210 }
6211
6212 void EditCommentProc(w, event, prms, nprms)
6213      Widget w;
6214      XEvent *event;
6215      String *prms;
6216      Cardinal *nprms;
6217 {
6218     if (editUp) {
6219         EditCommentPopDown();
6220     } else {
6221         EditCommentEvent();
6222     }
6223 }
6224
6225 void IcsInputBoxProc(w, event, prms, nprms)
6226      Widget w;
6227      XEvent *event;
6228      String *prms;
6229      Cardinal *nprms;
6230 {
6231     if (ICSInputBoxUp) {
6232         ICSInputBoxPopDown();
6233     } else {
6234         ICSInputBoxPopUp();
6235     }
6236 }
6237
6238 void AcceptProc(w, event, prms, nprms)
6239      Widget w;
6240      XEvent *event;
6241      String *prms;
6242      Cardinal *nprms;
6243 {
6244     AcceptEvent();
6245 }
6246
6247 void DeclineProc(w, event, prms, nprms)
6248      Widget w;
6249      XEvent *event;
6250      String *prms;
6251      Cardinal *nprms;
6252 {
6253     DeclineEvent();
6254 }
6255
6256 void RematchProc(w, event, prms, nprms)
6257      Widget w;
6258      XEvent *event;
6259      String *prms;
6260      Cardinal *nprms;
6261 {
6262     RematchEvent();
6263 }
6264
6265 void CallFlagProc(w, event, prms, nprms)
6266      Widget w;
6267      XEvent *event;
6268      String *prms;
6269      Cardinal *nprms;
6270 {
6271     CallFlagEvent();
6272 }
6273
6274 void DrawProc(w, event, prms, nprms)
6275      Widget w;
6276      XEvent *event;
6277      String *prms;
6278      Cardinal *nprms;
6279 {
6280     DrawEvent();
6281 }
6282
6283 void AbortProc(w, event, prms, nprms)
6284      Widget w;
6285      XEvent *event;
6286      String *prms;
6287      Cardinal *nprms;
6288 {
6289     AbortEvent();
6290 }
6291
6292 void AdjournProc(w, event, prms, nprms)
6293      Widget w;
6294      XEvent *event;
6295      String *prms;
6296      Cardinal *nprms;
6297 {
6298     AdjournEvent();
6299 }
6300
6301 void ResignProc(w, event, prms, nprms)
6302      Widget w;
6303      XEvent *event;
6304      String *prms;
6305      Cardinal *nprms;
6306 {
6307     ResignEvent();
6308 }
6309
6310 void AdjuWhiteProc(w, event, prms, nprms)
6311      Widget w;
6312      XEvent *event;
6313      String *prms;
6314      Cardinal *nprms;
6315 {
6316     UserAdjudicationEvent(+1);
6317 }
6318
6319 void AdjuBlackProc(w, event, prms, nprms)
6320      Widget w;
6321      XEvent *event;
6322      String *prms;
6323      Cardinal *nprms;
6324 {
6325     UserAdjudicationEvent(-1);
6326 }
6327
6328 void AdjuDrawProc(w, event, prms, nprms)
6329      Widget w;
6330      XEvent *event;
6331      String *prms;
6332      Cardinal *nprms;
6333 {
6334     UserAdjudicationEvent(0);
6335 }
6336
6337 void EnterKeyProc(w, event, prms, nprms)
6338      Widget w;
6339      XEvent *event;
6340      String *prms;
6341      Cardinal *nprms;
6342 {
6343     if (ICSInputBoxUp == True)
6344       ICSInputSendText();
6345 }
6346
6347 void StopObservingProc(w, event, prms, nprms)
6348      Widget w;
6349      XEvent *event;
6350      String *prms;
6351      Cardinal *nprms;
6352 {
6353     StopObservingEvent();
6354 }
6355
6356 void StopExaminingProc(w, event, prms, nprms)
6357      Widget w;
6358      XEvent *event;
6359      String *prms;
6360      Cardinal *nprms;
6361 {
6362     StopExaminingEvent();
6363 }
6364
6365
6366 void ForwardProc(w, event, prms, nprms)
6367      Widget w;
6368      XEvent *event;
6369      String *prms;
6370      Cardinal *nprms;
6371 {
6372     ForwardEvent();
6373 }
6374
6375
6376 void BackwardProc(w, event, prms, nprms)
6377      Widget w;
6378      XEvent *event;
6379      String *prms;
6380      Cardinal *nprms;
6381 {
6382     BackwardEvent();
6383 }
6384
6385 void ToStartProc(w, event, prms, nprms)
6386      Widget w;
6387      XEvent *event;
6388      String *prms;
6389      Cardinal *nprms;
6390 {
6391     ToStartEvent();
6392 }
6393
6394 void ToEndProc(w, event, prms, nprms)
6395      Widget w;
6396      XEvent *event;
6397      String *prms;
6398      Cardinal *nprms;
6399 {
6400     ToEndEvent();
6401 }
6402
6403 void RevertProc(w, event, prms, nprms)
6404      Widget w;
6405      XEvent *event;
6406      String *prms;
6407      Cardinal *nprms;
6408 {
6409     RevertEvent();
6410 }
6411
6412 void TruncateGameProc(w, event, prms, nprms)
6413      Widget w;
6414      XEvent *event;
6415      String *prms;
6416      Cardinal *nprms;
6417 {
6418     TruncateGameEvent();
6419 }
6420 void RetractMoveProc(w, event, prms, nprms)
6421      Widget w;
6422      XEvent *event;
6423      String *prms;
6424      Cardinal *nprms;
6425 {
6426     RetractMoveEvent();
6427 }
6428
6429 void MoveNowProc(w, event, prms, nprms)
6430      Widget w;
6431      XEvent *event;
6432      String *prms;
6433      Cardinal *nprms;
6434 {
6435     MoveNowEvent();
6436 }
6437
6438
6439 void AlwaysQueenProc(w, event, prms, nprms)
6440      Widget w;
6441      XEvent *event;
6442      String *prms;
6443      Cardinal *nprms;
6444 {
6445     Arg args[16];
6446
6447     appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6448
6449     if (appData.alwaysPromoteToQueen) {
6450         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6451     } else {
6452         XtSetArg(args[0], XtNleftBitmap, None);
6453     }
6454     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6455                 args, 1);
6456 }
6457
6458 void AnimateDraggingProc(w, event, prms, nprms)
6459      Widget w;
6460      XEvent *event;
6461      String *prms;
6462      Cardinal *nprms;
6463 {
6464     Arg args[16];
6465
6466     appData.animateDragging = !appData.animateDragging;
6467
6468     if (appData.animateDragging) {
6469         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6470         CreateAnimVars();
6471     } else {
6472         XtSetArg(args[0], XtNleftBitmap, None);
6473     }
6474     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6475                 args, 1);
6476 }
6477
6478 void AnimateMovingProc(w, event, prms, nprms)
6479      Widget w;
6480      XEvent *event;
6481      String *prms;
6482      Cardinal *nprms;
6483 {
6484     Arg args[16];
6485
6486     appData.animate = !appData.animate;
6487
6488     if (appData.animate) {
6489         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6490         CreateAnimVars();
6491     } else {
6492         XtSetArg(args[0], XtNleftBitmap, None);
6493     }
6494     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6495                 args, 1);
6496 }
6497
6498 void AutocommProc(w, event, prms, nprms)
6499      Widget w;
6500      XEvent *event;
6501      String *prms;
6502      Cardinal *nprms;
6503 {
6504     Arg args[16];
6505
6506     appData.autoComment = !appData.autoComment;
6507
6508     if (appData.autoComment) {
6509         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6510     } else {
6511         XtSetArg(args[0], XtNleftBitmap, None);
6512     }
6513     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6514                 args, 1);
6515 }
6516
6517
6518 void AutoflagProc(w, event, prms, nprms)
6519      Widget w;
6520      XEvent *event;
6521      String *prms;
6522      Cardinal *nprms;
6523 {
6524     Arg args[16];
6525
6526     appData.autoCallFlag = !appData.autoCallFlag;
6527
6528     if (appData.autoCallFlag) {
6529         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6530     } else {
6531         XtSetArg(args[0], XtNleftBitmap, None);
6532     }
6533     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6534                 args, 1);
6535 }
6536
6537 void AutoflipProc(w, event, prms, nprms)
6538      Widget w;
6539      XEvent *event;
6540      String *prms;
6541      Cardinal *nprms;
6542 {
6543     Arg args[16];
6544
6545     appData.autoFlipView = !appData.autoFlipView;
6546
6547     if (appData.autoFlipView) {
6548         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6549     } else {
6550         XtSetArg(args[0], XtNleftBitmap, None);
6551     }
6552     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6553                 args, 1);
6554 }
6555
6556 void AutobsProc(w, event, prms, nprms)
6557      Widget w;
6558      XEvent *event;
6559      String *prms;
6560      Cardinal *nprms;
6561 {
6562     Arg args[16];
6563
6564     appData.autoObserve = !appData.autoObserve;
6565
6566     if (appData.autoObserve) {
6567         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6568     } else {
6569         XtSetArg(args[0], XtNleftBitmap, None);
6570     }
6571     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6572                 args, 1);
6573 }
6574
6575 void AutoraiseProc(w, event, prms, nprms)
6576      Widget w;
6577      XEvent *event;
6578      String *prms;
6579      Cardinal *nprms;
6580 {
6581     Arg args[16];
6582
6583     appData.autoRaiseBoard = !appData.autoRaiseBoard;
6584
6585     if (appData.autoRaiseBoard) {
6586         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6587     } else {
6588         XtSetArg(args[0], XtNleftBitmap, None);
6589     }
6590     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6591                 args, 1);
6592 }
6593
6594 void AutosaveProc(w, event, prms, nprms)
6595      Widget w;
6596      XEvent *event;
6597      String *prms;
6598      Cardinal *nprms;
6599 {
6600     Arg args[16];
6601
6602     appData.autoSaveGames = !appData.autoSaveGames;
6603
6604     if (appData.autoSaveGames) {
6605         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6606     } else {
6607         XtSetArg(args[0], XtNleftBitmap, None);
6608     }
6609     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6610                 args, 1);
6611 }
6612
6613 void BlindfoldProc(w, event, prms, nprms)
6614      Widget w;
6615      XEvent *event;
6616      String *prms;
6617      Cardinal *nprms;
6618 {
6619     Arg args[16];
6620
6621     appData.blindfold = !appData.blindfold;
6622
6623     if (appData.blindfold) {
6624         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6625     } else {
6626         XtSetArg(args[0], XtNleftBitmap, None);
6627     }
6628     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6629                 args, 1);
6630
6631     DrawPosition(True, NULL);
6632 }
6633
6634 void TestLegalityProc(w, event, prms, nprms)
6635      Widget w;
6636      XEvent *event;
6637      String *prms;
6638      Cardinal *nprms;
6639 {
6640     Arg args[16];
6641
6642     appData.testLegality = !appData.testLegality;
6643
6644     if (appData.testLegality) {
6645         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6646     } else {
6647         XtSetArg(args[0], XtNleftBitmap, None);
6648     }
6649     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6650                 args, 1);
6651 }
6652
6653
6654 void FlashMovesProc(w, event, prms, nprms)
6655      Widget w;
6656      XEvent *event;
6657      String *prms;
6658      Cardinal *nprms;
6659 {
6660     Arg args[16];
6661
6662     if (appData.flashCount == 0) {
6663         appData.flashCount = 3;
6664     } else {
6665         appData.flashCount = -appData.flashCount;
6666     }
6667
6668     if (appData.flashCount > 0) {
6669         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6670     } else {
6671         XtSetArg(args[0], XtNleftBitmap, None);
6672     }
6673     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6674                 args, 1);
6675 }
6676
6677 void FlipViewProc(w, event, prms, nprms)
6678      Widget w;
6679      XEvent *event;
6680      String *prms;
6681      Cardinal *nprms;
6682 {
6683     flipView = !flipView;
6684     DrawPosition(True, NULL);
6685 }
6686
6687 void GetMoveListProc(w, event, prms, nprms)
6688      Widget w;
6689      XEvent *event;
6690      String *prms;
6691      Cardinal *nprms;
6692 {
6693     Arg args[16];
6694
6695     appData.getMoveList = !appData.getMoveList;
6696
6697     if (appData.getMoveList) {
6698         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6699         GetMoveListEvent();
6700     } else {
6701         XtSetArg(args[0], XtNleftBitmap, None);
6702     }
6703     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6704                 args, 1);
6705 }
6706
6707 #if HIGHDRAG
6708 void HighlightDraggingProc(w, event, prms, nprms)
6709      Widget w;
6710      XEvent *event;
6711      String *prms;
6712      Cardinal *nprms;
6713 {
6714     Arg args[16];
6715
6716     appData.highlightDragging = !appData.highlightDragging;
6717
6718     if (appData.highlightDragging) {
6719         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6720     } else {
6721         XtSetArg(args[0], XtNleftBitmap, None);
6722     }
6723     XtSetValues(XtNameToWidget(menuBarWidget,
6724                                "menuOptions.Highlight Dragging"), args, 1);
6725 }
6726 #endif
6727
6728 void HighlightLastMoveProc(w, event, prms, nprms)
6729      Widget w;
6730      XEvent *event;
6731      String *prms;
6732      Cardinal *nprms;
6733 {
6734     Arg args[16];
6735
6736     appData.highlightLastMove = !appData.highlightLastMove;
6737
6738     if (appData.highlightLastMove) {
6739         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6740     } else {
6741         XtSetArg(args[0], XtNleftBitmap, None);
6742     }
6743     XtSetValues(XtNameToWidget(menuBarWidget,
6744                                "menuOptions.Highlight Last Move"), args, 1);
6745 }
6746
6747 void IcsAlarmProc(w, event, prms, nprms)
6748      Widget w;
6749      XEvent *event;
6750      String *prms;
6751      Cardinal *nprms;
6752 {
6753     Arg args[16];
6754
6755     appData.icsAlarm = !appData.icsAlarm;
6756
6757     if (appData.icsAlarm) {
6758         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6759     } else {
6760         XtSetArg(args[0], XtNleftBitmap, None);
6761     }
6762     XtSetValues(XtNameToWidget(menuBarWidget,
6763                                "menuOptions.ICS Alarm"), args, 1);
6764 }
6765
6766 void MoveSoundProc(w, event, prms, nprms)
6767      Widget w;
6768      XEvent *event;
6769      String *prms;
6770      Cardinal *nprms;
6771 {
6772     Arg args[16];
6773
6774     appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6775
6776     if (appData.ringBellAfterMoves) {
6777         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6778     } else {
6779         XtSetArg(args[0], XtNleftBitmap, None);
6780     }
6781     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6782                 args, 1);
6783 }
6784
6785
6786 void OldSaveStyleProc(w, event, prms, nprms)
6787      Widget w;
6788      XEvent *event;
6789      String *prms;
6790      Cardinal *nprms;
6791 {
6792     Arg args[16];
6793
6794     appData.oldSaveStyle = !appData.oldSaveStyle;
6795
6796     if (appData.oldSaveStyle) {
6797         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6798     } else {
6799         XtSetArg(args[0], XtNleftBitmap, None);
6800     }
6801     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6802                 args, 1);
6803 }
6804
6805 void PeriodicUpdatesProc(w, event, prms, nprms)
6806      Widget w;
6807      XEvent *event;
6808      String *prms;
6809      Cardinal *nprms;
6810 {
6811     Arg args[16];
6812
6813     PeriodicUpdatesEvent(!appData.periodicUpdates);
6814
6815     if (appData.periodicUpdates) {
6816         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6817     } else {
6818         XtSetArg(args[0], XtNleftBitmap, None);
6819     }
6820     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6821                 args, 1);
6822 }
6823
6824 void PonderNextMoveProc(w, event, prms, nprms)
6825      Widget w;
6826      XEvent *event;
6827      String *prms;
6828      Cardinal *nprms;
6829 {
6830     Arg args[16];
6831
6832     PonderNextMoveEvent(!appData.ponderNextMove);
6833
6834     if (appData.ponderNextMove) {
6835         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6836     } else {
6837         XtSetArg(args[0], XtNleftBitmap, None);
6838     }
6839     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6840                 args, 1);
6841 }
6842
6843 void PopupExitMessageProc(w, event, prms, nprms)
6844      Widget w;
6845      XEvent *event;
6846      String *prms;
6847      Cardinal *nprms;
6848 {
6849     Arg args[16];
6850
6851     appData.popupExitMessage = !appData.popupExitMessage;
6852
6853     if (appData.popupExitMessage) {
6854         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6855     } else {
6856         XtSetArg(args[0], XtNleftBitmap, None);
6857     }
6858     XtSetValues(XtNameToWidget(menuBarWidget,
6859                                "menuOptions.Popup Exit Message"), args, 1);
6860 }
6861
6862 void PopupMoveErrorsProc(w, event, prms, nprms)
6863      Widget w;
6864      XEvent *event;
6865      String *prms;
6866      Cardinal *nprms;
6867 {
6868     Arg args[16];
6869
6870     appData.popupMoveErrors = !appData.popupMoveErrors;
6871
6872     if (appData.popupMoveErrors) {
6873         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6874     } else {
6875         XtSetArg(args[0], XtNleftBitmap, None);
6876     }
6877     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6878                 args, 1);
6879 }
6880
6881 void PremoveProc(w, event, prms, nprms)
6882      Widget w;
6883      XEvent *event;
6884      String *prms;
6885      Cardinal *nprms;
6886 {
6887     Arg args[16];
6888
6889     appData.premove = !appData.premove;
6890
6891     if (appData.premove) {
6892         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6893     } else {
6894         XtSetArg(args[0], XtNleftBitmap, None);
6895     }
6896     XtSetValues(XtNameToWidget(menuBarWidget,
6897                                "menuOptions.Premove"), args, 1);
6898 }
6899
6900 void QuietPlayProc(w, event, prms, nprms)
6901      Widget w;
6902      XEvent *event;
6903      String *prms;
6904      Cardinal *nprms;
6905 {
6906     Arg args[16];
6907
6908     appData.quietPlay = !appData.quietPlay;
6909
6910     if (appData.quietPlay) {
6911         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6912     } else {
6913         XtSetArg(args[0], XtNleftBitmap, None);
6914     }
6915     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6916                 args, 1);
6917 }
6918
6919 void ShowThinkingProc(w, event, prms, nprms)
6920      Widget w;
6921      XEvent *event;
6922      String *prms;
6923      Cardinal *nprms;
6924 {
6925     Arg args[16];
6926
6927     appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6928     ShowThinkingEvent();
6929 #if 0
6930     // [HGM] thinking: currently no suc menu item; replaced by Hide Thinking (From Human)
6931     if (appData.showThinking) {
6932         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6933     } else {
6934         XtSetArg(args[0], XtNleftBitmap, None);
6935     }
6936     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Thinking"),
6937                 args, 1);
6938 #endif
6939 }
6940
6941 void HideThinkingProc(w, event, prms, nprms)
6942      Widget w;
6943      XEvent *event;
6944      String *prms;
6945      Cardinal *nprms;
6946 {
6947     Arg args[16];
6948
6949     appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6950     ShowThinkingEvent();
6951
6952     if (appData.hideThinkingFromHuman) {
6953         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6954     } else {
6955         XtSetArg(args[0], XtNleftBitmap, None);
6956     }
6957     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6958                 args, 1);
6959 }
6960
6961 void InfoProc(w, event, prms, nprms)
6962      Widget w;
6963      XEvent *event;
6964      String *prms;
6965      Cardinal *nprms;
6966 {
6967     char buf[MSG_SIZ];
6968     snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6969             INFODIR, INFOFILE);
6970     system(buf);
6971 }
6972
6973 void ManProc(w, event, prms, nprms)
6974      Widget w;
6975      XEvent *event;
6976      String *prms;
6977      Cardinal *nprms;
6978 {
6979     char buf[MSG_SIZ];
6980     String name;
6981     if (nprms && *nprms > 0)
6982       name = prms[0];
6983     else
6984       name = "xboard";
6985     snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6986     system(buf);
6987 }
6988
6989 void HintProc(w, event, prms, nprms)
6990      Widget w;
6991      XEvent *event;
6992      String *prms;
6993      Cardinal *nprms;
6994 {
6995     HintEvent();
6996 }
6997
6998 void BookProc(w, event, prms, nprms)
6999      Widget w;
7000      XEvent *event;
7001      String *prms;
7002      Cardinal *nprms;
7003 {
7004     BookEvent();
7005 }
7006
7007 void DebugProc(w, event, prms, nprms)
7008      Widget w;
7009      XEvent *event;
7010      String *prms;
7011      Cardinal *nprms;
7012 {
7013     appData.debugMode = !appData.debugMode;
7014 }
7015
7016 void AboutGameProc(w, event, prms, nprms)
7017      Widget w;
7018      XEvent *event;
7019      String *prms;
7020      Cardinal *nprms;
7021 {
7022     AboutGameEvent();
7023 }
7024
7025 void NothingProc(w, event, prms, nprms)
7026      Widget w;
7027      XEvent *event;
7028      String *prms;
7029      Cardinal *nprms;
7030 {
7031     return;
7032 }
7033
7034 void Iconify(w, event, prms, nprms)
7035      Widget w;
7036      XEvent *event;
7037      String *prms;
7038      Cardinal *nprms;
7039 {
7040     Arg args[16];
7041
7042     fromX = fromY = -1;
7043     XtSetArg(args[0], XtNiconic, True);
7044     XtSetValues(shellWidget, args, 1);
7045 }
7046
7047 void DisplayMessage(message, extMessage)
7048      gchar *message, *extMessage;
7049 {
7050     char buf[MSG_SIZ];
7051     Arg arg;
7052
7053     if (extMessage) {
7054         if (*message) {
7055             snprintf(buf, sizeof(buf), "%s  %s", message, extMessage);
7056             message = buf;
7057         } else {
7058             message = extMessage;
7059         }
7060     }
7061  
7062     printf("TODO: message %s\n",message);
7063     gtk_label_set_text( GTK_LABEL(gtk_builder_get_object (builder, "Messages")),message);
7064 }
7065
7066 void DisplayTitle(text)
7067      char *text;
7068 {
7069     Arg args[16];
7070     int i;
7071     char title[MSG_SIZ];
7072     char icon[MSG_SIZ];
7073
7074     if (text == NULL) text = "";
7075
7076     if (appData.titleInWindow) {
7077         i = 0;
7078         XtSetArg(args[i], XtNlabel, text);   i++;
7079         XtSetValues(titleWidget, args, i);
7080     }
7081
7082     if (*text != NULLCHAR) {
7083         strcpy(icon, text);
7084         strcpy(title, text);
7085     } else if (appData.icsActive) {
7086         snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7087         snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7088     } else if (appData.cmailGameName[0] != NULLCHAR) {
7089         snprintf(icon, sizeof(icon), "%s", "CMail");
7090         snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7091 #ifdef GOTHIC
7092     // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7093     } else if (gameInfo.variant == VariantGothic) {
7094         strcpy(icon, programName);
7095         strcpy(title, GOTHIC);
7096 #endif
7097 #ifdef FALCON
7098     } else if (gameInfo.variant == VariantFalcon) {
7099         strcpy(icon, programName);
7100         strcpy(title, FALCON);
7101 #endif
7102     } else if (appData.noChessProgram) {
7103         strcpy(icon, programName);
7104         strcpy(title, programName);
7105     } else {
7106         strcpy(icon, first.tidy);
7107         snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7108     }
7109     i = 0;
7110     XtSetArg(args[i], XtNiconName, (XtArgVal) icon);    i++;
7111     XtSetArg(args[i], XtNtitle, (XtArgVal) title);      i++;
7112     XtSetValues(shellWidget, args, i);
7113 }
7114
7115
7116 void DisplayError(message, error)
7117      String message;
7118      int error;
7119 {
7120     char buf[MSG_SIZ];
7121
7122     if (error == 0) {
7123         if (appData.debugMode || appData.matchMode) {
7124             fprintf(stderr, "%s: %s\n", programName, message);
7125         }
7126     } else {
7127         if (appData.debugMode || appData.matchMode) {
7128             fprintf(stderr, "%s: %s: %s\n",
7129                     programName, message, strerror(error));
7130         }
7131         snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7132         message = buf;
7133     }
7134     ErrorPopUp(_("Error"), message, FALSE);
7135 }
7136
7137
7138 void DisplayMoveError(message)
7139      String message;
7140 {
7141     fromX = fromY = -1;
7142     ClearHighlights();
7143     DrawPosition(FALSE, NULL);
7144     if (appData.debugMode || appData.matchMode) {
7145         fprintf(stderr, "%s: %s\n", programName, message);
7146     }
7147     if (appData.popupMoveErrors) {
7148         ErrorPopUp(_("Error"), message, FALSE);
7149     } else {
7150         DisplayMessage(message, "");
7151     }
7152 }
7153
7154
7155 void DisplayFatalError(message, error, status)
7156      String message;
7157      int error, status;
7158 {
7159     char buf[MSG_SIZ];
7160
7161     errorExitStatus = status;
7162     if (error == 0) {
7163         fprintf(stderr, "%s: %s\n", programName, message);
7164     } else {
7165         fprintf(stderr, "%s: %s: %s\n",
7166                 programName, message, strerror(error));
7167         snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7168         message = buf;
7169     }
7170     if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7171       ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7172     } else {
7173       ExitEvent(status);
7174     }
7175 }
7176
7177 void DisplayInformation(message)
7178      String message;
7179 {
7180     ErrorPopDown();
7181     ErrorPopUp(_("Information"), message, TRUE);
7182 }
7183
7184 void DisplayNote(message)
7185      String message;
7186 {
7187     ErrorPopDown();
7188     ErrorPopUp(_("Note"), message, FALSE);
7189 }
7190
7191 static int
7192 NullXErrorCheck(dpy, error_event)
7193      Display *dpy;
7194      XErrorEvent *error_event;
7195 {
7196     return 0;
7197 }
7198
7199 void DisplayIcsInteractionTitle(message)
7200      String message;
7201 {
7202   if (oldICSInteractionTitle == NULL) {
7203     /* Magic to find the old window title, adapted from vim */
7204     char *wina = getenv("WINDOWID");
7205     if (wina != NULL) {
7206       Window win = (Window) atoi(wina);
7207       Window root, parent, *children;
7208       unsigned int nchildren;
7209       int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7210       for (;;) {
7211         if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7212         if (!XQueryTree(xDisplay, win, &root, &parent,
7213                         &children, &nchildren)) break;
7214         if (children) XFree((void *)children);
7215         if (parent == root || parent == 0) break;
7216         win = parent;
7217       }
7218       XSetErrorHandler(oldHandler);
7219     }
7220     if (oldICSInteractionTitle == NULL) {
7221       oldICSInteractionTitle = "xterm";
7222     }
7223   }
7224   printf("\033]0;%s\007", message);
7225   fflush(stdout);
7226 }
7227
7228 char pendingReplyPrefix[MSG_SIZ];
7229 ProcRef pendingReplyPR;
7230
7231 void AskQuestionProc(w, event, prms, nprms)
7232      Widget w;
7233      XEvent *event;
7234      String *prms;
7235      Cardinal *nprms;
7236 {
7237     if (*nprms != 4) {
7238         fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7239                 *nprms);
7240         return;
7241     }
7242     AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7243 }
7244
7245 void AskQuestionPopDown()
7246 {
7247     if (!askQuestionUp) return;
7248     XtPopdown(askQuestionShell);
7249     XtDestroyWidget(askQuestionShell);
7250     askQuestionUp = False;
7251 }
7252
7253 void AskQuestionReplyAction(w, event, prms, nprms)
7254      Widget w;
7255      XEvent *event;
7256      String *prms;
7257      Cardinal *nprms;
7258 {
7259     char buf[MSG_SIZ];
7260     int err;
7261     String reply;
7262
7263     reply = XawDialogGetValueString(w = XtParent(w));
7264     strcpy(buf, pendingReplyPrefix);
7265     if (*buf) strcat(buf, " ");
7266     strcat(buf, reply);
7267     strcat(buf, "\n");
7268     OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7269     AskQuestionPopDown();
7270
7271     if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7272 }
7273
7274 void AskQuestionCallback(w, client_data, call_data)
7275      Widget w;
7276      XtPointer client_data, call_data;
7277 {
7278     String name;
7279     Arg args[16];
7280
7281     XtSetArg(args[0], XtNlabel, &name);
7282     XtGetValues(w, args, 1);
7283
7284     if (strcmp(name, _("cancel")) == 0) {
7285         AskQuestionPopDown();
7286     } else {
7287         AskQuestionReplyAction(w, NULL, NULL, NULL);
7288     }
7289 }
7290
7291 void AskQuestion(title, question, replyPrefix, pr)
7292      char *title, *question, *replyPrefix;
7293      ProcRef pr;
7294 {
7295     Arg args[16];
7296     Widget popup, layout, dialog, edit;
7297     Window root, child;
7298     int x, y, i;
7299     int win_x, win_y;
7300     unsigned int mask;
7301
7302     strcpy(pendingReplyPrefix, replyPrefix);
7303     pendingReplyPR = pr;
7304
7305     i = 0;
7306     XtSetArg(args[i], XtNresizable, True); i++;
7307     XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7308     askQuestionShell = popup =
7309       XtCreatePopupShell(title, transientShellWidgetClass,
7310                          shellWidget, args, i);
7311
7312     layout =
7313       XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7314                             layoutArgs, XtNumber(layoutArgs));
7315
7316     i = 0;
7317     XtSetArg(args[i], XtNlabel, question); i++;
7318     XtSetArg(args[i], XtNvalue, ""); i++;
7319     XtSetArg(args[i], XtNborderWidth, 0); i++;
7320     dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7321                                    layout, args, i);
7322
7323     XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7324                        (XtPointer) dialog);
7325     XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7326                        (XtPointer) dialog);
7327
7328     XtRealizeWidget(popup);
7329     CatchDeleteWindow(popup, "AskQuestionPopDown");
7330
7331     XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7332                   &x, &y, &win_x, &win_y, &mask);
7333
7334     XtSetArg(args[0], XtNx, x - 10);
7335     XtSetArg(args[1], XtNy, y - 30);
7336     XtSetValues(popup, args, 2);
7337
7338     XtPopup(popup, XtGrabExclusive);
7339     askQuestionUp = True;
7340
7341     edit = XtNameToWidget(dialog, "*value");
7342     XtSetKeyboardFocus(popup, edit);
7343 }
7344
7345
7346 void
7347 PlaySound(name)
7348      char *name;
7349 {
7350   if (*name == NULLCHAR) {
7351     return;
7352   } else if (strcmp(name, "$") == 0) {
7353     putc(BELLCHAR, stderr);
7354   } else {
7355     char buf[2048];
7356     snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7357     system(buf);
7358   }
7359 }
7360
7361 void
7362 RingBell()
7363 {
7364   PlaySound(appData.soundMove);
7365 }
7366
7367 void
7368 PlayIcsWinSound()
7369 {
7370   PlaySound(appData.soundIcsWin);
7371 }
7372
7373 void
7374 PlayIcsLossSound()
7375 {
7376   PlaySound(appData.soundIcsLoss);
7377 }
7378
7379 void
7380 PlayIcsDrawSound()
7381 {
7382   PlaySound(appData.soundIcsDraw);
7383 }
7384
7385 void
7386 PlayIcsUnfinishedSound()
7387 {
7388   PlaySound(appData.soundIcsUnfinished);
7389 }
7390
7391 void
7392 PlayAlarmSound()
7393 {
7394   PlaySound(appData.soundIcsAlarm);
7395 }
7396
7397 void
7398 EchoOn()
7399 {
7400     system("stty echo");
7401 }
7402
7403 void
7404 EchoOff()
7405 {
7406     system("stty -echo");
7407 }
7408
7409 void
7410 Colorize(cc, continuation)
7411      ColorClass cc;
7412      int continuation;
7413 {
7414     char buf[MSG_SIZ];
7415     int count, outCount, error;
7416
7417     if (textColors[(int)cc].bg > 0) {
7418         if (textColors[(int)cc].fg > 0) {
7419             sprintf(buf, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7420                     textColors[(int)cc].fg, textColors[(int)cc].bg);
7421         } else {
7422             sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7423                     textColors[(int)cc].bg);
7424         }
7425     } else {
7426         if (textColors[(int)cc].fg > 0) {
7427             sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7428                     textColors[(int)cc].fg);
7429         } else {
7430             sprintf(buf, "\033[0;%dm", textColors[(int)cc].attr);
7431         }
7432     }
7433     count = strlen(buf);
7434     outCount = OutputToProcess(NoProc, buf, count, &error);
7435     if (outCount < count) {
7436         DisplayFatalError(_("Error writing to display"), error, 1);
7437     }
7438
7439     if (continuation) return;
7440     switch (cc) {
7441     case ColorShout:
7442       PlaySound(appData.soundShout);
7443       break;
7444     case ColorSShout:
7445       PlaySound(appData.soundSShout);
7446       break;
7447     case ColorChannel1:
7448       PlaySound(appData.soundChannel1);
7449       break;
7450     case ColorChannel:
7451       PlaySound(appData.soundChannel);
7452       break;
7453     case ColorKibitz:
7454       PlaySound(appData.soundKibitz);
7455       break;
7456     case ColorTell:
7457       PlaySound(appData.soundTell);
7458       break;
7459     case ColorChallenge:
7460       PlaySound(appData.soundChallenge);
7461       break;
7462     case ColorRequest:
7463       PlaySound(appData.soundRequest);
7464       break;
7465     case ColorSeek:
7466       PlaySound(appData.soundSeek);
7467       break;
7468     case ColorNormal:
7469     case ColorNone:
7470     default:
7471       break;
7472     }
7473 }
7474
7475 char *UserName()
7476 {
7477     return getpwuid(getuid())->pw_name;
7478 }
7479
7480 static char *ExpandPathName(path)
7481      char *path;
7482 {
7483     static char static_buf[2000];
7484     char *d, *s, buf[2000];
7485     struct passwd *pwd;
7486
7487     s = path;
7488     d = static_buf;
7489
7490     while (*s && isspace(*s))
7491       ++s;
7492
7493     if (!*s) {
7494         *d = 0;
7495         return static_buf;
7496     }
7497
7498     if (*s == '~') {
7499         if (*(s+1) == '/') {
7500             strcpy(d, getpwuid(getuid())->pw_dir);
7501             strcat(d, s+1);
7502         }
7503         else {
7504             strcpy(buf, s+1);
7505             *strchr(buf, '/') = 0;
7506             pwd = getpwnam(buf);
7507             if (!pwd)
7508               {
7509                   fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7510                           buf, path);
7511                   return NULL;
7512               }
7513             strcpy(d, pwd->pw_dir);
7514             strcat(d, strchr(s+1, '/'));
7515         }
7516     }
7517     else
7518       strcpy(d, s);
7519
7520     return static_buf;
7521 }
7522
7523 char *HostName()
7524 {
7525     static char host_name[MSG_SIZ];
7526
7527 #if HAVE_GETHOSTNAME
7528     gethostname(host_name, MSG_SIZ);
7529     return host_name;
7530 #else  /* not HAVE_GETHOSTNAME */
7531 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7532     sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7533     return host_name;
7534 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7535     return "localhost";
7536 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7537 #endif /* not HAVE_GETHOSTNAME */
7538 }
7539
7540 XtIntervalId delayedEventTimerXID = 0;
7541 DelayedEventCallback delayedEventCallback = 0;
7542
7543 void
7544 FireDelayedEvent()
7545 {
7546     delayedEventTimerXID = 0;
7547     delayedEventCallback();
7548 }
7549
7550 void
7551 ScheduleDelayedEvent(cb, millisec)
7552      DelayedEventCallback cb; long millisec;
7553 {
7554     delayedEventCallback = cb;
7555     delayedEventTimerXID =
7556       XtAppAddTimeOut(appContext, millisec,
7557                       (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7558 }
7559
7560 DelayedEventCallback
7561 GetDelayedEvent()
7562 {
7563   if (delayedEventTimerXID) {
7564     return delayedEventCallback;
7565   } else {
7566     return NULL;
7567   }
7568 }
7569
7570 void
7571 CancelDelayedEvent()
7572 {
7573   if (delayedEventTimerXID) {
7574     XtRemoveTimeOut(delayedEventTimerXID);
7575     delayedEventTimerXID = 0;
7576   }
7577 }
7578
7579 XtIntervalId loadGameTimerXID = 0;
7580
7581 int LoadGameTimerRunning()
7582 {
7583     return loadGameTimerXID != 0;
7584 }
7585
7586 int StopLoadGameTimer()
7587 {
7588     if (loadGameTimerXID != 0) {
7589         XtRemoveTimeOut(loadGameTimerXID);
7590         loadGameTimerXID = 0;
7591         return TRUE;
7592     } else {
7593         return FALSE;
7594     }
7595 }
7596
7597 void
7598 LoadGameTimerCallback(arg, id)
7599      XtPointer arg;
7600      XtIntervalId *id;
7601 {
7602     loadGameTimerXID = 0;
7603     AutoPlayGameLoop();
7604 }
7605
7606 void
7607 StartLoadGameTimer(millisec)
7608      long millisec;
7609 {
7610     loadGameTimerXID =
7611       XtAppAddTimeOut(appContext, millisec,
7612                       (XtTimerCallbackProc) LoadGameTimerCallback,
7613                       (XtPointer) 0);
7614 }
7615
7616 XtIntervalId analysisClockXID = 0;
7617
7618 void
7619 AnalysisClockCallback(arg, id)
7620      XtPointer arg;
7621      XtIntervalId *id;
7622 {
7623     if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7624          || appData.icsEngineAnalyze) { // [DM]
7625         AnalysisPeriodicEvent(0);
7626         StartAnalysisClock();
7627     }
7628 }
7629
7630 void
7631 StartAnalysisClock()
7632 {
7633     analysisClockXID =
7634       XtAppAddTimeOut(appContext, 2000,
7635                       (XtTimerCallbackProc) AnalysisClockCallback,
7636                       (XtPointer) 0);
7637 }
7638
7639 XtIntervalId clockTimerXID = 0;
7640
7641 int ClockTimerRunning()
7642 {
7643     return clockTimerXID != 0;
7644 }
7645
7646 int StopClockTimer()
7647 {
7648     if (clockTimerXID != 0) {
7649         XtRemoveTimeOut(clockTimerXID);
7650         clockTimerXID = 0;
7651         return TRUE;
7652     } else {
7653         return FALSE;
7654     }
7655 }
7656
7657 void
7658 ClockTimerCallback(arg, id)
7659      XtPointer arg;
7660      XtIntervalId *id;
7661 {
7662     clockTimerXID = 0;
7663     DecrementClocks();
7664 }
7665
7666 void
7667 StartClockTimer(millisec)
7668      long millisec;
7669 {
7670     clockTimerXID =
7671       XtAppAddTimeOut(appContext, millisec,
7672                       (XtTimerCallbackProc) ClockTimerCallback,
7673                       (XtPointer) 0);
7674 }
7675
7676 void
7677 DisplayTimerLabel(w, color, timer, highlight)
7678      GtkWidget *w;
7679      char *color;
7680      long timer;
7681      int highlight;
7682 {
7683   gchar buf[MSG_SIZ];
7684   
7685   
7686   if (appData.clockMode) {
7687     sprintf(buf, "%s: %s", color, TimeString(timer));
7688   } else {
7689     sprintf(buf, "%s  ", color);
7690   }
7691   gtk_label_set_text(GTK_LABEL(w),buf);
7692
7693   /* check for low time warning */
7694 //    Pixel foregroundOrWarningColor = timerForegroundPixel;
7695
7696 //    if (timer > 0 &&
7697 //        appData.lowTimeWarning && 
7698 //        (timer / 1000) < appData.icsAlarmTime)
7699 //      foregroundOrWarningColor = lowTimeWarningColor;
7700 //
7701 //    if (appData.clockMode) {
7702 //      sprintf(buf, "%s: %s", color, TimeString(timer));
7703 //      XtSetArg(args[0], XtNlabel, buf);
7704 //    } else {
7705 //      sprintf(buf, "%s  ", color);
7706 //      XtSetArg(args[0], XtNlabel, buf);
7707 //    }
7708 //
7709 //    if (highlight) {
7710 //
7711 //      XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7712 //      XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7713 //    } else {
7714 //      XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7715 //      XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7716 //    }
7717 //
7718 //    XtSetValues(w, args, 3);
7719 //
7720 }
7721
7722 void
7723 DisplayWhiteClock(timeRemaining, highlight)
7724      long timeRemaining;
7725      int highlight;
7726 {
7727   if(appData.noGUI) return;
7728
7729   DisplayTimerLabel(GUI_Whiteclock, _("White"), timeRemaining, highlight);
7730   if (highlight && WindowIcon == BlackIcon) {
7731     WindowIcon = WhiteIcon;
7732     gtk_window_set_icon(GTK_WINDOW(GUI_Window),WindowIcon);
7733   }
7734 }
7735
7736 void
7737 DisplayBlackClock(timeRemaining, highlight)
7738      long timeRemaining;
7739      int highlight;
7740 {
7741     if(appData.noGUI) return;
7742     DisplayTimerLabel(GUI_Blackclock, _("Black"), timeRemaining, highlight);
7743     if (highlight && WindowIcon == WhiteIcon) {
7744         WindowIcon = BlackIcon;
7745         gtk_window_set_icon(GTK_WINDOW(GUI_Window),WindowIcon);
7746     }
7747 }
7748
7749 #define CPNone 0
7750 #define CPReal 1
7751 #define CPComm 2
7752 #define CPSock 3
7753 #define CPLoop 4
7754 typedef int CPKind;
7755
7756 typedef struct {
7757     CPKind kind;
7758     int pid;
7759     int fdTo, fdFrom;
7760 } ChildProc;
7761
7762
7763 int StartChildProcess(cmdLine, dir, pr)
7764      char *cmdLine;
7765      char *dir;
7766      ProcRef *pr;
7767 {
7768     char *argv[64], *p;
7769     int i, pid;
7770     int to_prog[2], from_prog[2];
7771     ChildProc *cp;
7772     char buf[MSG_SIZ];
7773
7774     if (appData.debugMode) {
7775         fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7776     }
7777
7778     /* We do NOT feed the cmdLine to the shell; we just
7779        parse it into blank-separated arguments in the
7780        most simple-minded way possible.
7781        */
7782     i = 0;
7783     strcpy(buf, cmdLine);
7784     p = buf;
7785     for (;;) {
7786         argv[i++] = p;
7787         p = strchr(p, ' ');
7788         if (p == NULL) break;
7789         *p++ = NULLCHAR;
7790     }
7791     argv[i] = NULL;
7792
7793     SetUpChildIO(to_prog, from_prog);
7794
7795     if ((pid = fork()) == 0) {
7796         /* Child process */
7797         // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7798         close(to_prog[1]);     // first close the unused pipe ends
7799         close(from_prog[0]);
7800         dup2(to_prog[0], 0);   // to_prog was created first, nd is the only one to use 0 or 1
7801         dup2(from_prog[1], 1);
7802         if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7803         close(from_prog[1]);                   // and closing again loses one of the pipes!
7804         if(fileno(stderr) >= 2) // better safe than sorry...
7805                 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7806
7807         if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7808             perror(dir);
7809             exit(1);
7810         }
7811
7812         nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7813
7814         execvp(argv[0], argv);
7815
7816         /* If we get here, exec failed */
7817         perror(argv[0]);
7818         exit(1);
7819     }
7820
7821     /* Parent process */
7822     close(to_prog[0]);
7823     close(from_prog[1]);
7824
7825     cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7826     cp->kind = CPReal;
7827     cp->pid = pid;
7828     cp->fdFrom = from_prog[0];
7829     cp->fdTo = to_prog[1];
7830     *pr = (ProcRef) cp;
7831     return 0;
7832 }
7833
7834 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7835 static RETSIGTYPE AlarmCallBack(int n)
7836 {
7837     return;
7838 }
7839
7840 void
7841 DestroyChildProcess(pr, signalType)
7842      ProcRef pr;
7843      int signalType;
7844 {
7845     ChildProc *cp = (ChildProc *) pr;
7846
7847     if (cp->kind != CPReal) return;
7848     cp->kind = CPNone;
7849     if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7850         signal(SIGALRM, AlarmCallBack);
7851         alarm(3);
7852         if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7853             kill(cp->pid, SIGKILL); // kill it forcefully
7854             wait((int *) 0);        // and wait again
7855         }
7856     } else {
7857         if (signalType) {
7858             kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7859         }
7860         /* Process is exiting either because of the kill or because of
7861            a quit command sent by the backend; either way, wait for it to die.
7862         */
7863         wait((int *) 0);
7864     }
7865     close(cp->fdFrom);
7866     close(cp->fdTo);
7867 }
7868
7869 void
7870 InterruptChildProcess(pr)
7871      ProcRef pr;
7872 {
7873     ChildProc *cp = (ChildProc *) pr;
7874
7875     if (cp->kind != CPReal) return;
7876     (void) kill(cp->pid, SIGINT); /* stop it thinking */
7877 }
7878
7879 int OpenTelnet(host, port, pr)
7880      char *host;
7881      char *port;
7882      ProcRef *pr;
7883 {
7884     char cmdLine[MSG_SIZ];
7885
7886     if (port[0] == NULLCHAR) {
7887       snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7888     } else {
7889       snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7890     }
7891     return StartChildProcess(cmdLine, "", pr);
7892 }
7893
7894 int OpenTCP(host, port, pr)
7895      char *host;
7896      char *port;
7897      ProcRef *pr;
7898 {
7899 #if OMIT_SOCKETS
7900     DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7901 #else  /* !OMIT_SOCKETS */
7902     int s;
7903     struct sockaddr_in sa;
7904     struct hostent     *hp;
7905     unsigned short uport;
7906     ChildProc *cp;
7907
7908     if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7909         return errno;
7910     }
7911
7912     memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7913     sa.sin_family = AF_INET;
7914     sa.sin_addr.s_addr = INADDR_ANY;
7915     uport = (unsigned short) 0;
7916     sa.sin_port = htons(uport);
7917     if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7918         return errno;
7919     }
7920
7921     memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7922     if (!(hp = gethostbyname(host))) {
7923         int b0, b1, b2, b3;
7924         if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7925             hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7926             hp->h_addrtype = AF_INET;
7927             hp->h_length = 4;
7928             hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7929             hp->h_addr_list[0] = (char *) malloc(4);
7930             hp->h_addr_list[0][0] = b0;
7931             hp->h_addr_list[0][1] = b1;
7932             hp->h_addr_list[0][2] = b2;
7933             hp->h_addr_list[0][3] = b3;
7934         } else {
7935             return ENOENT;
7936         }
7937     }
7938     sa.sin_family = hp->h_addrtype;
7939     uport = (unsigned short) atoi(port);
7940     sa.sin_port = htons(uport);
7941     memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7942
7943     if (connect(s, (struct sockaddr *) &sa,
7944                 sizeof(struct sockaddr_in)) < 0) {
7945         return errno;
7946     }
7947
7948     cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7949     cp->kind = CPSock;
7950     cp->pid = 0;
7951     cp->fdFrom = s;
7952     cp->fdTo = s;
7953     *pr = (ProcRef) cp;
7954
7955 #endif /* !OMIT_SOCKETS */
7956
7957     return 0;
7958 }
7959
7960 int OpenCommPort(name, pr)
7961      char *name;
7962      ProcRef *pr;
7963 {
7964     int fd;
7965     ChildProc *cp;
7966
7967     fd = open(name, 2, 0);
7968     if (fd < 0) return errno;
7969
7970     cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7971     cp->kind = CPComm;
7972     cp->pid = 0;
7973     cp->fdFrom = fd;
7974     cp->fdTo = fd;
7975     *pr = (ProcRef) cp;
7976
7977     return 0;
7978 }
7979
7980 int OpenLoopback(pr)
7981      ProcRef *pr;
7982 {
7983     ChildProc *cp;
7984     int to[2], from[2];
7985
7986     SetUpChildIO(to, from);
7987
7988     cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7989     cp->kind = CPLoop;
7990     cp->pid = 0;
7991     cp->fdFrom = to[0];         /* note not from[0]; we are doing a loopback */
7992     cp->fdTo = to[1];
7993     *pr = (ProcRef) cp;
7994
7995     return 0;
7996 }
7997
7998 int OpenRcmd(host, user, cmd, pr)
7999      char *host, *user, *cmd;
8000      ProcRef *pr;
8001 {
8002     DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
8003     return -1;
8004 }
8005
8006 #define INPUT_SOURCE_BUF_SIZE 8192
8007
8008 typedef struct {
8009     CPKind kind;
8010     int fd;
8011     int lineByLine;
8012     char *unused;
8013     InputCallback func;
8014     XtInputId xid;
8015     char buf[INPUT_SOURCE_BUF_SIZE];
8016     VOIDSTAR closure;
8017 } InputSource;
8018
8019 void
8020 DoInputCallback(closure, source, xid)
8021      caddr_t closure;
8022      int *source;
8023      XtInputId *xid;
8024 {
8025     InputSource *is = (InputSource *) closure;
8026     int count;
8027     int error;
8028     char *p, *q;
8029
8030     if (is->lineByLine) {
8031         count = read(is->fd, is->unused,
8032                      INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
8033         if (count <= 0) {
8034             (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
8035             return;
8036         }
8037         is->unused += count;
8038         p = is->buf;
8039         while (p < is->unused) {
8040             q = memchr(p, '\n', is->unused - p);
8041             if (q == NULL) break;
8042             q++;
8043             (is->func)(is, is->closure, p, q - p, 0);
8044             p = q;
8045         }
8046         q = is->buf;
8047         while (p < is->unused) {
8048             *q++ = *p++;
8049         }
8050         is->unused = q;
8051     } else {
8052         count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8053         if (count == -1)
8054           error = errno;
8055         else
8056           error = 0;
8057         (is->func)(is, is->closure, is->buf, count, error);
8058     }
8059 }
8060
8061 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8062      ProcRef pr;
8063      int lineByLine;
8064      InputCallback func;
8065      VOIDSTAR closure;
8066 {
8067     InputSource *is;
8068     ChildProc *cp = (ChildProc *) pr;
8069
8070     is = (InputSource *) calloc(1, sizeof(InputSource));
8071     is->lineByLine = lineByLine;
8072     is->func = func;
8073     if (pr == NoProc) {
8074         is->kind = CPReal;
8075         is->fd = fileno(stdin);
8076     } else {
8077         is->kind = cp->kind;
8078         is->fd = cp->fdFrom;
8079     }
8080     if (lineByLine) {
8081         is->unused = is->buf;
8082     }
8083
8084     is->xid = XtAppAddInput(appContext, is->fd,
8085                             (XtPointer) (XtInputReadMask),
8086                             (XtInputCallbackProc) DoInputCallback,
8087                             (XtPointer) is);
8088     is->closure = closure;
8089     return (InputSourceRef) is;
8090 }
8091
8092 void
8093 RemoveInputSource(isr)
8094      InputSourceRef isr;
8095 {
8096     InputSource *is = (InputSource *) isr;
8097
8098     if (is->xid == 0) return;
8099     XtRemoveInput(is->xid);
8100     is->xid = 0;
8101 }
8102
8103 int OutputToProcess(pr, message, count, outError)
8104      ProcRef pr;
8105      char *message;
8106      int count;
8107      int *outError;
8108 {
8109     ChildProc *cp = (ChildProc *) pr;
8110     int outCount;
8111
8112     if (pr == NoProc)
8113       outCount = fwrite(message, 1, count, stdout);
8114     else
8115       outCount = write(cp->fdTo, message, count);
8116
8117     if (outCount == -1)
8118       *outError = errno;
8119     else
8120       *outError = 0;
8121
8122     return outCount;
8123 }
8124
8125 /* Output message to process, with "ms" milliseconds of delay
8126    between each character. This is needed when sending the logon
8127    script to ICC, which for some reason doesn't like the
8128    instantaneous send. */
8129 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8130      ProcRef pr;
8131      char *message;
8132      int count;
8133      int *outError;
8134      long msdelay;
8135 {
8136     ChildProc *cp = (ChildProc *) pr;
8137     int outCount = 0;
8138     int r;
8139
8140     while (count--) {
8141         r = write(cp->fdTo, message++, 1);
8142         if (r == -1) {
8143             *outError = errno;
8144             return outCount;
8145         }
8146         ++outCount;
8147         if (msdelay >= 0)
8148           TimeDelay(msdelay);
8149     }
8150
8151     return outCount;
8152 }
8153
8154 /****   Animation code by Hugh Fisher, DCS, ANU.
8155
8156         Known problem: if a window overlapping the board is
8157         moved away while a piece is being animated underneath,
8158         the newly exposed area won't be updated properly.
8159         I can live with this.
8160
8161         Known problem: if you look carefully at the animation
8162         of pieces in mono mode, they are being drawn as solid
8163         shapes without interior detail while moving. Fixing
8164         this would be a major complication for minimal return.
8165 ****/
8166
8167 /*      Masks for XPM pieces. Black and white pieces can have
8168         different shapes, but in the interest of retaining my
8169         sanity pieces must have the same outline on both light
8170         and dark squares, and all pieces must use the same
8171         background square colors/images.                */
8172
8173 static int xpmDone = 0;
8174
8175 static void
8176 CreateAnimMasks (pieceDepth)
8177      int pieceDepth;
8178 {
8179   ChessSquare   piece;
8180   Pixmap        buf;
8181   GC            bufGC, maskGC;
8182   int           kind, n;
8183   unsigned long plane;
8184   XGCValues     values;
8185
8186   /* Need a bitmap just to get a GC with right depth */
8187   buf = XCreatePixmap(xDisplay, xBoardWindow,
8188                         8, 8, 1);
8189   values.foreground = 1;
8190   values.background = 0;
8191   /* Don't use XtGetGC, not read only */
8192   maskGC = XCreateGC(xDisplay, buf,
8193                     GCForeground | GCBackground, &values);
8194   XFreePixmap(xDisplay, buf);
8195
8196   buf = XCreatePixmap(xDisplay, xBoardWindow,
8197                       squareSize, squareSize, pieceDepth);
8198   values.foreground = XBlackPixel(xDisplay, xScreen);
8199   values.background = XWhitePixel(xDisplay, xScreen);
8200   bufGC = XCreateGC(xDisplay, buf,
8201                     GCForeground | GCBackground, &values);
8202
8203   for (piece = WhitePawn; piece <= BlackKing; piece++) {
8204     /* Begin with empty mask */
8205     if(!xpmDone) // [HGM] pieces: keep using existing
8206     xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8207                                  squareSize, squareSize, 1);
8208     XSetFunction(xDisplay, maskGC, GXclear);
8209     XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8210                    0, 0, squareSize, squareSize);
8211
8212     /* Take a copy of the piece */
8213     if (White(piece))
8214       kind = 0;
8215     else
8216       kind = 2;
8217     XSetFunction(xDisplay, bufGC, GXcopy);
8218     XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8219               buf, bufGC,
8220               0, 0, squareSize, squareSize, 0, 0);
8221
8222     /* XOR the background (light) over the piece */
8223     XSetFunction(xDisplay, bufGC, GXxor);
8224     if (useImageSqs)
8225       XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8226                 0, 0, squareSize, squareSize, 0, 0);
8227     else {
8228       XSetForeground(xDisplay, bufGC, lightSquareColor);
8229       XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8230     }
8231
8232     /* We now have an inverted piece image with the background
8233        erased. Construct mask by just selecting all the non-zero
8234        pixels - no need to reconstruct the original image.      */
8235     XSetFunction(xDisplay, maskGC, GXor);
8236     plane = 1;
8237     /* Might be quicker to download an XImage and create bitmap
8238        data from it rather than this N copies per piece, but it
8239        only takes a fraction of a second and there is a much
8240        longer delay for loading the pieces.             */
8241     for (n = 0; n < pieceDepth; n ++) {
8242       XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8243                  0, 0, squareSize, squareSize,
8244                  0, 0, plane);
8245       plane = plane << 1;
8246     }
8247   }
8248   /* Clean up */
8249   XFreePixmap(xDisplay, buf);
8250   XFreeGC(xDisplay, bufGC);
8251   XFreeGC(xDisplay, maskGC);
8252 }
8253
8254 static void
8255 InitAnimState (anim, info)
8256   AnimState * anim;
8257   XWindowAttributes * info;
8258 {
8259   XtGCMask  mask;
8260   XGCValues values;
8261
8262   /* Each buffer is square size, same depth as window */
8263   anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8264                         squareSize, squareSize, info->depth);
8265   anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8266                         squareSize, squareSize, info->depth);
8267
8268   /* Create a plain GC for blitting */
8269   mask = GCForeground | GCBackground | GCFunction |
8270          GCPlaneMask | GCGraphicsExposures;
8271   values.foreground = XBlackPixel(xDisplay, xScreen);
8272   values.background = XWhitePixel(xDisplay, xScreen);
8273   values.function   = GXcopy;
8274   values.plane_mask = AllPlanes;
8275   values.graphics_exposures = False;
8276   anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8277
8278   /* Piece will be copied from an existing context at
8279      the start of each new animation/drag. */
8280   anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8281
8282   /* Outline will be a read-only copy of an existing */
8283   anim->outlineGC = None;
8284 }
8285
8286 static void
8287 CreateAnimVars ()
8288 {
8289   static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8290   XWindowAttributes info;
8291
8292   if (xpmDone && gameInfo.variant == old) return;
8293   if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8294   //  XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8295
8296   InitAnimState(&game, &info);
8297   InitAnimState(&player, &info);
8298
8299   /* For XPM pieces, we need bitmaps to use as masks. */
8300   if (useImages)
8301     CreateAnimMasks(info.depth);
8302    xpmDone = 1;
8303 }
8304
8305 #ifndef HAVE_USLEEP
8306
8307 static Boolean frameWaiting;
8308
8309 static RETSIGTYPE FrameAlarm (sig)
8310      int sig;
8311 {
8312   frameWaiting = False;
8313   /* In case System-V style signals.  Needed?? */
8314   signal(SIGALRM, FrameAlarm);
8315 }
8316
8317 static void
8318 FrameDelay (time)
8319      int time;
8320 {
8321   struct itimerval delay;
8322
8323   XSync(xDisplay, False);
8324
8325   if (time > 0) {
8326     frameWaiting = True;
8327     signal(SIGALRM, FrameAlarm);
8328     delay.it_interval.tv_sec =
8329       delay.it_value.tv_sec = time / 1000;
8330     delay.it_interval.tv_usec =
8331       delay.it_value.tv_usec = (time % 1000) * 1000;
8332     setitimer(ITIMER_REAL, &delay, NULL);
8333 #if 0
8334     /* Ugh -- busy-wait! --tpm */
8335     while (frameWaiting);
8336 #else
8337     while (frameWaiting) pause();
8338 #endif
8339     delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8340     delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8341     setitimer(ITIMER_REAL, &delay, NULL);
8342   }
8343 }
8344
8345 #else
8346
8347 static void
8348 FrameDelay (time)
8349      int time;
8350 {
8351   XSync(xDisplay, False);
8352   if (time > 0)
8353     usleep(time * 1000);
8354 }
8355
8356 #endif
8357
8358 /*      Convert board position to corner of screen rect and color       */
8359
8360 static void
8361 ScreenSquare(column, row, pt, color)
8362      int column; int row; XPoint * pt; int * color;
8363 {
8364   if (flipView) {
8365     pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8366     pt->y = lineGap + row * (squareSize + lineGap);
8367   } else {
8368     pt->x = lineGap + column * (squareSize + lineGap);
8369     pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8370   }
8371   *color = SquareColor(row, column);
8372 }
8373
8374 /*      Convert window coords to square                 */
8375
8376 static void
8377 BoardSquare(x, y, column, row)
8378      int x; int y; int * column; int * row;
8379 {
8380   *column = EventToSquare(x, BOARD_WIDTH);
8381   if (flipView && *column >= 0)
8382     *column = BOARD_WIDTH - 1 - *column;
8383   *row = EventToSquare(y, BOARD_HEIGHT);
8384   if (!flipView && *row >= 0)
8385     *row = BOARD_HEIGHT - 1 - *row;
8386 }
8387
8388 /*   Utilities  */
8389
8390 #undef Max  /* just in case */
8391 #undef Min
8392 #define Max(a, b) ((a) > (b) ? (a) : (b))
8393 #define Min(a, b) ((a) < (b) ? (a) : (b))
8394
8395 static void
8396 SetRect(rect, x, y, width, height)
8397      XRectangle * rect; int x; int y; int width; int height;
8398 {
8399   rect->x = x;
8400   rect->y = y;
8401   rect->width  = width;
8402   rect->height = height;
8403 }
8404
8405 /*      Test if two frames overlap. If they do, return
8406         intersection rect within old and location of
8407         that rect within new. */
8408
8409 static Boolean
8410 Intersect(old, new, size, area, pt)
8411      XPoint * old; XPoint * new;
8412      int size; XRectangle * area; XPoint * pt;
8413 {
8414   if (old->x > new->x + size || new->x > old->x + size ||
8415       old->y > new->y + size || new->y > old->y + size) {
8416     return False;
8417   } else {
8418     SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8419             size - abs(old->x - new->x), size - abs(old->y - new->y));
8420     pt->x = Max(old->x - new->x, 0);
8421     pt->y = Max(old->y - new->y, 0);
8422     return True;
8423   }
8424 }
8425
8426 /*      For two overlapping frames, return the rect(s)
8427         in the old that do not intersect with the new.   */
8428
8429 static void
8430 CalcUpdateRects(old, new, size, update, nUpdates)
8431      XPoint * old; XPoint * new; int size;
8432      XRectangle update[]; int * nUpdates;
8433 {
8434   int        count;
8435
8436   /* If old = new (shouldn't happen) then nothing to draw */
8437   if (old->x == new->x && old->y == new->y) {
8438     *nUpdates = 0;
8439     return;
8440   }
8441   /* Work out what bits overlap. Since we know the rects
8442      are the same size we don't need a full intersect calc. */
8443   count = 0;
8444   /* Top or bottom edge? */
8445   if (new->y > old->y) {
8446     SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8447     count ++;
8448   } else if (old->y > new->y) {
8449     SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8450                               size, old->y - new->y);
8451     count ++;
8452   }
8453   /* Left or right edge - don't overlap any update calculated above. */
8454   if (new->x > old->x) {
8455     SetRect(&(update[count]), old->x, Max(new->y, old->y),
8456                               new->x - old->x, size - abs(new->y - old->y));
8457     count ++;
8458   } else if (old->x > new->x) {
8459     SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8460                               old->x - new->x, size - abs(new->y - old->y));
8461     count ++;
8462   }
8463   /* Done */
8464   *nUpdates = count;
8465 }
8466
8467 /*      Generate a series of frame coords from start->mid->finish.
8468         The movement rate doubles until the half way point is
8469         reached, then halves back down to the final destination,
8470         which gives a nice slow in/out effect. The algorithmn
8471         may seem to generate too many intermediates for short
8472         moves, but remember that the purpose is to attract the
8473         viewers attention to the piece about to be moved and
8474         then to where it ends up. Too few frames would be less
8475         noticeable.                                             */
8476
8477 static void
8478 Tween(start, mid, finish, factor, frames, nFrames)
8479      XPoint * start; XPoint * mid;
8480      XPoint * finish; int factor;
8481      XPoint frames[]; int * nFrames;
8482 {
8483   int fraction, n, count;
8484
8485   count = 0;
8486
8487   /* Slow in, stepping 1/16th, then 1/8th, ... */
8488   fraction = 1;
8489   for (n = 0; n < factor; n++)
8490     fraction *= 2;
8491   for (n = 0; n < factor; n++) {
8492     frames[count].x = start->x + (mid->x - start->x) / fraction;
8493     frames[count].y = start->y + (mid->y - start->y) / fraction;
8494     count ++;
8495     fraction = fraction / 2;
8496   }
8497
8498   /* Midpoint */
8499   frames[count] = *mid;
8500   count ++;
8501
8502   /* Slow out, stepping 1/2, then 1/4, ... */
8503   fraction = 2;
8504   for (n = 0; n < factor; n++) {
8505     frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8506     frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8507     count ++;
8508     fraction = fraction * 2;
8509   }
8510   *nFrames = count;
8511 }
8512
8513 /*      Draw a piece on the screen without disturbing what's there      */
8514
8515 static void
8516 SelectGCMask(piece, clip, outline, mask)
8517      ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8518 {
8519   GC source;
8520
8521   /* Bitmap for piece being moved. */
8522   if (appData.monoMode) {
8523       *mask = *pieceToSolid(piece);
8524   } else if (useImages) {
8525 #if HAVE_LIBXPM
8526       *mask = xpmMask[piece];
8527 #else
8528       *mask = ximMaskPm[piece];
8529 #endif
8530   } else {
8531       *mask = *pieceToSolid(piece);
8532   }
8533
8534   /* GC for piece being moved. Square color doesn't matter, but
8535      since it gets modified we make a copy of the original. */
8536   if (White(piece)) {
8537     if (appData.monoMode)
8538       source = bwPieceGC;
8539     else
8540       source = wlPieceGC;
8541   } else {
8542     if (appData.monoMode)
8543       source = wbPieceGC;
8544     else
8545       source = blPieceGC;
8546   }
8547   XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8548
8549   /* Outline only used in mono mode and is not modified */
8550   if (White(piece))
8551     *outline = bwPieceGC;
8552   else
8553     *outline = wbPieceGC;
8554 }
8555
8556 static void
8557 OverlayPiece(piece, clip, outline,  dest)
8558      ChessSquare piece; GC clip; GC outline; Drawable dest;
8559 {
8560   int   kind;
8561
8562   if (!useImages) {
8563     /* Draw solid rectangle which will be clipped to shape of piece */
8564     XFillRectangle(xDisplay, dest, clip,
8565                    0, 0, squareSize, squareSize);
8566     if (appData.monoMode)
8567       /* Also draw outline in contrasting color for black
8568          on black / white on white cases                */
8569       XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8570                  0, 0, squareSize, squareSize, 0, 0, 1);
8571   } else {
8572     /* Copy the piece */
8573     if (White(piece))
8574       kind = 0;
8575     else
8576       kind = 2;
8577     XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8578               dest, clip,
8579               0, 0, squareSize, squareSize,
8580               0, 0);
8581   }
8582 }
8583
8584 /* Animate the movement of a single piece */
8585
8586 static void
8587 BeginAnimation(anim, piece, startColor, start)
8588      AnimState *anim;
8589      ChessSquare piece;
8590      int startColor;
8591      XPoint * start;
8592 {
8593   Pixmap mask;
8594
8595   /* The old buffer is initialised with the start square (empty) */
8596   BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8597   anim->prevFrame = *start;
8598
8599   /* The piece will be drawn using its own bitmap as a matte    */
8600   SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8601   XSetClipMask(xDisplay, anim->pieceGC, mask);
8602 }
8603
8604 static void
8605 AnimationFrame(anim, frame, piece)
8606      AnimState *anim;
8607      XPoint *frame;
8608      ChessSquare piece;
8609 {
8610   XRectangle updates[4];
8611   XRectangle overlap;
8612   XPoint     pt;
8613   int        count, i;
8614
8615   /* Save what we are about to draw into the new buffer */
8616   XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8617             frame->x, frame->y, squareSize, squareSize,
8618             0, 0);
8619
8620   /* Erase bits of the previous frame */
8621   if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8622     /* Where the new frame overlapped the previous,
8623        the contents in newBuf are wrong. */
8624     XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8625               overlap.x, overlap.y,
8626               overlap.width, overlap.height,
8627               pt.x, pt.y);
8628     /* Repaint the areas in the old that don't overlap new */
8629     CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8630     for (i = 0; i < count; i++)
8631       XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8632                 updates[i].x - anim->prevFrame.x,
8633                 updates[i].y - anim->prevFrame.y,
8634                 updates[i].width, updates[i].height,
8635                 updates[i].x, updates[i].y);
8636   } else {
8637     /* Easy when no overlap */
8638     XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8639                   0, 0, squareSize, squareSize,
8640                   anim->prevFrame.x, anim->prevFrame.y);
8641   }
8642
8643   /* Save this frame for next time round */
8644   XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8645                 0, 0, squareSize, squareSize,
8646                 0, 0);
8647   anim->prevFrame = *frame;
8648
8649   /* Draw piece over original screen contents, not current,
8650      and copy entire rect. Wipes out overlapping piece images. */
8651   OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8652   XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8653                 0, 0, squareSize, squareSize,
8654                 frame->x, frame->y);
8655 }
8656
8657 static void
8658 EndAnimation (anim, finish)
8659      AnimState *anim;
8660      XPoint *finish;
8661 {
8662   XRectangle updates[4];
8663   XRectangle overlap;
8664   XPoint     pt;
8665   int        count, i;
8666
8667   /* The main code will redraw the final square, so we
8668      only need to erase the bits that don't overlap.    */
8669   if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8670     CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8671     for (i = 0; i < count; i++)
8672       XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8673                 updates[i].x - anim->prevFrame.x,
8674                 updates[i].y - anim->prevFrame.y,
8675                 updates[i].width, updates[i].height,
8676                 updates[i].x, updates[i].y);
8677   } else {
8678     XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8679                 0, 0, squareSize, squareSize,
8680                 anim->prevFrame.x, anim->prevFrame.y);
8681   }
8682 }
8683
8684 static void
8685 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8686      AnimState *anim;
8687      ChessSquare piece; int startColor;
8688      XPoint * start; XPoint * finish;
8689      XPoint frames[]; int nFrames;
8690 {
8691   int n;
8692
8693   BeginAnimation(anim, piece, startColor, start);
8694   for (n = 0; n < nFrames; n++) {
8695     AnimationFrame(anim, &(frames[n]), piece);
8696     FrameDelay(appData.animSpeed);
8697   }
8698   EndAnimation(anim, finish);
8699 }
8700
8701 /* Main control logic for deciding what to animate and how */
8702
8703 void
8704 AnimateMove(board, fromX, fromY, toX, toY)
8705      Board board;
8706      int fromX;
8707      int fromY;
8708      int toX;
8709      int toY;
8710 {
8711   ChessSquare piece;
8712   int hop;
8713   XPoint      start, finish, mid;
8714   XPoint      frames[kFactor * 2 + 1];
8715   int         nFrames, startColor, endColor;
8716
8717   /* Are we animating? */
8718   if (!appData.animate || appData.blindfold)
8719     return;
8720
8721   if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing || 
8722      board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing) 
8723         return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8724
8725   if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8726   piece = board[fromY][fromX];
8727   if (piece >= EmptySquare) return;
8728
8729 #if DONT_HOP
8730   hop = FALSE;
8731 #else
8732   hop = (piece == WhiteKnight || piece == BlackKnight);
8733 #endif
8734
8735   if (appData.debugMode) {
8736       fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8737                              _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8738              piece, fromX, fromY, toX, toY);  }
8739
8740   ScreenSquare(fromX, fromY, &start, &startColor);
8741   ScreenSquare(toX, toY, &finish, &endColor);
8742
8743   if (hop) {
8744     /* Knight: make diagonal movement then straight */
8745     if (abs(toY - fromY) < abs(toX - fromX)) {
8746        mid.x = start.x + (finish.x - start.x) / 2;
8747        mid.y = finish.y;
8748      } else {
8749        mid.x = finish.x;
8750        mid.y = start.y + (finish.y - start.y) / 2;
8751      }
8752   } else {
8753     mid.x = start.x + (finish.x - start.x) / 2;
8754     mid.y = start.y + (finish.y - start.y) / 2;
8755   }
8756
8757   /* Don't use as many frames for very short moves */
8758   if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8759     Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8760   else
8761     Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8762   FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8763
8764   /* Be sure end square is redrawn */
8765   damage[toY][toX] = True;
8766 }
8767
8768 void
8769 DragPieceBegin(x, y)
8770      int x; int y;
8771 {
8772     int  boardX, boardY, color;
8773     XPoint corner;
8774
8775     /* Are we animating? */
8776     if (!appData.animateDragging || appData.blindfold)
8777       return;
8778
8779     /* Figure out which square we start in and the
8780        mouse position relative to top left corner. */
8781     BoardSquare(x, y, &boardX, &boardY);
8782     player.startBoardX = boardX;
8783     player.startBoardY = boardY;
8784     ScreenSquare(boardX, boardY, &corner, &color);
8785     player.startSquare  = corner;
8786     player.startColor   = color;
8787 #if 0
8788     /* Start from exactly where the piece is.  This can be confusing
8789        if you start dragging far from the center of the square; most
8790        or all of the piece can be over a different square from the one
8791        the mouse pointer is in. */
8792     player.mouseDelta.x = x - corner.x;
8793     player.mouseDelta.y = y - corner.y;
8794 #else
8795     /* As soon as we start dragging, the piece will jump slightly to
8796        be centered over the mouse pointer. */
8797     player.mouseDelta.x = squareSize/2;
8798     player.mouseDelta.y = squareSize/2;
8799 #endif
8800     /* Initialise animation */
8801     player.dragPiece = PieceForSquare(boardX, boardY);
8802     /* Sanity check */
8803     if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8804         player.dragActive = True;
8805         BeginAnimation(&player, player.dragPiece, color, &corner);
8806         /* Mark this square as needing to be redrawn. Note that
8807            we don't remove the piece though, since logically (ie
8808            as seen by opponent) the move hasn't been made yet. */
8809            if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8810               boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8811            XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8812                      corner.x, corner.y, squareSize, squareSize,
8813                      0, 0); // [HGM] zh: unstack in stead of grab
8814         damage[boardY][boardX] = True;
8815     } else {
8816         player.dragActive = False;
8817     }
8818 }
8819
8820 static void
8821 DragPieceMove(x, y)
8822      int x; int y;
8823 {
8824     XPoint corner;
8825
8826     /* Are we animating? */
8827     if (!appData.animateDragging || appData.blindfold)
8828       return;
8829
8830     /* Sanity check */
8831     if (! player.dragActive)
8832       return;
8833     /* Move piece, maintaining same relative position
8834        of mouse within square    */
8835     corner.x = x - player.mouseDelta.x;
8836     corner.y = y - player.mouseDelta.y;
8837     AnimationFrame(&player, &corner, player.dragPiece);
8838 #if HIGHDRAG
8839     if (appData.highlightDragging) {
8840         int boardX, boardY;
8841         BoardSquare(x, y, &boardX, &boardY);
8842         SetHighlights(fromX, fromY, boardX, boardY);
8843     }
8844 #endif
8845 }
8846
8847 void
8848 DragPieceEnd(x, y)
8849      int x; int y;
8850 {
8851     int boardX, boardY, color;
8852     XPoint corner;
8853
8854     /* Are we animating? */
8855     if (!appData.animateDragging || appData.blindfold)
8856       return;
8857
8858     /* Sanity check */
8859     if (! player.dragActive)
8860       return;
8861     /* Last frame in sequence is square piece is
8862        placed on, which may not match mouse exactly. */
8863     BoardSquare(x, y, &boardX, &boardY);
8864     ScreenSquare(boardX, boardY, &corner, &color);
8865     EndAnimation(&player, &corner);
8866
8867     /* Be sure end square is redrawn */
8868     damage[boardY][boardX] = True;
8869
8870     /* This prevents weird things happening with fast successive
8871        clicks which on my Sun at least can cause motion events
8872        without corresponding press/release. */
8873     player.dragActive = False;
8874 }
8875
8876 /* Handle expose event while piece being dragged */
8877
8878 static void
8879 DrawDragPiece ()
8880 {
8881   if (!player.dragActive || appData.blindfold)
8882     return;
8883
8884   /* What we're doing: logically, the move hasn't been made yet,
8885      so the piece is still in it's original square. But visually
8886      it's being dragged around the board. So we erase the square
8887      that the piece is on and draw it at the last known drag point. */
8888   BlankSquare(player.startSquare.x, player.startSquare.y,
8889                 player.startColor, EmptySquare, xBoardWindow);
8890   AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8891   damage[player.startBoardY][player.startBoardX] = TRUE;
8892 }
8893
8894 void
8895 SetProgramStats( FrontEndProgramStats * stats )
8896 {
8897   // [HR] TODO
8898   // [HGM] done, but perhaps backend should call this directly?
8899     EngineOutputUpdate( stats );
8900 }