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