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