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