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