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