These are the changes I had made in my source tree between 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 #ifdef __EMX__
196 #ifndef HAVE_USLEEP
197 #define HAVE_USLEEP
198 #endif
199 #define usleep(t)   _sleep2(((t)+500)/1000)
200 #endif
201
202 typedef struct {
203     String string;
204     XtActionProc proc;
205 } MenuItem;
206
207 typedef struct {
208     String name;
209     MenuItem *mi;
210 } Menu;
211
212 int main P((int argc, char **argv));
213 RETSIGTYPE CmailSigHandler P((int sig));
214 RETSIGTYPE IntSigHandler P((int sig));
215 void CreateGCs P((void));
216 void CreateXIMPieces P((void));
217 void CreateXPMPieces P((void));
218 void CreatePieces P((void));
219 void CreatePieceMenus P((void));
220 Widget CreateMenuBar P((Menu *mb));
221 Widget CreateButtonBar P ((MenuItem *mi));
222 char *FindFont P((char *pattern, int targetPxlSize));
223 void PieceMenuPopup P((Widget w, XEvent *event,
224                        String *params, Cardinal *num_params));
225 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
226 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
227 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
228                    u_int wreq, u_int hreq));
229 void CreateGrid P((void));
230 int EventToSquare P((int x, int limit));
231 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
232 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
233 void HandleUserMove P((Widget w, XEvent *event,
234                      String *prms, Cardinal *nprms));
235 void AnimateUserMove P((Widget w, XEvent * event,
236                      String * params, Cardinal * nParams));
237 void WhiteClock P((Widget w, XEvent *event,
238                    String *prms, Cardinal *nprms));
239 void BlackClock P((Widget w, XEvent *event,
240                    String *prms, Cardinal *nprms));
241 void DrawPositionProc P((Widget w, XEvent *event,
242                      String *prms, Cardinal *nprms));
243 void XDrawPosition P((Widget w, /*Boolean*/int repaint, 
244                      Board board));
245 void CommentPopUp P((char *title, char *label));
246 void CommentPopDown P((void));
247 void CommentCallback P((Widget w, XtPointer client_data,
248                         XtPointer call_data));
249 void ICSInputBoxPopUp P((void));
250 void ICSInputBoxPopDown P((void));
251 void FileNamePopUp P((char *label, char *def,
252                       FileProc proc, char *openMode));
253 void FileNamePopDown P((void));
254 void FileNameCallback P((Widget w, XtPointer client_data,
255                          XtPointer call_data));
256 void FileNameAction P((Widget w, XEvent *event,
257                        String *prms, Cardinal *nprms));
258 void AskQuestionReplyAction P((Widget w, XEvent *event,
259                           String *prms, Cardinal *nprms));
260 void AskQuestionProc P((Widget w, XEvent *event,
261                           String *prms, Cardinal *nprms));
262 void AskQuestionPopDown P((void));
263 void PromotionPopUp P((void));
264 void PromotionPopDown P((void));
265 void PromotionCallback P((Widget w, XtPointer client_data,
266                           XtPointer call_data));
267 void EditCommentPopDown P((void));
268 void EditCommentCallback P((Widget w, XtPointer client_data,
269                             XtPointer call_data));
270 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
271 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
272 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
273 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
274                          Cardinal *nprms));
275 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
276                          Cardinal *nprms));
277 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
278                        Cardinal *nprms));
279 void LoadPositionProc P((Widget w, XEvent *event,
280                          String *prms, Cardinal *nprms));
281 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
282                          Cardinal *nprms));
283 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
284                          Cardinal *nprms));
285 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
286                        Cardinal *nprms));
287 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
288                          Cardinal *nprms));
289 void PastePositionProc P((Widget w, XEvent *event, String *prms,
290                           Cardinal *nprms));
291 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
292 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
293 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
294 void SavePositionProc P((Widget w, XEvent *event,
295                          String *prms, Cardinal *nprms));
296 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
297 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
298                             Cardinal *nprms));
299 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
300 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
301 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
302                          Cardinal *nprms));
303 void MachineWhiteProc P((Widget w, XEvent *event,
304                          String *prms, Cardinal *nprms));
305 void AnalyzeModeProc P((Widget w, XEvent *event,
306                          String *prms, Cardinal *nprms));
307 void AnalyzeFileProc P((Widget w, XEvent *event,
308                          String *prms, Cardinal *nprms));
309 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
310                         Cardinal *nprms));
311 void IcsClientProc P((Widget w, XEvent *event, String *prms,
312                       Cardinal *nprms));
313 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
314 void EditPositionProc P((Widget w, XEvent *event,
315                          String *prms, Cardinal *nprms));
316 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
317 void EditCommentProc P((Widget w, XEvent *event,
318                         String *prms, Cardinal *nprms));
319 void IcsInputBoxProc P((Widget w, XEvent *event,
320                         String *prms, Cardinal *nprms));
321 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
322 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
323 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
324 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
325 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
326 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
327 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
328 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
329 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
330 void StopObservingProc P((Widget w, XEvent *event, String *prms,
331                           Cardinal *nprms));
332 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
333                           Cardinal *nprms));
334 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
335 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
336 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
337 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
338 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
339 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
340                          Cardinal *nprms));
341 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
342                         Cardinal *nprms));
343 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
344 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
345                         Cardinal *nprms));
346 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
347                          Cardinal *nprms));
348 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
349                          Cardinal *nprms));
350 void AutocommProc P((Widget w, XEvent *event, String *prms,
351                      Cardinal *nprms));
352 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
353 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
354 void AutobsProc P((Widget w, XEvent *event, String *prms,
355                         Cardinal *nprms));
356 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
357 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
358 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
359 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
360                        Cardinal *nprms));
361 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
363                         Cardinal *nprms));
364 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
365                               Cardinal *nprms));
366 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
367                               Cardinal *nprms));
368 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
369 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
370 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
371                          Cardinal *nprms));
372 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
373                          Cardinal *nprms));
374 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
375                            Cardinal *nprms));
376 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
377                         Cardinal *nprms));
378 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
379                              Cardinal *nprms));
380 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
383                        Cardinal *nprms));
384 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
385                          Cardinal *nprms));
386 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
387                           Cardinal *nprms));
388 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
389 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
390 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
391 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
392 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
393 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
394 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
395 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
396 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
397 void DisplayMove P((int moveNumber));
398 void DisplayTitle P((char *title));
399 void ICSInitScript P((void));
400 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
401 void ErrorPopUp P((char *title, char *text, int modal));
402 void ErrorPopDown P((void));
403 static char *ExpandPathName P((char *path));
404 static void CreateAnimVars P((void));
405 static void DragPieceBegin P((int x, int y));
406 static void DragPieceMove P((int x, int y));
407 static void DragPieceEnd P((int x, int y));
408 static void DrawDragPiece P((void));
409 char *ModeToWidgetName P((GameMode mode));
410
411 /*
412 * XBoard depends on Xt R4 or higher
413 */
414 int xtVersion = XtSpecificationRelease;
415
416 int xScreen;
417 Display *xDisplay;
418 Window xBoardWindow;
419 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
420   jailSquareColor, highlightSquareColor, premoveHighlightColor;
421 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
422   bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
423   wjPieceGC, bjPieceGC, prelineGC;
424 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
425 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget, 
426   whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16], 
427   commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
428   menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
429   ICSInputShell, fileNameShell, askQuestionShell;
430 XSegment gridSegments[(BOARD_SIZE + 1) * 2];
431 XSegment jailGridSegments[(BOARD_SIZE + 3) * 2];
432 Font clockFontID, coordFontID;
433 XFontStruct *clockFontStruct, *coordFontStruct;
434 XtAppContext appContext;
435 char *layoutName;
436 char *oldICSInteractionTitle;
437
438 FileProc fileProc;
439 char *fileOpenMode;
440
441 Position commentX = -1, commentY = -1;
442 Dimension commentW, commentH;
443
444 int squareSize, smallLayout = 0, tinyLayout = 0,
445   fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
446   ICSInputBoxUp = False, askQuestionUp = False,
447   filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
448   editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
449 Pixel timerForegroundPixel, timerBackgroundPixel;
450 Pixel buttonForegroundPixel, buttonBackgroundPixel;
451 char *chessDir, *programName, *programVersion,
452   *gameCopyFilename, *gamePasteFilename;
453
454 #define SOLID 0
455 #define OUTLINE 1
456 Pixmap pieceBitmap[2][6];
457 Pixmap xpmPieceBitmap[4][6];    /* LL, LD, DL, DD */
458 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
459 int useImages, useImageSqs;
460 XImage *ximPieceBitmap[4][6];   /* LL, LD, DL, DD */
461 Pixmap ximMaskPm[6];            /* clipmasks, used for XIM pieces */
462 XImage *ximLightSquare, *ximDarkSquare;
463 XImage *xim_Cross;
464
465 #define pieceToSolid(piece) &pieceBitmap[SOLID][((int)(piece)) % 6]
466 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][((int)(piece)) % 6]
467
468 #define White(piece) ((int)(piece) < (int)BlackPawn)
469
470 /* Variables for doing smooth animation. This whole thing
471    would be much easier if the board was double-buffered,
472    but that would require a fairly major rewrite.       */
473
474 typedef struct {
475         Pixmap  saveBuf;
476         Pixmap  newBuf;
477         GC      blitGC, pieceGC, outlineGC;
478         XPoint  startSquare, prevFrame, mouseDelta;
479         int     startColor;
480         int     dragPiece;
481         Boolean dragActive;
482         int     startBoardX, startBoardY;
483     } AnimState;
484
485 /* There can be two pieces being animated at once: a player
486    can begin dragging a piece before the remote opponent has moved. */
487
488 static AnimState game, player;
489
490 /* Bitmaps for use as masks when drawing XPM pieces.
491    Need one for each black and white piece.             */
492 static Pixmap xpmMask[BlackKing + 1];
493
494 /* This magic number is the number of intermediate frames used
495    in each half of the animation. For short moves it's reduced
496    by 1. The total number of frames will be factor * 2 + 1.  */
497 #define kFactor    4
498
499 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
500
501 MenuItem fileMenu[] = {
502     {"Reset Game", ResetProc},
503     {"----", NothingProc},
504     {"Load Game", LoadGameProc},
505     {"Load Next Game", LoadNextGameProc},
506     {"Load Previous Game", LoadPrevGameProc},
507     {"Reload Same Game", ReloadGameProc},
508     {"Save Game", SaveGameProc},
509     {"----", NothingProc},
510     {"Copy Game", CopyGameProc},
511     {"Paste Game", PasteGameProc},
512     {"----", NothingProc},
513     {"Load Position", LoadPositionProc},
514     {"Load Next Position", LoadNextPositionProc},
515     {"Load Previous Position", LoadPrevPositionProc},
516     {"Reload Same Position", ReloadPositionProc},
517     {"Save Position", SavePositionProc},
518     {"----", NothingProc},
519     {"Copy Position", CopyPositionProc},
520     {"Paste Position", PastePositionProc},
521     {"----", NothingProc},
522     {"Mail Move", MailMoveProc},
523     {"Reload CMail Message", ReloadCmailMsgProc},
524     {"----", NothingProc},
525     {"Exit", QuitProc},
526     {NULL, NULL}
527 };
528
529 MenuItem modeMenu[] = {
530     {"Machine White", MachineWhiteProc},
531     {"Machine Black", MachineBlackProc},
532     {"Two Machines", TwoMachinesProc},
533     {"Analysis Mode", AnalyzeModeProc},
534     {"Analyze File", AnalyzeFileProc },
535     {"ICS Client", IcsClientProc},
536     {"Edit Game", EditGameProc},
537     {"Edit Position", EditPositionProc},
538     {"Training", TrainingProc},
539     {"----", NothingProc},
540     {"Show Game List", ShowGameListProc},
541     {"Show Move List", HistoryShowProc},
542     {"Edit Tags", EditTagsProc},
543     {"Edit Comment", EditCommentProc},
544     {"ICS Input Box", IcsInputBoxProc},
545     {"Pause", PauseProc},
546     {NULL, NULL}
547 };
548
549 MenuItem actionMenu[] = {
550     {"Accept", AcceptProc},
551     {"Decline", DeclineProc},
552     {"Rematch", RematchProc},
553     {"----", NothingProc},    
554     {"Call Flag", CallFlagProc},
555     {"Draw", DrawProc},
556     {"Adjourn", AdjournProc},
557     {"Abort", AbortProc},
558     {"Resign", ResignProc},
559     {"----", NothingProc},    
560     {"Stop Observing", StopObservingProc},
561     {"Stop Examining", StopExaminingProc},
562     {NULL, NULL}
563 };
564
565 MenuItem stepMenu[] = {
566     {"Backward", BackwardProc},
567     {"Forward", ForwardProc},
568     {"Back to Start", ToStartProc},
569     {"Forward to End", ToEndProc},
570     {"Revert", RevertProc},
571     {"Truncate Game", TruncateGameProc},
572     {"----", NothingProc},    
573     {"Move Now", MoveNowProc},
574     {"Retract Move", RetractMoveProc},
575     {NULL, NULL}
576 };    
577
578 MenuItem optionsMenu[] = {
579     {"Always Queen", AlwaysQueenProc},
580     {"Animate Dragging", AnimateDraggingProc},
581     {"Animate Moving", AnimateMovingProc},
582     {"Auto Comment", AutocommProc},
583     {"Auto Flag", AutoflagProc},
584     {"Auto Flip View", AutoflipProc},
585     {"Auto Observe", AutobsProc},
586     {"Auto Raise Board", AutoraiseProc},
587     {"Auto Save", AutosaveProc},
588     {"Blindfold", BlindfoldProc},
589     {"Flash Moves", FlashMovesProc},
590     {"Flip View", FlipViewProc},
591     {"Get Move List", GetMoveListProc},
592 #if HIGHDRAG
593     {"Highlight Dragging", HighlightDraggingProc},
594 #endif
595     {"Highlight Last Move", HighlightLastMoveProc},
596     {"Move Sound", MoveSoundProc},
597     {"ICS Alarm", IcsAlarmProc},
598     {"Old Save Style", OldSaveStyleProc},
599     {"Periodic Updates", PeriodicUpdatesProc},  
600     {"Ponder Next Move", PonderNextMoveProc},
601     {"Popup Exit Message", PopupExitMessageProc},       
602     {"Popup Move Errors", PopupMoveErrorsProc}, 
603     {"Premove", PremoveProc},
604     {"Quiet Play", QuietPlayProc},
605     {"Show Coords", ShowCoordsProc},
606     {"Show Thinking", ShowThinkingProc},
607     {"Test Legality", TestLegalityProc},
608     {NULL, NULL}
609 };
610
611 MenuItem helpMenu[] = {
612     {"Info XBoard", InfoProc},
613     {"Man XBoard", ManProc},
614     {"----", NothingProc},
615     {"Hint", HintProc},
616     {"Book", BookProc},
617     {"----", NothingProc},
618     {"About XBoard", AboutProc},
619     {NULL, NULL}
620 };
621
622 Menu menuBar[] = {
623     {"File", fileMenu},
624     {"Mode", modeMenu},
625     {"Action", actionMenu},
626     {"Step", stepMenu},
627     {"Options", optionsMenu},
628     {"Help", helpMenu},
629     {NULL, NULL}
630 };
631
632 #define PAUSE_BUTTON "P"
633 MenuItem buttonBar[] = {
634     {"<<", ToStartProc},
635     {"<", BackwardProc},
636     {PAUSE_BUTTON, PauseProc},
637     {">", ForwardProc},
638     {">>", ToEndProc},
639     {NULL, NULL}
640 };
641
642 #define PIECE_MENU_SIZE 11
643 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
644     { "White", "----", "Pawn", "Knight", "Bishop", "Rook", "Queen", "King",
645       "----", "Empty square", "Clear board" },
646     { "Black", "----", "Pawn", "Knight", "Bishop", "Rook", "Queen", "King",
647       "----", "Empty square", "Clear board" },
648   };
649 /* must be in same order as PieceMenuStrings! */
650 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
651     { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
652         WhiteRook, WhiteQueen, WhiteKing,
653         (ChessSquare) 0, EmptySquare, ClearBoard },
654     { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
655         BlackRook, BlackQueen, BlackKing,
656         (ChessSquare) 0, EmptySquare, ClearBoard },
657 };
658
659 #define DROP_MENU_SIZE 6
660 String dropMenuStrings[DROP_MENU_SIZE] = {
661     "----", "Pawn", "Knight", "Bishop", "Rook", "Queen"
662   };
663 /* must be in same order as PieceMenuStrings! */
664 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
665     (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
666     WhiteRook, WhiteQueen
667 };
668
669 typedef struct {
670     char piece;
671     char* widget;
672 } DropMenuEnables;
673
674 DropMenuEnables dmEnables[] = {
675     { 'P', "Pawn" },
676     { 'N', "Knight" },
677     { 'B', "Bishop" },
678     { 'R', "Rook" },
679     { 'Q', "Queen" }
680 };
681
682 Arg shellArgs[] = {
683     { XtNwidth, 0 },
684     { XtNheight, 0 },
685     { XtNminWidth, 0 },
686     { XtNminHeight, 0 },
687     { XtNmaxWidth, 0 },
688     { XtNmaxHeight, 0 }
689 };
690
691 Arg layoutArgs[] = {
692     { XtNborderWidth, 0 },
693     { XtNdefaultDistance, 0 },
694 };
695
696 Arg formArgs[] = {
697     { XtNborderWidth, 0 },
698     { XtNresizable, (XtArgVal) True },
699 };
700
701 Arg boardArgs[] = {
702     { XtNborderWidth, 0 },
703     { XtNwidth, 0 },
704     { XtNheight, 0 }
705 };
706
707 Arg titleArgs[] = {
708     { XtNjustify, (XtArgVal) XtJustifyRight },
709     { XtNlabel, (XtArgVal) "..." },
710     { XtNresizable, (XtArgVal) True },
711     { XtNresize, (XtArgVal) False }
712 };
713
714 Arg messageArgs[] = {
715     { XtNjustify, (XtArgVal) XtJustifyLeft },
716     { XtNlabel, (XtArgVal) "..." },
717     { XtNresizable, (XtArgVal) True },
718     { XtNresize, (XtArgVal) False }
719 };
720
721 Arg timerArgs[] = {
722     { XtNborderWidth, 0 },
723     { XtNjustify, (XtArgVal) XtJustifyLeft }
724 };
725
726 XtResource clientResources[] = {
727     { "whitePieceColor", "whitePieceColor", XtRString, sizeof(String),
728         XtOffset(AppDataPtr, whitePieceColor), XtRString,
729         WHITE_PIECE_COLOR },
730     { "blackPieceColor", "blackPieceColor", XtRString, sizeof(String),
731         XtOffset(AppDataPtr, blackPieceColor), XtRString,
732         BLACK_PIECE_COLOR },
733     { "lightSquareColor", "lightSquareColor", XtRString,
734         sizeof(String), XtOffset(AppDataPtr, lightSquareColor),
735         XtRString, LIGHT_SQUARE_COLOR }, 
736     { "darkSquareColor", "darkSquareColor", XtRString, sizeof(String),
737         XtOffset(AppDataPtr, darkSquareColor), XtRString,
738         DARK_SQUARE_COLOR },
739     { "highlightSquareColor", "highlightSquareColor", XtRString,
740         sizeof(String), XtOffset(AppDataPtr, highlightSquareColor),
741         XtRString, HIGHLIGHT_SQUARE_COLOR },
742     { "premoveHighlightColor", "premoveHighlightColor", XtRString,
743         sizeof(String), XtOffset(AppDataPtr, premoveHighlightColor),
744         XtRString, PREMOVE_HIGHLIGHT_COLOR },
745     { "movesPerSession", "movesPerSession", XtRInt, sizeof(int),
746         XtOffset(AppDataPtr, movesPerSession), XtRImmediate,
747         (XtPointer) MOVES_PER_SESSION },
748     { "timeIncrement", "timeIncrement", XtRInt, sizeof(int),
749         XtOffset(AppDataPtr, timeIncrement), XtRImmediate,
750         (XtPointer) TIME_INCREMENT },
751     { "initString", "initString", XtRString, sizeof(String),
752         XtOffset(AppDataPtr, initString), XtRString, INIT_STRING },
753     { "secondInitString", "secondInitString", XtRString, sizeof(String),
754         XtOffset(AppDataPtr, secondInitString), XtRString, INIT_STRING },
755     { "firstComputerString", "firstComputerString", XtRString,
756         sizeof(String), XtOffset(AppDataPtr, firstComputerString), XtRString,
757       COMPUTER_STRING },
758     { "secondComputerString", "secondComputerString", XtRString,
759         sizeof(String), XtOffset(AppDataPtr, secondComputerString), XtRString,
760       COMPUTER_STRING },
761     { "firstChessProgram", "firstChessProgram", XtRString,
762         sizeof(String), XtOffset(AppDataPtr, firstChessProgram),
763         XtRString, FIRST_CHESS_PROGRAM },
764     { "secondChessProgram", "secondChessProgram", XtRString,
765         sizeof(String), XtOffset(AppDataPtr, secondChessProgram),
766         XtRString, SECOND_CHESS_PROGRAM },
767     { "firstPlaysBlack", "firstPlaysBlack", XtRBoolean,
768         sizeof(Boolean), XtOffset(AppDataPtr, firstPlaysBlack),
769         XtRImmediate, (XtPointer) False },
770     { "noChessProgram", "noChessProgram", XtRBoolean,
771         sizeof(Boolean), XtOffset(AppDataPtr, noChessProgram),
772         XtRImmediate, (XtPointer) False },
773     { "firstHost", "firstHost", XtRString, sizeof(String),
774         XtOffset(AppDataPtr, firstHost), XtRString, FIRST_HOST },
775     { "secondHost", "secondHost", XtRString, sizeof(String),
776         XtOffset(AppDataPtr, secondHost), XtRString, SECOND_HOST },
777     { "firstDirectory", "firstDirectory", XtRString, sizeof(String),
778         XtOffset(AppDataPtr, firstDirectory), XtRString, "" },
779     { "secondDirectory", "secondDirectory", XtRString, sizeof(String),
780         XtOffset(AppDataPtr, secondDirectory), XtRString, "" },
781     { "bitmapDirectory", "bitmapDirectory", XtRString,
782         sizeof(String), XtOffset(AppDataPtr, bitmapDirectory),
783         XtRString, "" },
784     { "remoteShell", "remoteShell", XtRString, sizeof(String),
785         XtOffset(AppDataPtr, remoteShell), XtRString, REMOTE_SHELL },
786     { "remoteUser", "remoteUser", XtRString, sizeof(String),
787         XtOffset(AppDataPtr, remoteUser), XtRString, "" },
788     { "timeDelay", "timeDelay", XtRFloat, sizeof(float),
789         XtOffset(AppDataPtr, timeDelay), XtRString,
790         (XtPointer) TIME_DELAY_QUOTE },
791     { "timeControl", "timeControl", XtRString, sizeof(String),
792         XtOffset(AppDataPtr, timeControl), XtRString,
793         (XtPointer) TIME_CONTROL },
794     { "internetChessServerMode", "internetChessServerMode",
795         XtRBoolean, sizeof(Boolean),
796         XtOffset(AppDataPtr, icsActive), XtRImmediate,
797         (XtPointer) False },
798     { "internetChessServerHost", "internetChessServerHost",
799         XtRString, sizeof(String),
800         XtOffset(AppDataPtr, icsHost),
801         XtRString, (XtPointer) ICS_HOST },
802     { "internetChessServerPort", "internetChessServerPort",
803         XtRString, sizeof(String),
804         XtOffset(AppDataPtr, icsPort), XtRString,
805         (XtPointer) ICS_PORT },
806     { "internetChessServerCommPort", "internetChessServerCommPort",
807         XtRString, sizeof(String),
808         XtOffset(AppDataPtr, icsCommPort), XtRString,
809         ICS_COMM_PORT },
810     { "internetChessServerLogonScript", "internetChessServerLogonScript",
811         XtRString, sizeof(String),
812         XtOffset(AppDataPtr, icsLogon), XtRString,
813         ICS_LOGON },
814     { "internetChessServerHelper", "internetChessServerHelper",
815         XtRString, sizeof(String),
816         XtOffset(AppDataPtr, icsHelper), XtRString, "" },
817     { "internetChessServerInputBox", "internetChessServerInputBox",
818         XtRBoolean, sizeof(Boolean),
819         XtOffset(AppDataPtr, icsInputBox), XtRImmediate,
820         (XtPointer) False },
821     { "icsAlarm", "icsAlarm",
822         XtRBoolean, sizeof(Boolean),
823         XtOffset(AppDataPtr, icsAlarm), XtRImmediate,
824         (XtPointer) True },
825     { "icsAlarmTime", "icsAlarmTime",
826         XtRInt, sizeof(int),
827         XtOffset(AppDataPtr, icsAlarmTime), XtRImmediate,
828         (XtPointer) 5000 },
829     { "useTelnet", "useTelnet", XtRBoolean, sizeof(Boolean),
830         XtOffset(AppDataPtr, useTelnet), XtRImmediate,
831         (XtPointer) False },
832     { "telnetProgram", "telnetProgram", XtRString, sizeof(String),
833         XtOffset(AppDataPtr, telnetProgram), XtRString, TELNET_PROGRAM },
834     { "gateway", "gateway", XtRString, sizeof(String),
835         XtOffset(AppDataPtr, gateway), XtRString, "" },
836     { "loadGameFile", "loadGameFile", XtRString, sizeof(String),
837         XtOffset(AppDataPtr, loadGameFile), XtRString, "" },
838     { "loadGameIndex", "loadGameIndex",
839         XtRInt, sizeof(int),
840         XtOffset(AppDataPtr, loadGameIndex), XtRImmediate,
841         (XtPointer) 0 },
842     { "saveGameFile", "saveGameFile", XtRString, sizeof(String),
843         XtOffset(AppDataPtr, saveGameFile), XtRString, "" },
844     { "autoRaiseBoard", "autoRaiseBoard", XtRBoolean,
845         sizeof(Boolean), XtOffset(AppDataPtr, autoRaiseBoard),
846         XtRImmediate, (XtPointer) True },
847     { "autoSaveGames", "autoSaveGames", XtRBoolean,
848         sizeof(Boolean), XtOffset(AppDataPtr, autoSaveGames),
849         XtRImmediate, (XtPointer) False },
850     { "blindfold", "blindfold", XtRBoolean,
851         sizeof(Boolean), XtOffset(AppDataPtr, blindfold),
852         XtRImmediate, (XtPointer) False },
853     { "loadPositionFile", "loadPositionFile", XtRString,
854         sizeof(String), XtOffset(AppDataPtr, loadPositionFile),
855         XtRString, "" },
856     { "loadPositionIndex", "loadPositionIndex",
857         XtRInt, sizeof(int),
858         XtOffset(AppDataPtr, loadPositionIndex), XtRImmediate,
859         (XtPointer) 1 },
860     { "savePositionFile", "savePositionFile", XtRString,
861         sizeof(String), XtOffset(AppDataPtr, savePositionFile),
862         XtRString, "" },
863     { "matchMode", "matchMode", XtRBoolean, sizeof(Boolean),
864         XtOffset(AppDataPtr, matchMode), XtRImmediate, (XtPointer) False },
865     { "matchGames", "matchGames", XtRInt, sizeof(int),
866         XtOffset(AppDataPtr, matchGames), XtRImmediate,
867         (XtPointer) 0 },
868     { "monoMode", "monoMode", XtRBoolean, sizeof(Boolean),
869         XtOffset(AppDataPtr, monoMode), XtRImmediate,
870         (XtPointer) False },
871     { "debugMode", "debugMode", XtRBoolean, sizeof(Boolean),
872         XtOffset(AppDataPtr, debugMode), XtRImmediate,
873         (XtPointer) False },
874     { "clockMode", "clockMode", XtRBoolean, sizeof(Boolean),
875         XtOffset(AppDataPtr, clockMode), XtRImmediate,
876         (XtPointer) True },
877     { "boardSize", "boardSize", XtRString, sizeof(String),
878         XtOffset(AppDataPtr, boardSize), XtRString, "" },
879     { "searchTime", "searchTime", XtRString, sizeof(String),
880         XtOffset(AppDataPtr, searchTime), XtRString,
881         (XtPointer) "" },
882     { "searchDepth", "searchDepth", XtRInt, sizeof(int),
883         XtOffset(AppDataPtr, searchDepth), XtRImmediate, 
884         (XtPointer) 0 },
885     { "showCoords", "showCoords", XtRBoolean, sizeof(Boolean),
886         XtOffset(AppDataPtr, showCoords), XtRImmediate,
887         (XtPointer) False },
888     { "showJail", "showJail", XtRInt, sizeof(int),
889         XtOffset(AppDataPtr, showJail), XtRImmediate,
890         (XtPointer) 0 },
891     { "showThinking", "showThinking", XtRBoolean, sizeof(Boolean),
892         XtOffset(AppDataPtr, showThinking), XtRImmediate,
893         (XtPointer) False },
894     { "ponderNextMove", "ponderNextMove", XtRBoolean, sizeof(Boolean),
895         XtOffset(AppDataPtr, ponderNextMove), XtRImmediate,
896         (XtPointer) True },
897     { "periodicUpdates", "periodicUpdates", XtRBoolean, sizeof(Boolean),
898         XtOffset(AppDataPtr, periodicUpdates), XtRImmediate,
899         (XtPointer) True },
900     { "clockFont", "clockFont", XtRString, sizeof(String),
901         XtOffset(AppDataPtr, clockFont), XtRString, CLOCK_FONT },
902     { "coordFont", "coordFont", XtRString, sizeof(String),
903         XtOffset(AppDataPtr, coordFont), XtRString, COORD_FONT },
904     { "font", "font", XtRString, sizeof(String),
905         XtOffset(AppDataPtr, font), XtRString, DEFAULT_FONT },
906     { "ringBellAfterMoves", "ringBellAfterMoves",
907         XtRBoolean, sizeof(Boolean),
908         XtOffset(AppDataPtr, ringBellAfterMoves),
909         XtRImmediate, (XtPointer) False },
910     { "autoCallFlag", "autoCallFlag", XtRBoolean,
911         sizeof(Boolean), XtOffset(AppDataPtr, autoCallFlag),
912         XtRImmediate, (XtPointer) False },
913     { "autoFlipView", "autoFlipView", XtRBoolean,
914         sizeof(Boolean), XtOffset(AppDataPtr, autoFlipView),
915         XtRImmediate, (XtPointer) True },
916     { "autoObserve", "autoObserve", XtRBoolean,
917         sizeof(Boolean), XtOffset(AppDataPtr, autoObserve),
918         XtRImmediate, (XtPointer) False },
919     { "autoComment", "autoComment", XtRBoolean,
920         sizeof(Boolean), XtOffset(AppDataPtr, autoComment),
921         XtRImmediate, (XtPointer) False },
922     { "getMoveList", "getMoveList", XtRBoolean,
923         sizeof(Boolean), XtOffset(AppDataPtr, getMoveList),
924         XtRImmediate, (XtPointer) True },
925 #if HIGHDRAG
926     { "highlightDragging", "highlightDragging", XtRBoolean,
927         sizeof(Boolean), XtOffset(AppDataPtr, highlightDragging),
928         XtRImmediate, (XtPointer) False },
929 #endif
930     { "highlightLastMove", "highlightLastMove", XtRBoolean,
931         sizeof(Boolean), XtOffset(AppDataPtr, highlightLastMove),
932         XtRImmediate, (XtPointer) False },
933     { "premove", "premove", XtRBoolean,
934         sizeof(Boolean), XtOffset(AppDataPtr, premove),
935         XtRImmediate, (XtPointer) True },
936     { "testLegality", "testLegality", XtRBoolean,
937         sizeof(Boolean), XtOffset(AppDataPtr, testLegality),
938         XtRImmediate, (XtPointer) True },
939     { "flipView", "flipView", XtRBoolean,
940         sizeof(Boolean), XtOffset(AppDataPtr, flipView),
941         XtRImmediate, (XtPointer) False },
942     { "cmail", "cmailGameName", XtRString, sizeof(String),
943         XtOffset(AppDataPtr, cmailGameName), XtRString, "" },
944     { "alwaysPromoteToQueen", "alwaysPromoteToQueen", XtRBoolean,
945         sizeof(Boolean), XtOffset(AppDataPtr, alwaysPromoteToQueen),
946         XtRImmediate, (XtPointer) False },
947     { "oldSaveStyle", "oldSaveStyle", XtRBoolean,
948         sizeof(Boolean), XtOffset(AppDataPtr, oldSaveStyle),
949         XtRImmediate, (XtPointer) False },
950     { "quietPlay", "quietPlay", XtRBoolean,
951         sizeof(Boolean), XtOffset(AppDataPtr, quietPlay),
952         XtRImmediate, (XtPointer) False },
953     { "titleInWindow", "titleInWindow", XtRBoolean,
954         sizeof(Boolean), XtOffset(AppDataPtr, titleInWindow),
955         XtRImmediate, (XtPointer) False },
956     { "localLineEditing", "localLineEditing", XtRBoolean,
957         sizeof(Boolean), XtOffset(AppDataPtr, localLineEditing),
958         XtRImmediate, (XtPointer) True }, /* not implemented, must be True */
959 #ifdef ZIPPY
960     { "zippyTalk", "zippyTalk", XtRBoolean,
961         sizeof(Boolean), XtOffset(AppDataPtr, zippyTalk),
962         XtRImmediate, (XtPointer) ZIPPY_TALK },
963     { "zippyPlay", "zippyPlay", XtRBoolean,
964         sizeof(Boolean), XtOffset(AppDataPtr, zippyPlay),
965         XtRImmediate, (XtPointer) ZIPPY_PLAY },
966     { "zippyLines", "zippyLines", XtRString, sizeof(String),
967         XtOffset(AppDataPtr, zippyLines), XtRString, ZIPPY_LINES },
968     { "zippyPinhead", "zippyPinhead", XtRString, sizeof(String),
969         XtOffset(AppDataPtr, zippyPinhead), XtRString, ZIPPY_PINHEAD },
970     { "zippyPassword", "zippyPassword", XtRString, sizeof(String),
971         XtOffset(AppDataPtr, zippyPassword), XtRString, ZIPPY_PASSWORD },
972     { "zippyPassword2", "zippyPassword2", XtRString, sizeof(String),
973         XtOffset(AppDataPtr, zippyPassword2), XtRString, ZIPPY_PASSWORD2 },
974     { "zippyWrongPassword", "zippyWrongPassword", XtRString, sizeof(String),
975         XtOffset(AppDataPtr, zippyWrongPassword), XtRString,
976         ZIPPY_WRONG_PASSWORD },
977     { "zippyAcceptOnly", "zippyAcceptOnly", XtRString, sizeof(String),
978         XtOffset(AppDataPtr, zippyAcceptOnly), XtRString, ZIPPY_ACCEPT_ONLY },
979     { "zippyUseI", "zippyUseI", XtRBoolean,
980         sizeof(Boolean), XtOffset(AppDataPtr, zippyUseI),
981         XtRImmediate, (XtPointer) ZIPPY_USE_I },
982     { "zippyBughouse", "zippyBughouse", XtRInt,
983         sizeof(int), XtOffset(AppDataPtr, zippyBughouse),
984         XtRImmediate, (XtPointer) ZIPPY_BUGHOUSE },
985     { "zippyNoplayCrafty", "zippyNoplayCrafty", XtRBoolean,
986         sizeof(Boolean), XtOffset(AppDataPtr, zippyNoplayCrafty),
987         XtRImmediate, (XtPointer) ZIPPY_NOPLAY_CRAFTY },
988     { "zippyGameEnd", "zippyGameEnd", XtRString, sizeof(String),
989         XtOffset(AppDataPtr, zippyGameEnd), XtRString, ZIPPY_GAME_END },
990     { "zippyGameStart", "zippyGameStart", XtRString, sizeof(String),
991         XtOffset(AppDataPtr, zippyGameStart), XtRString, ZIPPY_GAME_START },
992     { "zippyAdjourn", "zippyAdjourn", XtRBoolean,
993         sizeof(Boolean), XtOffset(AppDataPtr, zippyAdjourn),
994         XtRImmediate, (XtPointer) ZIPPY_ADJOURN },
995     { "zippyAbort", "zippyAbort", XtRBoolean,
996         sizeof(Boolean), XtOffset(AppDataPtr, zippyAbort),
997         XtRImmediate, (XtPointer) ZIPPY_ABORT },
998     { "zippyVariants", "zippyVariants", XtRString, sizeof(String),
999         XtOffset(AppDataPtr, zippyVariants), XtRString, ZIPPY_VARIANTS },
1000     { "zippyMaxGames", "zippyMaxGames", XtRInt, sizeof(int),
1001         XtOffset(AppDataPtr, zippyMaxGames), XtRImmediate,
1002         (XtPointer) ZIPPY_MAX_GAMES },
1003     { "zippyReplayTimeout", "zippyReplayTimeout", XtRInt, sizeof(int),
1004         XtOffset(AppDataPtr, zippyReplayTimeout), XtRImmediate,
1005         (XtPointer) ZIPPY_REPLAY_TIMEOUT },
1006 #endif
1007     { "flashCount", "flashCount", XtRInt, sizeof(int),
1008         XtOffset(AppDataPtr, flashCount), XtRImmediate,
1009         (XtPointer) FLASH_COUNT  },
1010     { "flashRate", "flashRate", XtRInt, sizeof(int),
1011         XtOffset(AppDataPtr, flashRate), XtRImmediate,
1012         (XtPointer) FLASH_RATE },
1013     { "pixmapDirectory", "pixmapDirectory", XtRString,
1014         sizeof(String), XtOffset(AppDataPtr, pixmapDirectory),
1015         XtRString, "" },
1016     { "msLoginDelay", "msLoginDelay", XtRInt, sizeof(int),
1017         XtOffset(AppDataPtr, msLoginDelay), XtRImmediate,
1018         (XtPointer) MS_LOGIN_DELAY },
1019     { "colorizeMessages", "colorizeMessages", XtRBoolean,
1020         sizeof(Boolean), XtOffset(AppDataPtr, colorize),
1021         XtRImmediate, (XtPointer) False },      
1022     { "colorShout", "colorShout", XtRString,
1023         sizeof(String), XtOffset(AppDataPtr, colorShout),
1024         XtRString, COLOR_SHOUT },
1025     { "colorSShout", "colorSShout", XtRString,
1026         sizeof(String), XtOffset(AppDataPtr, colorSShout),
1027         XtRString, COLOR_SSHOUT },
1028     { "colorChannel1", "colorChannel1", XtRString,
1029         sizeof(String), XtOffset(AppDataPtr, colorChannel1),
1030         XtRString, COLOR_CHANNEL1 },
1031     { "colorChannel", "colorChannel", XtRString,
1032         sizeof(String), XtOffset(AppDataPtr, colorChannel),
1033         XtRString, COLOR_CHANNEL },
1034     { "colorKibitz", "colorKibitz", XtRString,
1035         sizeof(String), XtOffset(AppDataPtr, colorKibitz),
1036         XtRString, COLOR_KIBITZ },
1037     { "colorTell", "colorTell", XtRString,
1038         sizeof(String), XtOffset(AppDataPtr, colorTell),
1039         XtRString, COLOR_TELL },
1040     { "colorChallenge", "colorChallenge", XtRString,
1041         sizeof(String), XtOffset(AppDataPtr, colorChallenge),
1042         XtRString, COLOR_CHALLENGE },
1043     { "colorRequest", "colorRequest", XtRString,
1044         sizeof(String), XtOffset(AppDataPtr, colorRequest),
1045         XtRString, COLOR_REQUEST },
1046     { "colorSeek", "colorSeek", XtRString,
1047         sizeof(String), XtOffset(AppDataPtr, colorSeek),
1048         XtRString, COLOR_SEEK },
1049     { "colorNormal", "colorNormal", XtRString,
1050         sizeof(String), XtOffset(AppDataPtr, colorNormal),
1051         XtRString, COLOR_NORMAL },      
1052     { "soundProgram", "soundProgram", XtRString,
1053       sizeof(String), XtOffset(AppDataPtr, soundProgram),
1054       XtRString, "play" },
1055     { "soundShout", "soundShout", XtRString,
1056       sizeof(String), XtOffset(AppDataPtr, soundShout),
1057       XtRString, "" },
1058     { "soundSShout", "soundSShout", XtRString,
1059       sizeof(String), XtOffset(AppDataPtr, soundSShout),
1060       XtRString, "" },
1061     { "soundChannel1", "soundChannel1", XtRString,
1062       sizeof(String), XtOffset(AppDataPtr, soundChannel1),
1063       XtRString, "" },
1064     { "soundChannel", "soundChannel", XtRString,
1065       sizeof(String), XtOffset(AppDataPtr, soundChannel),
1066       XtRString, "" },
1067     { "soundKibitz", "soundKibitz", XtRString,
1068       sizeof(String), XtOffset(AppDataPtr, soundKibitz),
1069       XtRString, "" },
1070     { "soundTell", "soundTell", XtRString,
1071       sizeof(String), XtOffset(AppDataPtr, soundTell),
1072       XtRString, "" },
1073     { "soundChallenge", "soundChallenge", XtRString,
1074       sizeof(String), XtOffset(AppDataPtr, soundChallenge),
1075       XtRString, "" },
1076     { "soundRequest", "soundRequest", XtRString,
1077       sizeof(String), XtOffset(AppDataPtr, soundRequest),
1078       XtRString, "" },
1079     { "soundSeek", "soundSeek", XtRString,
1080       sizeof(String), XtOffset(AppDataPtr, soundSeek),
1081       XtRString, "" },
1082     { "soundMove", "soundMove", XtRString,
1083       sizeof(String), XtOffset(AppDataPtr, soundMove),
1084       XtRString, "$" },
1085     { "soundIcsWin", "soundIcsWin", XtRString,
1086       sizeof(String), XtOffset(AppDataPtr, soundIcsWin),
1087       XtRString, "" },
1088     { "soundIcsLoss", "soundIcsLoss", XtRString,
1089       sizeof(String), XtOffset(AppDataPtr, soundIcsLoss),
1090       XtRString, "" },
1091     { "soundIcsDraw", "soundIcsDraw", XtRString,
1092       sizeof(String), XtOffset(AppDataPtr, soundIcsDraw),
1093       XtRString, "" },
1094     { "soundIcsUnfinished", "soundIcsUnfinished", XtRString,
1095       sizeof(String), XtOffset(AppDataPtr, soundIcsUnfinished),
1096       XtRString, "" },
1097     { "soundIcsAlarm", "soundIcsAlarm", XtRString,
1098       sizeof(String), XtOffset(AppDataPtr, soundIcsAlarm),
1099       XtRString, "$" },
1100     { "reuseFirst", "reuseFirst", XtRBoolean,
1101         sizeof(Boolean), XtOffset(AppDataPtr, reuseFirst),
1102         XtRImmediate, (XtPointer) True },
1103     { "reuseSecond", "reuseSecond", XtRBoolean,
1104         sizeof(Boolean), XtOffset(AppDataPtr, reuseSecond),
1105         XtRImmediate, (XtPointer) True },
1106     { "animateDragging", "animateDragging", XtRBoolean,
1107         sizeof(Boolean), XtOffset(AppDataPtr, animateDragging),
1108         XtRImmediate, (XtPointer) True },
1109     { "animateMoving", "animateMoving", XtRBoolean,
1110         sizeof(Boolean), XtOffset(AppDataPtr, animate),
1111         XtRImmediate, (XtPointer) True },
1112     { "animateSpeed", "animateSpeed", XtRInt,
1113         sizeof(int), XtOffset(AppDataPtr, animSpeed),
1114         XtRImmediate, (XtPointer)10 },
1115     { "popupExitMessage", "popupExitMessage", XtRBoolean,
1116         sizeof(Boolean), XtOffset(AppDataPtr, popupExitMessage),
1117         XtRImmediate, (XtPointer) True },
1118     { "popupMoveErrors", "popupMoveErrors", XtRBoolean,
1119         sizeof(Boolean), XtOffset(AppDataPtr, popupMoveErrors),
1120         XtRImmediate, (XtPointer) False },
1121     { "fontSizeTolerance", "fontSizeTolerance", XtRInt,
1122         sizeof(int), XtOffset(AppDataPtr, fontSizeTolerance),
1123         XtRImmediate, (XtPointer)4 },
1124     { "initialMode", "initialMode", XtRString,
1125         sizeof(String), XtOffset(AppDataPtr, initialMode),
1126         XtRImmediate, (XtPointer) "" },
1127     { "variant", "variant", XtRString,
1128         sizeof(String), XtOffset(AppDataPtr, variant),
1129         XtRImmediate, (XtPointer) "normal" },
1130     { "firstProtocolVersion", "firstProtocolVersion", XtRInt,
1131         sizeof(int), XtOffset(AppDataPtr, firstProtocolVersion),
1132         XtRImmediate, (XtPointer)PROTOVER },
1133     { "secondProtocolVersion", "secondProtocolVersion", XtRInt,
1134         sizeof(int), XtOffset(AppDataPtr, secondProtocolVersion),
1135         XtRImmediate, (XtPointer)PROTOVER },
1136     { "showButtonBar", "showButtonBar", XtRBoolean,
1137         sizeof(Boolean), XtOffset(AppDataPtr, showButtonBar),
1138         XtRImmediate, (XtPointer) True },
1139 };
1140
1141 XrmOptionDescRec shellOptions[] = {
1142     { "-whitePieceColor", "whitePieceColor", XrmoptionSepArg, NULL },
1143     { "-blackPieceColor", "blackPieceColor", XrmoptionSepArg, NULL },
1144     { "-lightSquareColor", "lightSquareColor", XrmoptionSepArg, NULL },
1145     { "-darkSquareColor", "darkSquareColor", XrmoptionSepArg, NULL },
1146     { "-highlightSquareColor", "highlightSquareColor", XrmoptionSepArg, NULL },
1147     { "-premoveHighlightColor", "premoveHighlightColor", XrmoptionSepArg,NULL},
1148     { "-movesPerSession", "movesPerSession", XrmoptionSepArg, NULL },
1149     { "-mps", "movesPerSession", XrmoptionSepArg, NULL },
1150     { "-timeIncrement", "timeIncrement", XrmoptionSepArg, NULL },
1151     { "-inc", "timeIncrement", XrmoptionSepArg, NULL },
1152     { "-initString", "initString", XrmoptionSepArg, NULL },
1153     { "-firstInitString", "initString", XrmoptionSepArg, NULL },
1154     { "-secondInitString", "secondInitString", XrmoptionSepArg, NULL },
1155     { "-firstComputerString", "firstComputerString", XrmoptionSepArg, NULL },
1156     { "-secondComputerString", "secondComputerString", XrmoptionSepArg, NULL },
1157     { "-firstChessProgram", "firstChessProgram", XrmoptionSepArg, NULL },
1158     { "-fcp", "firstChessProgram", XrmoptionSepArg, NULL },
1159     { "-secondChessProgram", "secondChessProgram", XrmoptionSepArg, NULL },
1160     { "-scp", "secondChessProgram", XrmoptionSepArg, NULL },
1161     { "-firstPlaysBlack", "firstPlaysBlack", XrmoptionSepArg, NULL },
1162     { "-fb", "firstPlaysBlack", XrmoptionNoArg, "True" },
1163     { "-xfb", "firstPlaysBlack", XrmoptionNoArg, "False" },
1164     { "-noChessProgram", "noChessProgram", XrmoptionSepArg, NULL },
1165     { "-ncp", "noChessProgram", XrmoptionNoArg, "True" },
1166     { "-xncp", "noChessProgram", XrmoptionNoArg, "False" },
1167     { "-firstHost", "firstHost", XrmoptionSepArg, NULL },
1168     { "-fh", "firstHost", XrmoptionSepArg, NULL },
1169     { "-secondHost", "secondHost", XrmoptionSepArg, NULL },
1170     { "-sh", "secondHost", XrmoptionSepArg, NULL },
1171     { "-firstDirectory", "firstDirectory", XrmoptionSepArg, NULL },
1172     { "-fd", "firstDirectory", XrmoptionSepArg, NULL },
1173     { "-secondDirectory", "secondDirectory", XrmoptionSepArg, NULL },
1174     { "-sd", "secondDirectory", XrmoptionSepArg, NULL },
1175     { "-bitmapDirectory", "bitmapDirectory", XrmoptionSepArg, NULL },
1176     { "-bm", "bitmapDirectory", XrmoptionSepArg, NULL },
1177     { "-remoteShell", "remoteShell", XrmoptionSepArg, NULL },
1178     { "-rsh", "remoteShell", XrmoptionSepArg, NULL },
1179     { "-remoteUser", "remoteUser", XrmoptionSepArg, NULL },
1180     { "-ruser", "remoteUser", XrmoptionSepArg, NULL },
1181     { "-timeDelay", "timeDelay", XrmoptionSepArg, NULL },
1182     { "-td", "timeDelay", XrmoptionSepArg, NULL },
1183     { "-timeControl", "timeControl", XrmoptionSepArg, NULL },
1184     { "-tc", "timeControl", XrmoptionSepArg, NULL },
1185     { "-internetChessServerMode", "internetChessServerMode",
1186         XrmoptionSepArg, NULL },
1187     { "-ics", "internetChessServerMode", XrmoptionNoArg, "True" },
1188     { "-xics", "internetChessServerMode", XrmoptionNoArg, "False" },
1189     { "-internetChessServerHost", "internetChessServerHost",
1190         XrmoptionSepArg, NULL },
1191     { "-icshost", "internetChessServerHost", XrmoptionSepArg, NULL },
1192     { "-internetChessServerPort", "internetChessServerPort",
1193         XrmoptionSepArg, NULL },
1194     { "-icsport", "internetChessServerPort", XrmoptionSepArg, NULL },
1195     { "-internetChessServerCommPort", "internetChessServerCommPort",
1196         XrmoptionSepArg, NULL },
1197     { "-icscomm", "internetChessServerCommPort", XrmoptionSepArg, NULL },
1198     { "-internetChessServerLogonScript", "internetChessServerLogonScript",
1199         XrmoptionSepArg, NULL },
1200     { "-icslogon", "internetChessServerLogonScript", XrmoptionSepArg, NULL },
1201     { "-internetChessServerHelper", "internetChessServerHelper",
1202         XrmoptionSepArg, NULL },
1203     { "-icshelper", "internetChessServerHelper", XrmoptionSepArg, NULL },
1204     { "-internetChessServerInputBox", "internetChessServerInputBox",
1205         XrmoptionSepArg, NULL },
1206     { "-icsinput", "internetChessServerInputBox", XrmoptionNoArg, "True" },
1207     { "-xicsinput", "internetChessServerInputBox", XrmoptionNoArg, "False" },
1208     { "-icsAlarm", "icsAlarm", XrmoptionSepArg, NULL },
1209     { "-alarm", "icsAlarm", XrmoptionNoArg, "True" },
1210     { "-xalarm", "icsAlarm", XrmoptionNoArg, "False" },
1211     { "-icsAlarmTime", "icsAlarmTime", XrmoptionSepArg, NULL },
1212     { "-useTelnet", "useTelnet", XrmoptionSepArg, NULL },
1213     { "-telnet", "useTelnet", XrmoptionNoArg, "True" },
1214     { "-xtelnet", "useTelnet", XrmoptionNoArg, "False" },
1215     { "-telnetProgram", "telnetProgram", XrmoptionSepArg, NULL },
1216     { "-gateway", "gateway", XrmoptionSepArg, NULL },
1217     { "-loadGameFile", "loadGameFile", XrmoptionSepArg, NULL },
1218     { "-lgf", "loadGameFile", XrmoptionSepArg, NULL },
1219     { "-loadGameIndex", "loadGameIndex", XrmoptionSepArg, NULL },
1220     { "-lgi", "loadGameIndex", XrmoptionSepArg, NULL },
1221     { "-saveGameFile", "saveGameFile", XrmoptionSepArg, NULL },
1222     { "-sgf", "saveGameFile", XrmoptionSepArg, NULL },
1223     { "-autoSaveGames", "autoSaveGames", XrmoptionSepArg, NULL },
1224     { "-autosave", "autoSaveGames", XrmoptionNoArg, "True" },
1225     { "-xautosave", "autoSaveGames", XrmoptionNoArg, "False" },
1226     { "-autoRaiseBoard", "autoRaiseBoard", XrmoptionSepArg, NULL },
1227     { "-autoraise", "autoRaiseBoard", XrmoptionNoArg, "True" },
1228     { "-xautoraise", "autoRaiseBoard", XrmoptionNoArg, "False" },
1229     { "-blindfold", "blindfold", XrmoptionSepArg, NULL },
1230     { "-blind", "blindfold", XrmoptionNoArg, "True" },
1231     { "-xblind", "blindfold", XrmoptionNoArg, "False" },
1232     { "-loadPositionFile", "loadPositionFile", XrmoptionSepArg, NULL },
1233     { "-lpf", "loadPositionFile", XrmoptionSepArg, NULL },
1234     { "-loadPositionIndex", "loadPositionIndex", XrmoptionSepArg, NULL },
1235     { "-lpi", "loadPositionIndex", XrmoptionSepArg, NULL },
1236     { "-savePositionFile", "savePositionFile", XrmoptionSepArg, NULL },
1237     { "-spf", "savePositionFile", XrmoptionSepArg, NULL },
1238     { "-matchMode", "matchMode", XrmoptionSepArg, NULL },
1239     { "-mm", "matchMode", XrmoptionNoArg, "True" },
1240     { "-xmm", "matchMode", XrmoptionNoArg, "False" },
1241     { "-matchGames", "matchGames", XrmoptionSepArg, NULL },
1242     { "-mg", "matchGames", XrmoptionSepArg, NULL },
1243     { "-monoMode", "monoMode", XrmoptionSepArg, NULL },
1244     { "-mono", "monoMode", XrmoptionNoArg, "True" },
1245     { "-xmono", "monoMode", XrmoptionNoArg, "False" },
1246     { "-debugMode", "debugMode", XrmoptionSepArg, NULL },
1247     { "-debug", "debugMode", XrmoptionNoArg, "True" },
1248     { "-xdebug", "debugMode", XrmoptionNoArg, "False" },
1249     { "-clockMode", "clockMode", XrmoptionSepArg, NULL },
1250     { "-clock", "clockMode", XrmoptionNoArg, "True" },
1251     { "-xclock", "clockMode", XrmoptionNoArg, "False" },
1252     { "-boardSize", "boardSize", XrmoptionSepArg, NULL },
1253     { "-size", "boardSize", XrmoptionSepArg, NULL },
1254     { "-searchTime", "searchTime", XrmoptionSepArg, NULL },
1255     { "-st", "searchTime", XrmoptionSepArg, NULL },
1256     { "-searchDepth", "searchDepth", XrmoptionSepArg, NULL },
1257     { "-depth", "searchDepth", XrmoptionSepArg, NULL },
1258     { "-showCoords", "showCoords", XrmoptionSepArg, NULL },
1259     { "-coords", "showCoords", XrmoptionNoArg, "True" },
1260     { "-xcoords", "showCoords", XrmoptionNoArg, "False" },
1261 #if JAIL
1262     { "-showJail", "showJail", XrmoptionSepArg, NULL },
1263     { "-jail", "showJail", XrmoptionNoArg, "1" },
1264     { "-sidejail", "showJail", XrmoptionNoArg, "2" },
1265     { "-xjail", "showJail", XrmoptionNoArg, "0" },
1266 #endif
1267     { "-showThinking", "showThinking", XrmoptionSepArg, NULL },
1268     { "-thinking", "showThinking", XrmoptionNoArg, "True" },
1269     { "-xthinking", "showThinking", XrmoptionNoArg, "False" },
1270     { "-ponderNextMove", "ponderNextMove", XrmoptionSepArg, NULL },
1271     { "-ponder", "ponderNextMove", XrmoptionNoArg, "True" },
1272     { "-xponder", "ponderNextMove", XrmoptionNoArg, "False" },
1273     { "-periodicUpdates", "periodicUpdates", XrmoptionSepArg, NULL },
1274     { "-periodic", "periodicUpdates", XrmoptionNoArg, "True" },
1275     { "-xperiodic", "periodicUpdates", XrmoptionNoArg, "False" },
1276     { "-clockFont", "clockFont", XrmoptionSepArg, NULL },
1277     { "-coordFont", "coordFont", XrmoptionSepArg, NULL },
1278     { "-font", "font", XrmoptionSepArg, NULL },
1279     { "-ringBellAfterMoves", "ringBellAfterMoves", XrmoptionSepArg, NULL },
1280     { "-bell", "ringBellAfterMoves", XrmoptionNoArg, "True" },
1281     { "-xbell", "ringBellAfterMoves", XrmoptionNoArg, "False" },
1282     { "-movesound", "ringBellAfterMoves", XrmoptionNoArg, "True" },
1283     { "-xmovesound", "ringBellAfterMoves", XrmoptionNoArg, "False" },
1284     { "-autoCallFlag", "autoCallFlag", XrmoptionSepArg, NULL },
1285     { "-autoflag", "autoCallFlag", XrmoptionNoArg, "True" },
1286     { "-xautoflag", "autoCallFlag", XrmoptionNoArg, "False" },
1287     { "-autoFlipView", "autoFlipView", XrmoptionSepArg, NULL },
1288     { "-autoflip", "autoFlipView", XrmoptionNoArg, "True" },
1289     { "-xautoflip", "autoFlipView", XrmoptionNoArg, "False" },
1290     { "-autoObserve", "autoObserve", XrmoptionSepArg, NULL },
1291     { "-autobs", "autoObserve", XrmoptionNoArg, "True" },
1292     { "-xautobs", "autoObserve", XrmoptionNoArg, "False" },
1293     { "-autoComment", "autoComment", XrmoptionSepArg, NULL },
1294     { "-autocomm", "autoComment", XrmoptionNoArg, "True" },
1295     { "-xautocomm", "autoComment", XrmoptionNoArg, "False" },
1296     { "-getMoveList", "getMoveList", XrmoptionSepArg, NULL },
1297     { "-moves", "getMoveList", XrmoptionNoArg, "True" },
1298     { "-xmoves", "getMoveList", XrmoptionNoArg, "False" },
1299 #if HIGHDRAG
1300     { "-highlightDragging", "highlightDragging", XrmoptionSepArg, NULL },
1301     { "-highdrag", "highlightDragging", XrmoptionNoArg, "True" },
1302     { "-xhighdrag", "highlightDragging", XrmoptionNoArg, "False" },
1303 #endif
1304     { "-highlightLastMove", "highlightLastMove", XrmoptionSepArg, NULL },
1305     { "-highlight", "highlightLastMove", XrmoptionNoArg, "True" },
1306     { "-xhighlight", "highlightLastMove", XrmoptionNoArg, "False" },
1307     { "-premove", "premove", XrmoptionSepArg, NULL },
1308     { "-pre", "premove", XrmoptionNoArg, "True" },
1309     { "-xpre", "premove", XrmoptionNoArg, "False" },
1310     { "-testLegality", "testLegality", XrmoptionSepArg, NULL },
1311     { "-legal", "testLegality", XrmoptionNoArg, "True" },
1312     { "-xlegal", "testLegality", XrmoptionNoArg, "False" },
1313     { "-flipView", "flipView", XrmoptionSepArg, NULL },
1314     { "-flip", "flipView", XrmoptionNoArg, "True" },
1315     { "-xflip", "flipView", XrmoptionNoArg, "False" },
1316     { "-cmail", "cmailGameName", XrmoptionSepArg, NULL },
1317     { "-alwaysPromoteToQueen", "alwaysPromoteToQueen",
1318         XrmoptionSepArg, NULL },
1319     { "-queen", "alwaysPromoteToQueen", XrmoptionNoArg, "True" },
1320     { "-xqueen", "alwaysPromoteToQueen", XrmoptionNoArg, "False" },
1321     { "-oldSaveStyle", "oldSaveStyle", XrmoptionSepArg, NULL },
1322     { "-oldsave", "oldSaveStyle", XrmoptionNoArg, "True" },
1323     { "-xoldsave", "oldSaveStyle", XrmoptionNoArg, "False" },
1324     { "-quietPlay", "quietPlay", XrmoptionSepArg, NULL },
1325     { "-quiet", "quietPlay", XrmoptionNoArg, "True" },
1326     { "-xquiet", "quietPlay", XrmoptionNoArg, "False" },
1327     { "-titleInWindow", "titleInWindow", XrmoptionSepArg, NULL },
1328     { "-title", "titleInWindow", XrmoptionNoArg, "True" },
1329     { "-xtitle", "titleInWindow", XrmoptionNoArg, "False" },
1330 #ifdef ZIPPY
1331     { "-zippyTalk", "zippyTalk", XrmoptionSepArg, NULL },
1332     { "-zt", "zippyTalk", XrmoptionNoArg, "True" },
1333     { "-xzt", "zippyTalk", XrmoptionNoArg, "False" },
1334     { "-zippyPlay", "zippyPlay", XrmoptionSepArg, NULL },
1335     { "-zp", "zippyPlay", XrmoptionNoArg, "True" },
1336     { "-xzp", "zippyPlay", XrmoptionNoArg, "False" },
1337     { "-zippyLines", "zippyLines", XrmoptionSepArg, NULL },
1338     { "-zippyPinhead", "zippyPinhead", XrmoptionSepArg, NULL },
1339     { "-zippyPassword", "zippyPassword", XrmoptionSepArg, NULL },
1340     { "-zippyPassword2", "zippyPassword2", XrmoptionSepArg, NULL },
1341     { "-zippyWrongPassword", "zippyWrongPassword", XrmoptionSepArg, NULL },
1342     { "-zippyAcceptOnly", "zippyAcceptOnly", XrmoptionSepArg, NULL },
1343     { "-zippyUseI", "zippyUseI", XrmoptionSepArg, NULL },
1344     { "-zui", "zippyUseI", XrmoptionNoArg, "True" },
1345     { "-xzui", "zippyUseI", XrmoptionNoArg, "False" },
1346     { "-zippyBughouse", "zippyBughouse", XrmoptionSepArg, NULL },
1347     { "-zippyNoplayCrafty", "zippyNoplayCrafty", XrmoptionSepArg, NULL },
1348     { "-znc", "zippyNoplayCrafty", XrmoptionNoArg, "True" },
1349     { "-xznc", "zippyNoplayCrafty", XrmoptionNoArg, "False" },
1350     { "-zippyGameEnd", "zippyGameEnd", XrmoptionSepArg, NULL },
1351     { "-zippyGameStart", "zippyGameStart", XrmoptionSepArg, NULL },
1352     { "-zippyAdjourn", "zippyAdjourn", XrmoptionSepArg, NULL },
1353     { "-zadj", "zippyAdjourn", XrmoptionNoArg, "True" },
1354     { "-xzadj", "zippyAdjourn", XrmoptionNoArg, "False" },
1355     { "-zippyAbort", "zippyAbort", XrmoptionSepArg, NULL },
1356     { "-zab", "zippyAbort", XrmoptionNoArg, "True" },
1357     { "-xzab", "zippyAbort", XrmoptionNoArg, "False" },
1358     { "-zippyVariants", "zippyVariants", XrmoptionSepArg, NULL },
1359     { "-zippyMaxGames", "zippyMaxGames", XrmoptionSepArg, NULL },
1360     { "-zippyReplayTimeout", "zippyReplayTimeout", XrmoptionSepArg, NULL },
1361 #endif
1362     { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
1363     { "-flash", "flashCount", XrmoptionNoArg, "3" },
1364     { "-xflash", "flashCount", XrmoptionNoArg, "0" },
1365     { "-flashRate", "flashRate", XrmoptionSepArg, NULL },
1366     { "-pixmapDirectory", "pixmapDirectory", XrmoptionSepArg, NULL },
1367     { "-msLoginDelay", "msLoginDelay", XrmoptionSepArg, NULL },
1368     { "-pixmap", "pixmapDirectory", XrmoptionSepArg, NULL },
1369     { "-colorizeMessages", "colorizeMessages", XrmoptionSepArg, NULL },
1370     { "-colorize", "colorizeMessages", XrmoptionNoArg, "True" },
1371     { "-xcolorize", "colorizeMessages", XrmoptionNoArg, "False" },
1372     { "-colorShout", "colorShout", XrmoptionSepArg, NULL },
1373     { "-colorSShout", "colorSShout", XrmoptionSepArg, NULL },
1374     { "-colorCShout", "colorSShout", XrmoptionSepArg, NULL }, /*FICS name*/
1375     { "-colorChannel1", "colorChannel1", XrmoptionSepArg, NULL },
1376     { "-colorChannel", "colorChannel", XrmoptionSepArg, NULL },
1377     { "-colorKibitz", "colorKibitz", XrmoptionSepArg, NULL },
1378     { "-colorTell", "colorTell", XrmoptionSepArg, NULL },
1379     { "-colorChallenge", "colorChallenge", XrmoptionSepArg, NULL },
1380     { "-colorRequest", "colorRequest", XrmoptionSepArg, NULL },
1381     { "-colorSeek", "colorSeek", XrmoptionSepArg, NULL },
1382     { "-colorNormal", "colorNormal", XrmoptionSepArg, NULL },
1383     { "-soundProgram", "soundProgram", XrmoptionSepArg, NULL },
1384     { "-soundShout", "soundShout", XrmoptionSepArg, NULL },
1385     { "-soundSShout", "soundSShout", XrmoptionSepArg, NULL },
1386     { "-soundCShout", "soundSShout", XrmoptionSepArg, NULL }, /*FICS name*/
1387     { "-soundChannel1", "soundChannel1", XrmoptionSepArg, NULL },
1388     { "-soundChannel", "soundChannel", XrmoptionSepArg, NULL },
1389     { "-soundKibitz", "soundKibitz", XrmoptionSepArg, NULL },
1390     { "-soundTell", "soundTell", XrmoptionSepArg, NULL },
1391     { "-soundChallenge", "soundChallenge", XrmoptionSepArg, NULL },
1392     { "-soundRequest", "soundRequest", XrmoptionSepArg, NULL },
1393     { "-soundSeek", "soundSeek", XrmoptionSepArg, NULL },
1394     { "-soundMove", "soundMove", XrmoptionSepArg, NULL },
1395     { "-soundIcsWin", "soundIcsWin", XrmoptionSepArg, NULL },
1396     { "-soundIcsLoss", "soundIcsLoss", XrmoptionSepArg, NULL },
1397     { "-soundIcsDraw", "soundIcsDraw", XrmoptionSepArg, NULL },
1398     { "-soundIcsUnfinished", "soundIcsUnfinished", XrmoptionSepArg, NULL },
1399     { "-soundIcsAlarm", "soundIcsAlarm", XrmoptionSepArg, NULL },
1400     { "-reuseFirst", "reuseFirst", XrmoptionSepArg, NULL },
1401     { "-reuseChessPrograms", "reuseFirst", XrmoptionSepArg, NULL }, /*compat*/
1402     { "-reuse", "reuseFirst", XrmoptionNoArg, "True" },
1403     { "-xreuse", "reuseFirst", XrmoptionNoArg, "False" },
1404     { "-reuseSecond", "reuseSecond", XrmoptionSepArg, NULL },
1405     { "-reuse2", "reuseSecond", XrmoptionNoArg, "True" },
1406     { "-xreuse2", "reuseSecond", XrmoptionNoArg, "False" },
1407     { "-animateMoving", "animateMoving", XrmoptionSepArg, NULL },
1408     { "-animate", "animateMoving", XrmoptionNoArg, "True" },
1409     { "-xanimate", "animateMoving", XrmoptionNoArg, "False" },
1410     { "-animateDragging", "animateDragging", XrmoptionSepArg, NULL },
1411     { "-drag", "animateDragging", XrmoptionNoArg, "True" },
1412     { "-xdrag", "animateDragging", XrmoptionNoArg, "False" },
1413     { "-animateSpeed", "animateSpeed", XrmoptionSepArg, NULL },
1414     { "-popupExitMessage", "popupExitMessage", XrmoptionSepArg, NULL },
1415     { "-exit", "popupExitMessage", XrmoptionNoArg, "True" },
1416     { "-xexit", "popupExitMessage", XrmoptionNoArg, "False" },
1417     { "-popupMoveErrors", "popupMoveErrors", XrmoptionSepArg, NULL },
1418     { "-popup", "popupMoveErrors", XrmoptionNoArg, "True" },
1419     { "-xpopup", "popupMoveErrors", XrmoptionNoArg, "False" },
1420     { "-fontSizeTolerance", "fontSizeTolerance", XrmoptionSepArg, NULL },
1421     { "-initialMode", "initialMode", XrmoptionSepArg, NULL },
1422     { "-mode", "initialMode", XrmoptionSepArg, NULL },
1423     { "-variant", "variant", XrmoptionSepArg, NULL },
1424     { "-firstProtocolVersion", "firstProtocolVersion", XrmoptionSepArg, NULL },
1425     { "-secondProtocolVersion","secondProtocolVersion",XrmoptionSepArg, NULL },
1426     { "-showButtonBar", "showButtonBar", XrmoptionSepArg, NULL },
1427     { "-buttons", "showButtonBar", XrmoptionNoArg, "True" },
1428     { "-xbuttons", "showButtonBar", XrmoptionNoArg, "False" },
1429 };
1430
1431
1432 XtActionsRec boardActions[] = {
1433     { "DrawPosition", DrawPositionProc },
1434     { "HandleUserMove", HandleUserMove },
1435     { "AnimateUserMove", AnimateUserMove },
1436     { "FileNameAction", FileNameAction },
1437     { "AskQuestionProc", AskQuestionProc },
1438     { "AskQuestionReplyAction", AskQuestionReplyAction },
1439     { "PieceMenuPopup", PieceMenuPopup },
1440     { "WhiteClock", WhiteClock },
1441     { "BlackClock", BlackClock },
1442     { "Iconify", Iconify },
1443     { "ResetProc", ResetProc },
1444     { "LoadGameProc", LoadGameProc },
1445     { "LoadNextGameProc", LoadNextGameProc },
1446     { "LoadPrevGameProc", LoadPrevGameProc },
1447     { "LoadSelectedProc", LoadSelectedProc },
1448     { "ReloadGameProc", ReloadGameProc },
1449     { "LoadPositionProc", LoadPositionProc },
1450     { "LoadNextPositionProc", LoadNextPositionProc },
1451     { "LoadPrevPositionProc", LoadPrevPositionProc },
1452     { "ReloadPositionProc", ReloadPositionProc },
1453     { "CopyPositionProc", CopyPositionProc },
1454     { "PastePositionProc", PastePositionProc },
1455     { "CopyGameProc", CopyGameProc },
1456     { "PasteGameProc", PasteGameProc },
1457     { "SaveGameProc", SaveGameProc },
1458     { "SavePositionProc", SavePositionProc },
1459     { "MailMoveProc", MailMoveProc },
1460     { "ReloadCmailMsgProc", ReloadCmailMsgProc },
1461     { "QuitProc", QuitProc },
1462     { "MachineWhiteProc", MachineWhiteProc },
1463     { "MachineBlackProc", MachineBlackProc },
1464     { "AnalysisModeProc", AnalyzeModeProc },
1465     { "AnalyzeFileProc", AnalyzeFileProc },
1466     { "TwoMachinesProc", TwoMachinesProc },
1467     { "IcsClientProc", IcsClientProc },
1468     { "EditGameProc", EditGameProc },
1469     { "EditPositionProc", EditPositionProc },
1470     { "TrainingProc", EditPositionProc },
1471     { "ShowGameListProc", ShowGameListProc },
1472     { "ShowMoveListProc", HistoryShowProc},
1473     { "EditTagsProc", EditCommentProc },
1474     { "EditCommentProc", EditCommentProc },
1475     { "IcsAlarmProc", IcsAlarmProc },
1476     { "IcsInputBoxProc", IcsInputBoxProc },
1477     { "PauseProc", PauseProc },
1478     { "AcceptProc", AcceptProc },
1479     { "DeclineProc", DeclineProc },
1480     { "RematchProc", RematchProc },
1481     { "CallFlagProc", CallFlagProc },
1482     { "DrawProc", DrawProc },
1483     { "AdjournProc", AdjournProc },
1484     { "AbortProc", AbortProc },
1485     { "ResignProc", ResignProc },
1486     { "EnterKeyProc", EnterKeyProc },
1487     { "StopObservingProc", StopObservingProc },
1488     { "StopExaminingProc", StopExaminingProc },
1489     { "BackwardProc", BackwardProc },
1490     { "ForwardProc", ForwardProc },
1491     { "ToStartProc", ToStartProc },
1492     { "ToEndProc", ToEndProc },
1493     { "RevertProc", RevertProc },
1494     { "TruncateGameProc", TruncateGameProc },
1495     { "MoveNowProc", MoveNowProc },
1496     { "RetractMoveProc", RetractMoveProc },
1497     { "AlwaysQueenProc", AlwaysQueenProc },
1498     { "AnimateDraggingProc", AnimateDraggingProc },
1499     { "AnimateMovingProc", AnimateMovingProc },
1500     { "AutoflagProc", AutoflagProc },
1501     { "AutoflipProc", AutoflipProc },
1502     { "AutobsProc", AutobsProc },
1503     { "AutoraiseProc", AutoraiseProc },
1504     { "AutosaveProc", AutosaveProc },
1505     { "BlindfoldProc", BlindfoldProc },
1506     { "FlashMovesProc", FlashMovesProc },
1507     { "FlipViewProc", FlipViewProc },
1508     { "GetMoveListProc", GetMoveListProc },
1509 #if HIGHDRAG
1510     { "HighlightDraggingProc", HighlightDraggingProc },
1511 #endif
1512     { "HighlightLastMoveProc", HighlightLastMoveProc },
1513     { "IcsAlarmProc", IcsAlarmProc },
1514     { "MoveSoundProc", MoveSoundProc },
1515     { "OldSaveStyleProc", OldSaveStyleProc },
1516     { "PeriodicUpdatesProc", PeriodicUpdatesProc },     
1517     { "PonderNextMoveProc", PonderNextMoveProc },
1518     { "PopupExitMessageProc", PopupExitMessageProc },   
1519     { "PopupMoveErrorsProc", PopupMoveErrorsProc },     
1520     { "PremoveProc", PremoveProc },
1521     { "QuietPlayProc", QuietPlayProc },
1522     { "ShowCoordsProc", ShowCoordsProc },
1523     { "ShowThinkingProc", ShowThinkingProc },
1524     { "TestLegalityProc", TestLegalityProc },
1525     { "InfoProc", InfoProc },
1526     { "ManProc", ManProc },
1527     { "HintProc", HintProc },
1528     { "BookProc", BookProc },
1529     { "AboutGameProc", AboutGameProc },
1530     { "AboutProc", AboutProc },
1531     { "DebugProc", DebugProc },
1532     { "NothingProc", NothingProc },
1533     { "CommentPopDown", (XtActionProc) CommentPopDown },
1534     { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
1535     { "TagsPopDown", (XtActionProc) TagsPopDown },
1536     { "ErrorPopDown", (XtActionProc) ErrorPopDown },
1537     { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
1538     { "AnalysisPopDown", (XtActionProc) AnalysisPopDown },
1539     { "FileNamePopDown", (XtActionProc) FileNamePopDown },
1540     { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
1541     { "GameListPopDown", (XtActionProc) GameListPopDown },
1542     { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1543     { "HistoryPopDown", (XtActionProc) HistoryPopDown },
1544 };
1545      
1546 char globalTranslations[] =
1547   ":<Key>R: ResignProc() \n \
1548    :<Key>r: ResetProc() \n \
1549    :<Key>g: LoadGameProc() \n \
1550    :<Key>N: LoadNextGameProc() \n \
1551    :<Key>P: LoadPrevGameProc() \n \
1552    :<Key>Q: QuitProc() \n \
1553    :<Key>F: ToEndProc() \n \
1554    :<Key>f: ForwardProc() \n \
1555    :<Key>B: ToStartProc() \n \
1556    :<Key>b: BackwardProc() \n \
1557    :<Key>p: PauseProc() \n \
1558    :<Key>d: DrawProc() \n \
1559    :<Key>t: CallFlagProc() \n \
1560    :<Key>i: Iconify() \n \
1561    :<Key>c: Iconify() \n \
1562    :<Key>v: FlipViewProc() \n \
1563    <KeyDown>Control_L: BackwardProc() \n \
1564    <KeyUp>Control_L: ForwardProc() \n \
1565    <KeyDown>Control_R: BackwardProc() \n \
1566    <KeyUp>Control_R: ForwardProc() \n \
1567    Shift<Key>1: AskQuestionProc(\"Direct command\",\
1568                                 \"Send to chess program:\",,1) \n \
1569    Shift<Key>2: AskQuestionProc(\"Direct command\",\
1570                                 \"Send to second chess program:\",,2) \n";
1571
1572 char boardTranslations[] =
1573    "<Btn1Down>: HandleUserMove() \n \
1574    <Btn1Up>: HandleUserMove() \n \
1575    <Btn1Motion>: AnimateUserMove() \n \
1576    Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1577                  PieceMenuPopup(menuB) \n \
1578    Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1579                  PieceMenuPopup(menuW) \n \
1580    Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1581                  PieceMenuPopup(menuW) \n \
1582    Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1583                  PieceMenuPopup(menuB) \n";
1584      
1585 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1586 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1587      
1588 char ICSInputTranslations[] =
1589     "<Key>Return: EnterKeyProc() \n";
1590
1591 String xboardResources[] = {
1592     "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1593     "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1594     "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1595     NULL
1596   };
1597      
1598
1599 /* Max possible square size */
1600 #define MAXSQSIZE 256
1601
1602 static int xpm_avail[MAXSQSIZE];
1603
1604 #ifdef HAVE_DIR_STRUCT
1605
1606 /* Extract piece size from filename */
1607 static int
1608 xpm_getsize(name, len, ext)
1609      char *name;
1610      int len;
1611      char *ext;
1612 {
1613     char *p, *d;
1614     char buf[10];
1615   
1616     if (len < 4)
1617       return 0;
1618
1619     if ((p=strchr(name, '.')) == NULL ||
1620         StrCaseCmp(p+1, ext) != 0)
1621       return 0;
1622   
1623     p = name + 3;
1624     d = buf;
1625
1626     while (*p && isdigit(*p))
1627       *(d++) = *(p++);
1628
1629     *d = 0;
1630     return atoi(buf);
1631 }
1632
1633 /* Setup xpm_avail */
1634 static int
1635 xpm_getavail(dirname, ext)
1636      char *dirname;
1637      char *ext;
1638 {
1639     DIR *dir;
1640     struct dirent *ent;
1641     int  i;
1642
1643     for (i=0; i<MAXSQSIZE; ++i)
1644       xpm_avail[i] = 0;
1645
1646     if (appData.debugMode)
1647       fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1648   
1649     dir = opendir(dirname);
1650     if (!dir)
1651       {
1652           fprintf(stderr, "%s: Can't access XPM directory %s\n", 
1653                   programName, dirname);
1654           exit(1);
1655       }
1656   
1657     while ((ent=readdir(dir)) != NULL) {
1658         i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1659         if (i > 0 && i < MAXSQSIZE)
1660           xpm_avail[i] = 1;
1661     }
1662
1663     closedir(dir);
1664
1665     return 0;
1666 }
1667
1668 void
1669 xpm_print_avail(fp, ext)
1670      FILE *fp;
1671      char *ext;
1672 {
1673     int i;
1674
1675     fprintf(fp, "Available `%s' sizes:\n", ext);
1676     for (i=1; i<MAXSQSIZE; ++i) {
1677         if (xpm_avail[i])
1678           printf("%d\n", i);
1679     }
1680 }
1681
1682 /* Return XPM piecesize closest to size */
1683 int
1684 xpm_closest_to(dirname, size, ext)
1685      char *dirname;
1686      int size;
1687      char *ext;
1688 {
1689     int i;
1690     int sm_diff = MAXSQSIZE;
1691     int sm_index = 0;
1692     int diff;
1693   
1694     xpm_getavail(dirname, ext);
1695
1696     if (appData.debugMode)
1697       xpm_print_avail(stderr, ext);
1698   
1699     for (i=1; i<MAXSQSIZE; ++i) {
1700         if (xpm_avail[i]) {
1701             diff = size - i;
1702             diff = (diff<0) ? -diff : diff;
1703             if (diff < sm_diff) {
1704                 sm_diff = diff;
1705                 sm_index = i;
1706             }
1707         }
1708     }
1709
1710     if (!sm_index) {
1711         fprintf(stderr, "Error: No `%s' files!\n", ext);
1712         exit(1);
1713     }
1714
1715     return sm_index;
1716 }
1717 #else   /* !HAVE_DIR_STRUCT */
1718 /* If we are on a system without a DIR struct, we can't
1719    read the directory, so we can't collect a list of
1720    filenames, etc., so we can't do any size-fitting. */
1721 int
1722 xpm_closest_to(dirname, size, ext)
1723      char *dirname;
1724      int size;
1725      char *ext;
1726 {
1727     fprintf(stderr, "Warning: No DIR structure found on this system --\n");
1728     fprintf(stderr, "         Unable to autosize for XPM/XIM pieces.\n");
1729     fprintf(stderr, "   Please report this error to frankm@hiwaay.net.\n");
1730     fprintf(stderr, "   Include system type & operating system in message.\n");
1731     return size;
1732 }
1733 #endif /* HAVE_DIR_STRUCT */
1734
1735 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1736                              "magenta", "cyan", "white" };
1737 typedef struct {
1738     int attr, bg, fg;
1739 } TextColors;
1740 TextColors textColors[(int)NColorClasses];
1741
1742 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1743 static int
1744 parse_color(str, which)
1745      char *str;
1746      int which;
1747 {
1748     char *p, buf[100], *d;
1749     int i;
1750   
1751     if (strlen(str) > 99)       /* watch bounds on buf */
1752       return -1;
1753
1754     p = str;
1755     d = buf;
1756     for (i=0; i<which; ++i) {
1757         p = strchr(p, ',');
1758         if (!p)
1759           return -1;
1760         ++p;
1761     }
1762
1763     /* Could be looking at something like:
1764        black, , 1
1765        .. in which case we want to stop on a comma also */
1766     while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1767       ++p;
1768
1769     if (*p == ',') {
1770         return -1;              /* Use default for empty field */
1771     }
1772     
1773     if (which == 2 || isdigit(*p))
1774       return atoi(p);
1775  
1776     while (*p && isalpha(*p))
1777       *(d++) = *(p++);
1778
1779     *d = 0;
1780
1781     for (i=0; i<8; ++i) {
1782         if (!StrCaseCmp(buf, cnames[i]))
1783           return which? (i+40) : (i+30);
1784     }
1785     if (!StrCaseCmp(buf, "default")) return -1;
1786
1787     fprintf(stderr, "%s: unrecognized color %s\n", programName, buf);
1788     return -2;
1789 }
1790
1791 static int
1792 parse_cpair(cc, str)
1793      ColorClass cc;
1794      char *str;
1795 {
1796     if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1797         fprintf(stderr, "%s: can't parse foreground color in `%s'\n",
1798                 programName, str);
1799         return -1;
1800     }
1801
1802     /* bg and attr are optional */
1803     textColors[(int)cc].bg = parse_color(str, 1);
1804     if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1805         textColors[(int)cc].attr = 0;
1806     }
1807     return 0;
1808 }
1809
1810
1811 /* Arrange to catch delete-window events */
1812 Atom wm_delete_window;
1813 void
1814 CatchDeleteWindow(Widget w, String procname)
1815 {
1816   char buf[MSG_SIZ];
1817   XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1818   sprintf(buf, "<Message>WM_PROTOCOLS: %s() \n", procname);
1819   XtAugmentTranslations(w, XtParseTranslationTable(buf));
1820 }
1821
1822 void
1823 BoardToTop()
1824 {
1825   Arg args[16];
1826   XtSetArg(args[0], XtNiconic, False);
1827   XtSetValues(shellWidget, args, 1);
1828
1829   XtPopup(shellWidget, XtGrabNone); /* Raise if lowered  */
1830 }
1831
1832 int
1833 main(argc, argv)
1834      int argc;
1835      char **argv;
1836 {
1837     int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1838     XSetWindowAttributes window_attributes;
1839     Arg args[16];
1840     Dimension timerWidth, boardWidth, w, h, sep, bor, wr, hr;
1841     XrmValue vFrom, vTo;
1842     XtGeometryResult gres;
1843     char *p;
1844     XrmDatabase xdb;
1845     int forceMono = False;
1846
1847     setbuf(stdout, NULL);
1848     setbuf(stderr, NULL);
1849     debugFP = stderr;
1850     
1851     programName = strrchr(argv[0], '/');
1852     if (programName == NULL)
1853       programName = argv[0];
1854     else
1855       programName++;
1856
1857     shellWidget =
1858       XtAppInitialize(&appContext, "XBoard", shellOptions,
1859                       XtNumber(shellOptions),
1860                       &argc, argv, xboardResources, NULL, 0);
1861     if (argc > 1) {
1862         fprintf(stderr, "%s: unrecognized argument %s\n",
1863                 programName, argv[1]);
1864         exit(2);
1865     }
1866     
1867     if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1868         chessDir = ".";
1869     } else {
1870         if (chdir(chessDir) != 0) {
1871             fprintf(stderr, "%s: can't cd to CHESSDIR: ", programName);
1872             perror(chessDir);
1873             exit(1);
1874         }
1875     }
1876     
1877     p = getenv("HOME");
1878     if (p == NULL) p = "/tmp";
1879     i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1880     gameCopyFilename = (char*) malloc(i);
1881     gamePasteFilename = (char*) malloc(i);
1882     sprintf(gameCopyFilename, "%s/.xboard%05uc.pgn", p, getpid());
1883     sprintf(gamePasteFilename, "%s/.xboard%05up.pgn", p, getpid());
1884
1885     XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1886                               clientResources, XtNumber(clientResources),
1887                               NULL, 0);
1888
1889 #if !HIGHDRAG
1890     /* This feature does not work; animation needs a rewrite */
1891     appData.highlightDragging = FALSE;
1892 #endif
1893     InitBackEnd1();
1894
1895     xDisplay = XtDisplay(shellWidget);
1896     xScreen = DefaultScreen(xDisplay);
1897     wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1898
1899     /*
1900      * Determine boardSize
1901      */
1902     if (isdigit(appData.boardSize[0])) {
1903         i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1904                    &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1905                    &fontPxlSize, &smallLayout, &tinyLayout);
1906         if (i == 0) {
1907             fprintf(stderr, "%s: bad boardSize syntax %s\n",
1908                     programName, appData.boardSize);
1909             exit(2);
1910         }
1911         if (i < 7) {
1912             /* Find some defaults; use the nearest known size */
1913             SizeDefaults *szd, *nearest;
1914             int distance = 99999;
1915             nearest = szd = sizeDefaults;
1916             while (szd->name != NULL) {
1917                 if (abs(szd->squareSize - squareSize) < distance) {
1918                     nearest = szd;
1919                     distance = abs(szd->squareSize - squareSize);
1920                     if (distance == 0) break;
1921                 }
1922                 szd++;
1923             }
1924             if (i < 2) lineGap = nearest->lineGap;
1925             if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1926             if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1927             if (i < 5) fontPxlSize = nearest->fontPxlSize;
1928             if (i < 6) smallLayout = nearest->smallLayout;
1929             if (i < 7) tinyLayout = nearest->tinyLayout;
1930         }
1931     } else {
1932         SizeDefaults *szd = sizeDefaults;
1933         if (*appData.boardSize == NULLCHAR) {
1934             while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1935                    DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1936               szd++;
1937             }
1938             if (szd->name == NULL) szd--;
1939         } else {
1940             while (szd->name != NULL &&
1941                    StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1942             if (szd->name == NULL) {
1943                 fprintf(stderr, "%s: unrecognized boardSize name %s\n",
1944                         programName, appData.boardSize);
1945                 exit(2);
1946             }
1947         }
1948         squareSize = szd->squareSize;
1949         lineGap = szd->lineGap;
1950         clockFontPxlSize = szd->clockFontPxlSize;
1951         coordFontPxlSize = szd->coordFontPxlSize;
1952         fontPxlSize = szd->fontPxlSize;
1953         smallLayout = szd->smallLayout;
1954         tinyLayout = szd->tinyLayout;
1955     }
1956
1957     /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1958     if (strlen(appData.pixmapDirectory) > 0) {
1959         p = ExpandPathName(appData.pixmapDirectory);
1960         if (!p) {
1961             fprintf(stderr, "Error expanding path name \"%s\"\n",
1962                    appData.pixmapDirectory);
1963             exit(1);
1964         }
1965         if (appData.debugMode) {
1966             fprintf(stderr, "XBoard square size (hint): %d\n", squareSize);
1967             fprintf(stderr, "%s fulldir:%s:\n", IMAGE_EXT, p);
1968         }
1969         squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1970         if (appData.debugMode) {
1971             fprintf(stderr, "Closest %s size: %d\n", IMAGE_EXT, squareSize);
1972         }
1973     }
1974                 
1975     boardWidth = lineGap + BOARD_SIZE * (squareSize + lineGap);
1976     if (appData.showJail == 1) {
1977         /* Jail on top and bottom */
1978         XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1979         XtSetArg(boardArgs[2], XtNheight,
1980                  boardWidth + 2*(lineGap + squareSize));
1981     } else if (appData.showJail == 2) {
1982         /* Jail on sides */
1983         XtSetArg(boardArgs[1], XtNwidth,
1984                  boardWidth + 2*(lineGap + squareSize));
1985         XtSetArg(boardArgs[2], XtNheight, boardWidth);
1986     } else {
1987         /* No jail */
1988         XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1989         XtSetArg(boardArgs[2], XtNheight, boardWidth);
1990     }
1991
1992     /*
1993      * Determine what fonts to use.
1994      */
1995     appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1996     clockFontID = XLoadFont(xDisplay, appData.clockFont);
1997     clockFontStruct = XQueryFont(xDisplay, clockFontID);
1998     appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1999     coordFontID = XLoadFont(xDisplay, appData.coordFont);
2000     coordFontStruct = XQueryFont(xDisplay, coordFontID);
2001     appData.font = FindFont(appData.font, fontPxlSize);
2002
2003     xdb = XtDatabase(xDisplay);
2004     XrmPutStringResource(&xdb, "*font", appData.font);
2005
2006     /*
2007      * Detect if there are not enough colors available and adapt.
2008      */
2009     if (DefaultDepth(xDisplay, xScreen) <= 2) {
2010       appData.monoMode = True;
2011     }
2012
2013     if (!appData.monoMode) {
2014         vFrom.addr = (caddr_t) appData.lightSquareColor;
2015         vFrom.size = strlen(appData.lightSquareColor);
2016         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2017         if (vTo.addr == NULL) {
2018           appData.monoMode = True;
2019           forceMono = True;
2020         } else {
2021           lightSquareColor = *(Pixel *) vTo.addr;
2022         }
2023     }
2024     if (!appData.monoMode) {
2025         vFrom.addr = (caddr_t) appData.darkSquareColor;
2026         vFrom.size = strlen(appData.darkSquareColor);
2027         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2028         if (vTo.addr == NULL) {
2029           appData.monoMode = True;
2030           forceMono = True;
2031         } else {
2032           darkSquareColor = *(Pixel *) vTo.addr;
2033         }
2034     }
2035     if (!appData.monoMode) {
2036         vFrom.addr = (caddr_t) appData.whitePieceColor;
2037         vFrom.size = strlen(appData.whitePieceColor);
2038         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2039         if (vTo.addr == NULL) {
2040           appData.monoMode = True;
2041           forceMono = True;
2042         } else {
2043           whitePieceColor = *(Pixel *) vTo.addr;
2044         }
2045     }
2046     if (!appData.monoMode) {
2047         vFrom.addr = (caddr_t) appData.blackPieceColor;
2048         vFrom.size = strlen(appData.blackPieceColor);
2049         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2050         if (vTo.addr == NULL) {
2051           appData.monoMode = True;
2052           forceMono = True;
2053         } else {
2054           blackPieceColor = *(Pixel *) vTo.addr;
2055         }
2056     }
2057
2058     if (!appData.monoMode) {
2059         vFrom.addr = (caddr_t) appData.highlightSquareColor;
2060         vFrom.size = strlen(appData.highlightSquareColor);
2061         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2062         if (vTo.addr == NULL) {
2063           appData.monoMode = True;
2064           forceMono = True;
2065         } else {
2066           highlightSquareColor = *(Pixel *) vTo.addr;
2067         }
2068     }
2069
2070     if (!appData.monoMode) {
2071         vFrom.addr = (caddr_t) appData.premoveHighlightColor;
2072         vFrom.size = strlen(appData.premoveHighlightColor);
2073         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2074         if (vTo.addr == NULL) {
2075           appData.monoMode = True;
2076           forceMono = True;
2077         } else {
2078           premoveHighlightColor = *(Pixel *) vTo.addr;
2079         }
2080     }
2081
2082     if (forceMono) {
2083       fprintf(stderr, "%s: too few colors available; trying monochrome mode\n",
2084               programName);
2085     }
2086
2087     if (appData.monoMode && appData.debugMode) {
2088         fprintf(stderr, "white pixel = 0x%lx, black pixel = 0x%lx\n",
2089                 (unsigned long) XWhitePixel(xDisplay, xScreen),
2090                 (unsigned long) XBlackPixel(xDisplay, xScreen));
2091     }
2092     
2093     if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2094         parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2095         parse_cpair(ColorChannel1, appData.colorChannel1) < 0  ||
2096         parse_cpair(ColorChannel, appData.colorChannel) < 0  ||
2097         parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2098         parse_cpair(ColorTell, appData.colorTell) < 0 ||
2099         parse_cpair(ColorChallenge, appData.colorChallenge) < 0  ||
2100         parse_cpair(ColorRequest, appData.colorRequest) < 0  ||
2101         parse_cpair(ColorSeek, appData.colorSeek) < 0  ||
2102         parse_cpair(ColorNormal, appData.colorNormal) < 0)
2103       {
2104           if (appData.colorize) {
2105               fprintf(stderr,
2106                       "%s: can't parse color names; disabling colorization\n",
2107                       programName);
2108           }
2109           appData.colorize = FALSE;
2110       }
2111     textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2112     textColors[ColorNone].attr = 0;
2113     
2114     XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2115     
2116     /*
2117      * widget hierarchy
2118      */
2119     if (tinyLayout) {
2120         layoutName = "tinyLayout";
2121     } else if (smallLayout) {
2122         layoutName = "smallLayout";
2123     } else {
2124         layoutName = "normalLayout";
2125     }
2126     /* Outer layoutWidget is there only to provide a name for use in
2127        resources that depend on the layout style */
2128     layoutWidget =
2129       XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2130                             layoutArgs, XtNumber(layoutArgs));
2131     formWidget =
2132       XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2133                             formArgs, XtNumber(formArgs));
2134     XtSetArg(args[0], XtNdefaultDistance, &sep);
2135     XtGetValues(formWidget, args, 1);
2136     
2137     j = 0;
2138     widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2139
2140     widgetList[j++] = whiteTimerWidget =
2141       XtCreateWidget("whiteTime", labelWidgetClass,
2142                      formWidget, timerArgs, XtNumber(timerArgs));
2143     XtSetArg(args[0], XtNfont, clockFontStruct);
2144     XtSetValues(whiteTimerWidget, args, 1);
2145     
2146     widgetList[j++] = blackTimerWidget =
2147       XtCreateWidget("blackTime", labelWidgetClass,
2148                      formWidget, timerArgs, XtNumber(timerArgs));
2149     XtSetArg(args[0], XtNfont, clockFontStruct);
2150     XtSetValues(blackTimerWidget, args, 1);
2151     
2152     if (appData.titleInWindow) {
2153         widgetList[j++] = titleWidget = 
2154           XtCreateWidget("title", labelWidgetClass, formWidget,
2155                          titleArgs, XtNumber(titleArgs));
2156     }
2157
2158     if (appData.showButtonBar) {
2159       widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2160     }
2161
2162     widgetList[j++] = messageWidget =
2163       XtCreateWidget("message", labelWidgetClass, formWidget,
2164                      messageArgs, XtNumber(messageArgs));
2165     
2166     widgetList[j++] = boardWidget =
2167       XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2168                      XtNumber(boardArgs));
2169
2170     XtManageChildren(widgetList, j);
2171     
2172     timerWidth = (boardWidth - sep) / 2;
2173     XtSetArg(args[0], XtNwidth, timerWidth);
2174     XtSetValues(whiteTimerWidget, args, 1);
2175     XtSetValues(blackTimerWidget, args, 1);
2176     
2177     XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2178     XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2179     XtGetValues(whiteTimerWidget, args, 2);
2180     
2181     if (appData.showButtonBar) {
2182       XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2183       XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2184       XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2185     }
2186
2187     /*
2188      * formWidget uses these constraints but they are stored
2189      * in the children.
2190      */
2191     i = 0;
2192     XtSetArg(args[i], XtNfromHoriz, 0); i++;
2193     XtSetValues(menuBarWidget, args, i);
2194     if (appData.titleInWindow) {
2195         if (smallLayout) {
2196             i = 0;
2197             XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2198             XtSetValues(whiteTimerWidget, args, i);
2199             i = 0;
2200             XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2201             XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2202             XtSetValues(blackTimerWidget, args, i);
2203             i = 0;
2204             XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2205             XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2206             XtSetValues(titleWidget, args, i);
2207             i = 0;
2208             XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2209             XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2210             XtSetValues(messageWidget, args, i);
2211             if (appData.showButtonBar) {
2212               i = 0;
2213               XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2214               XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2215               XtSetValues(buttonBarWidget, args, i);
2216             }
2217         } else {
2218             i = 0;
2219             XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2220             XtSetValues(whiteTimerWidget, args, i);
2221             i = 0;
2222             XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2223             XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2224             XtSetValues(blackTimerWidget, args, i);
2225             i = 0;
2226             XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2227             XtSetValues(titleWidget, args, i);
2228             i = 0;
2229             XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2230             XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2231             XtSetValues(messageWidget, args, i);
2232             if (appData.showButtonBar) {
2233               i = 0;
2234               XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2235               XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2236               XtSetValues(buttonBarWidget, args, i);
2237             }
2238         }
2239     } else {
2240         i = 0;
2241         XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2242         XtSetValues(whiteTimerWidget, args, i);
2243         i = 0;
2244         XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2245         XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2246         XtSetValues(blackTimerWidget, args, i);
2247         i = 0;
2248         XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2249         XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2250         XtSetValues(messageWidget, args, i);
2251         if (appData.showButtonBar) {
2252           i = 0;
2253           XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2254           XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2255           XtSetValues(buttonBarWidget, args, i);
2256         }
2257     }
2258     i = 0;
2259     XtSetArg(args[0], XtNfromVert, messageWidget);
2260     XtSetValues(boardWidget, args, 1);
2261
2262     XtRealizeWidget(shellWidget);
2263
2264     /*
2265      * Correct the width of the message and title widgets.
2266      * It is not known why some systems need the extra fudge term.
2267      * The value "2" is probably larger than needed.
2268      */
2269     XawFormDoLayout(formWidget, False);
2270 #define WIDTH_FUDGE 2
2271     i = 0;
2272     XtSetArg(args[i], XtNborderWidth, &bor);  i++;
2273     XtSetArg(args[i], XtNheight, &h);  i++;
2274     XtGetValues(messageWidget, args, i);
2275     if (appData.showButtonBar) {
2276       i = 0;
2277       XtSetArg(args[i], XtNwidth, &w);  i++;
2278       XtGetValues(buttonBarWidget, args, i);
2279       w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2280     } else {
2281       w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2282     }
2283
2284     gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2285     if (gres != XtGeometryYes && appData.debugMode) {
2286       fprintf(stderr, "%s: messageWidget geometry error %d %d %d %d %d\n",
2287               programName, gres, w, h, wr, hr);
2288     }
2289     
2290     /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2291     /* The size used for the child widget in layout lags one resize behind
2292        its true size, so we resize a second time, 1 pixel smaller.  Yeech! */
2293     w--;
2294     gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2295     if (gres != XtGeometryYes && appData.debugMode) {
2296       fprintf(stderr, "%s: messageWidget geometry error %d %d %d %d %d\n",
2297               programName, gres, w, h, wr, hr);
2298     }
2299     /* !! end hack */
2300
2301     if (appData.titleInWindow) {
2302         i = 0;
2303         XtSetArg(args[i], XtNborderWidth, &bor); i++;
2304         XtSetArg(args[i], XtNheight, &h);  i++;
2305         XtGetValues(titleWidget, args, i);
2306         if (smallLayout) {
2307             w = boardWidth - 2*bor;
2308         } else {
2309             XtSetArg(args[0], XtNwidth, &w);
2310             XtGetValues(menuBarWidget, args, 1);
2311             w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2312         }
2313
2314         gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2315         if (gres != XtGeometryYes && appData.debugMode) {
2316             fprintf(stderr,
2317                     "%s: titleWidget geometry error %d %d %d %d %d\n",
2318                     programName, gres, w, h, wr, hr);
2319         }
2320     }
2321     XawFormDoLayout(formWidget, True);
2322
2323     xBoardWindow = XtWindow(boardWidget);
2324     
2325     /* 
2326      * Create X checkmark bitmap and initialize option menu checks.
2327      */
2328     ReadBitmap(&xMarkPixmap, "checkmark.bm",
2329                checkmark_bits, checkmark_width, checkmark_height);
2330     XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2331     if (appData.alwaysPromoteToQueen) {
2332         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2333                     args, 1);
2334     }
2335     if (appData.animateDragging) {
2336         XtSetValues(XtNameToWidget(menuBarWidget,
2337                                    "menuOptions.Animate Dragging"),
2338                     args, 1);
2339     }
2340     if (appData.animate) {
2341         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2342                     args, 1);
2343     }
2344     if (appData.autoComment) {
2345         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2346                     args, 1);
2347     }
2348     if (appData.autoCallFlag) {
2349         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2350                     args, 1);
2351     }
2352     if (appData.autoFlipView) {
2353         XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2354                     args, 1);
2355     }
2356     if (appData.autoObserve) {
2357         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2358                     args, 1);
2359     }
2360     if (appData.autoRaiseBoard) {
2361         XtSetValues(XtNameToWidget(menuBarWidget,
2362                                    "menuOptions.Auto Raise Board"), args, 1);
2363     }
2364     if (appData.autoSaveGames) {
2365         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2366                     args, 1);
2367     }
2368     if (appData.saveGameFile[0] != NULLCHAR) {
2369         /* Can't turn this off from menu */
2370         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2371                     args, 1);
2372         XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2373                        False);
2374
2375     }
2376     if (appData.blindfold) {
2377         XtSetValues(XtNameToWidget(menuBarWidget,
2378                                    "menuOptions.Blindfold"), args, 1);
2379     }
2380     if (appData.flashCount > 0) {
2381         XtSetValues(XtNameToWidget(menuBarWidget,
2382                                    "menuOptions.Flash Moves"),
2383                     args, 1);
2384     }
2385     if (appData.getMoveList) {
2386         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2387                     args, 1);
2388     }
2389 #if HIGHDRAG
2390     if (appData.highlightDragging) {
2391         XtSetValues(XtNameToWidget(menuBarWidget,
2392                                    "menuOptions.Highlight Dragging"),
2393                     args, 1);
2394     }
2395 #endif
2396     if (appData.highlightLastMove) {
2397         XtSetValues(XtNameToWidget(menuBarWidget,
2398                                    "menuOptions.Highlight Last Move"),
2399                     args, 1);
2400     }
2401     if (appData.icsAlarm) {
2402         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2403                     args, 1);
2404     }
2405     if (appData.ringBellAfterMoves) {
2406         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2407                     args, 1);
2408     }
2409     if (appData.oldSaveStyle) {
2410         XtSetValues(XtNameToWidget(menuBarWidget,
2411                                    "menuOptions.Old Save Style"), args, 1);
2412     }
2413     if (appData.periodicUpdates) {
2414         XtSetValues(XtNameToWidget(menuBarWidget,
2415                                    "menuOptions.Periodic Updates"), args, 1);
2416     }   
2417     if (appData.ponderNextMove) {
2418         XtSetValues(XtNameToWidget(menuBarWidget,
2419                                    "menuOptions.Ponder Next Move"), args, 1);
2420     }   
2421     if (appData.popupExitMessage) {
2422         XtSetValues(XtNameToWidget(menuBarWidget,
2423                                    "menuOptions.Popup Exit Message"), args, 1);
2424     }   
2425     if (appData.popupMoveErrors) {
2426         XtSetValues(XtNameToWidget(menuBarWidget,
2427                                    "menuOptions.Popup Move Errors"), args, 1);
2428     }   
2429     if (appData.premove) {
2430         XtSetValues(XtNameToWidget(menuBarWidget,
2431                                    "menuOptions.Premove"), args, 1);
2432     }
2433     if (appData.quietPlay) {
2434         XtSetValues(XtNameToWidget(menuBarWidget,
2435                                    "menuOptions.Quiet Play"), args, 1);
2436     }
2437     if (appData.showCoords) {
2438         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2439                     args, 1);
2440     }
2441     if (appData.showThinking) {
2442         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Thinking"),
2443                     args, 1);
2444     }
2445     if (appData.testLegality) {
2446         XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2447                     args, 1);
2448     }
2449
2450     /*
2451      * Create an icon.
2452      */
2453     ReadBitmap(&wIconPixmap, "icon_white.bm",
2454                icon_white_bits, icon_white_width, icon_white_height);
2455     ReadBitmap(&bIconPixmap, "icon_black.bm",
2456                icon_black_bits, icon_black_width, icon_black_height);
2457     iconPixmap = wIconPixmap;
2458     i = 0;
2459     XtSetArg(args[i], XtNiconPixmap, iconPixmap);  i++;
2460     XtSetValues(shellWidget, args, i);
2461     
2462     /*
2463      * Create a cursor for the board widget.
2464      */
2465     window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2466     XChangeWindowAttributes(xDisplay, xBoardWindow,
2467                             CWCursor, &window_attributes);
2468     
2469     /*
2470      * Inhibit shell resizing.
2471      */
2472     shellArgs[0].value = (XtArgVal) &w;
2473     shellArgs[1].value = (XtArgVal) &h;
2474     XtGetValues(shellWidget, shellArgs, 2);
2475     shellArgs[4].value = shellArgs[2].value = w;
2476     shellArgs[5].value = shellArgs[3].value = h;
2477     XtSetValues(shellWidget, &shellArgs[2], 4);
2478     
2479     CatchDeleteWindow(shellWidget, "QuitProc");
2480
2481     CreateGCs();
2482     CreateGrid();
2483 #if HAVE_LIBXPM
2484     if (appData.bitmapDirectory[0] != NULLCHAR) {
2485       CreatePieces();
2486     } else {
2487       CreateXPMPieces();
2488     }
2489 #else
2490     CreateXIMPieces();
2491     /* Create regular pieces */
2492     if (!useImages) CreatePieces();
2493 #endif  
2494
2495     CreatePieceMenus();
2496
2497     if (appData.animate || appData.animateDragging)
2498       CreateAnimVars();
2499     
2500     XtAugmentTranslations(formWidget,
2501                           XtParseTranslationTable(globalTranslations));
2502     XtAugmentTranslations(boardWidget,
2503                           XtParseTranslationTable(boardTranslations));
2504     XtAugmentTranslations(whiteTimerWidget,
2505                           XtParseTranslationTable(whiteTranslations));
2506     XtAugmentTranslations(blackTimerWidget,
2507                           XtParseTranslationTable(blackTranslations));
2508
2509     /* Why is the following needed on some versions of X instead
2510      * of a translation? */
2511     XtAddEventHandler(boardWidget, ExposureMask, False,
2512                       (XtEventHandler) EventProc, NULL);
2513     /* end why */
2514
2515     InitBackEnd2();
2516     
2517     if (errorExitStatus == -1) {
2518         if (appData.icsActive) {
2519             /* We now wait until we see "login:" from the ICS before
2520                sending the logon script (problems with timestamp otherwise) */
2521             /*ICSInitScript();*/
2522             if (appData.icsInputBox) ICSInputBoxPopUp();
2523         }
2524
2525         signal(SIGINT, IntSigHandler);
2526         signal(SIGTERM, IntSigHandler);
2527         if (*appData.cmailGameName != NULLCHAR) {
2528             signal(SIGUSR1, CmailSigHandler);
2529         }
2530     }
2531
2532     XtAppMainLoop(appContext);
2533     return 0;
2534 }
2535
2536 void
2537 ShutDownFrontEnd()
2538 {
2539     if (appData.icsActive && oldICSInteractionTitle != NULL) {
2540         DisplayIcsInteractionTitle(oldICSInteractionTitle);
2541     }
2542     unlink(gameCopyFilename);
2543     unlink(gamePasteFilename);
2544 }
2545
2546 RETSIGTYPE
2547 IntSigHandler(sig)
2548      int sig;
2549 {
2550     ExitEvent(sig);
2551 }
2552
2553 RETSIGTYPE
2554 CmailSigHandler(sig)
2555      int sig;
2556 {
2557     int dummy = 0;
2558     int error;
2559
2560     signal(SIGUSR1, SIG_IGN);   /* suspend handler     */
2561
2562     /* Activate call-back function CmailSigHandlerCallBack()             */
2563     OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2564
2565     signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2566 }
2567
2568 void
2569 CmailSigHandlerCallBack(isr, closure, message, count, error)
2570      InputSourceRef isr;
2571      VOIDSTAR closure;
2572      char *message;
2573      int count;
2574      int error;
2575 {
2576     BoardToTop();
2577     ReloadCmailMsgEvent(TRUE);  /* Reload cmail msg  */
2578 }
2579 /**** end signal code ****/
2580
2581
2582 void
2583 ICSInitScript()
2584 {
2585     FILE *f;
2586     char buf[MSG_SIZ];
2587     char *p;
2588
2589     f = fopen(appData.icsLogon, "r");
2590     if (f == NULL) {
2591         p = getenv("HOME");
2592         if (p != NULL) {
2593             strcpy(buf, p);
2594             strcat(buf, "/");
2595             strcat(buf, appData.icsLogon);
2596             f = fopen(buf, "r");
2597         }
2598     }
2599     if (f != NULL)
2600       ProcessICSInitScript(f);
2601 }
2602
2603 void
2604 ResetFrontEnd()
2605 {
2606     CommentPopDown();
2607     EditCommentPopDown();
2608     TagsPopDown();
2609     return;
2610 }
2611
2612 typedef struct {
2613     char *name;
2614     Boolean value;
2615 } Enables;
2616
2617 void
2618 SetMenuEnables(enab)
2619      Enables *enab;
2620 {
2621   Widget w;
2622   if (!menuBarWidget) return;
2623   while (enab->name != NULL) {
2624     w = XtNameToWidget(menuBarWidget, enab->name);
2625     if (w == NULL) {
2626       DisplayError(enab->name, 0);
2627     } else {
2628       XtSetSensitive(w, enab->value);
2629     }
2630     enab++;
2631   }
2632 }
2633
2634 Enables icsEnables[] = {
2635     { "menuFile.Mail Move", False },
2636     { "menuFile.Reload CMail Message", False },
2637     { "menuMode.Machine Black", False },
2638     { "menuMode.Machine White", False },
2639     { "menuMode.Analysis Mode", False },
2640     { "menuMode.Analyze File", False },
2641     { "menuMode.Two Machines", False },
2642 #ifndef ZIPPY
2643     { "menuHelp.Hint", False },
2644     { "menuHelp.Book", False },
2645     { "menuStep.Move Now", False },
2646     { "menuOptions.Periodic Updates", False },  
2647     { "menuOptions.Show Thinking", False },
2648     { "menuOptions.Ponder Next Move", False },
2649 #endif
2650     { NULL, False }
2651 };
2652
2653 Enables ncpEnables[] = {    
2654     { "menuFile.Mail Move", False },
2655     { "menuFile.Reload CMail Message", False },
2656     { "menuMode.Machine White", False },
2657     { "menuMode.Machine Black", False },
2658     { "menuMode.Analysis Mode", False },
2659     { "menuMode.Analyze File", False },
2660     { "menuMode.Two Machines", False },
2661     { "menuMode.ICS Client", False },
2662     { "menuMode.ICS Input Box", False },
2663     { "Action", False },
2664     { "menuStep.Revert", False },
2665     { "menuStep.Move Now", False },
2666     { "menuStep.Retract Move", False },
2667     { "menuOptions.Auto Comment", False },
2668     { "menuOptions.Auto Flag", False },
2669     { "menuOptions.Auto Flip View", False },
2670     { "menuOptions.Auto Observe", False },
2671     { "menuOptions.Auto Raise Board", False },
2672     { "menuOptions.Get Move List", False },
2673     { "menuOptions.ICS Alarm", False },
2674     { "menuOptions.Move Sound", False },
2675     { "menuOptions.Quiet Play", False },
2676     { "menuOptions.Show Thinking", False },
2677     { "menuOptions.Periodic Updates", False },  
2678     { "menuOptions.Ponder Next Move", False },
2679     { "menuHelp.Hint", False },
2680     { "menuHelp.Book", False },
2681     { NULL, False }
2682 };
2683
2684 Enables gnuEnables[] = {    
2685     { "menuMode.ICS Client", False },
2686     { "menuMode.ICS Input Box", False },
2687     { "menuAction.Accept", False },
2688     { "menuAction.Decline", False },
2689     { "menuAction.Rematch", False },
2690     { "menuAction.Adjourn", False },
2691     { "menuAction.Stop Examining", False },
2692     { "menuAction.Stop Observing", False },
2693     { "menuStep.Revert", False },
2694     { "menuOptions.Auto Comment", False },
2695     { "menuOptions.Auto Observe", False },
2696     { "menuOptions.Auto Raise Board", False },
2697     { "menuOptions.Get Move List", False },
2698     { "menuOptions.Premove", False },
2699     { "menuOptions.Quiet Play", False },
2700
2701     /* The next two options rely on SetCmailMode being called *after*    */
2702     /* SetGNUMode so that when GNU is being used to give hints these     */
2703     /* menu options are still available                                  */
2704
2705     { "menuFile.Mail Move", False },
2706     { "menuFile.Reload CMail Message", False },
2707     { NULL, False }
2708 };
2709
2710 Enables cmailEnables[] = {    
2711     { "Action", True },
2712     { "menuAction.Call Flag", False },
2713     { "menuAction.Draw", True },
2714     { "menuAction.Adjourn", False },
2715     { "menuAction.Abort", False },
2716     { "menuAction.Stop Observing", False },
2717     { "menuAction.Stop Examining", False },
2718     { "menuFile.Mail Move", True },
2719     { "menuFile.Reload CMail Message", True },
2720     { NULL, False }
2721 };
2722
2723 Enables trainingOnEnables[] = {    
2724   { "menuMode.Edit Comment", False },
2725   { "menuMode.Pause", False },
2726   { "menuStep.Forward", False },
2727   { "menuStep.Backward", False },
2728   { "menuStep.Forward to End", False },
2729   { "menuStep.Back to Start", False },
2730   { "menuStep.Move Now", False },
2731   { "menuStep.Truncate Game", False },
2732   { NULL, False }
2733 };
2734
2735 Enables trainingOffEnables[] = {    
2736   { "menuMode.Edit Comment", True },
2737   { "menuMode.Pause", True },
2738   { "menuStep.Forward", True },
2739   { "menuStep.Backward", True },
2740   { "menuStep.Forward to End", True },
2741   { "menuStep.Back to Start", True },
2742   { "menuStep.Move Now", True },
2743   { "menuStep.Truncate Game", True },
2744   { NULL, False }
2745 };
2746
2747 Enables machineThinkingEnables[] = {
2748   { "menuFile.Load Game", False },
2749   { "menuFile.Load Next Game", False },
2750   { "menuFile.Load Previous Game", False },
2751   { "menuFile.Reload Same Game", False },
2752   { "menuFile.Paste Game", False },
2753   { "menuFile.Load Position", False },
2754   { "menuFile.Load Next Position", False },
2755   { "menuFile.Load Previous Position", False },
2756   { "menuFile.Reload Same Position", False },
2757   { "menuFile.Paste Position", False },
2758   { "menuMode.Machine White", False },
2759   { "menuMode.Machine Black", False },
2760   { "menuMode.Two Machines", False },
2761   { "menuStep.Retract Move", False },
2762   { NULL, False }
2763 };
2764
2765 Enables userThinkingEnables[] = {
2766   { "menuFile.Load Game", True },
2767   { "menuFile.Load Next Game", True },
2768   { "menuFile.Load Previous Game", True },
2769   { "menuFile.Reload Same Game", True },
2770   { "menuFile.Paste Game", True },
2771   { "menuFile.Load Position", True },
2772   { "menuFile.Load Next Position", True },
2773   { "menuFile.Load Previous Position", True },
2774   { "menuFile.Reload Same Position", True },
2775   { "menuFile.Paste Position", True },
2776   { "menuMode.Machine White", True },
2777   { "menuMode.Machine Black", True },
2778   { "menuMode.Two Machines", True },
2779   { "menuStep.Retract Move", True },
2780   { NULL, False }
2781 };
2782
2783 void SetICSMode()
2784 {
2785   SetMenuEnables(icsEnables);
2786 }
2787
2788 void
2789 SetNCPMode()
2790 {
2791   SetMenuEnables(ncpEnables);
2792 }
2793
2794 void
2795 SetGNUMode()
2796 {
2797   SetMenuEnables(gnuEnables);
2798 }
2799
2800 void
2801 SetCmailMode()
2802 {
2803   SetMenuEnables(cmailEnables);
2804 }
2805
2806 void
2807 SetTrainingModeOn()
2808 {
2809   SetMenuEnables(trainingOnEnables);
2810   if (appData.showButtonBar) {
2811     XtSetSensitive(buttonBarWidget, False);
2812   }
2813   CommentPopDown();
2814 }
2815
2816 void
2817 SetTrainingModeOff()
2818 {
2819   SetMenuEnables(trainingOffEnables);
2820   if (appData.showButtonBar) {
2821     XtSetSensitive(buttonBarWidget, True);
2822   }
2823 }
2824
2825 void
2826 SetUserThinkingEnables()
2827 {
2828   if (appData.noChessProgram) return;
2829   SetMenuEnables(userThinkingEnables);
2830 }
2831
2832 void
2833 SetMachineThinkingEnables()
2834 {
2835   if (appData.noChessProgram) return;
2836   SetMenuEnables(machineThinkingEnables);
2837   switch (gameMode) {
2838   case MachinePlaysBlack:
2839   case MachinePlaysWhite:
2840   case TwoMachinesPlay:
2841     XtSetSensitive(XtNameToWidget(menuBarWidget,
2842                                   ModeToWidgetName(gameMode)), True);
2843     break;
2844   default:
2845     break;
2846   }
2847 }
2848
2849 #define Abs(n) ((n)<0 ? -(n) : (n))
2850
2851 /*
2852  * Find a font that matches "pattern" that is as close as
2853  * possible to the targetPxlSize.  Prefer fonts that are k
2854  * pixels smaller to fonts that are k pixels larger.  The
2855  * pattern must be in the X Consortium standard format, 
2856  * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2857  * The return value should be freed with XtFree when no
2858  * longer needed.
2859  */
2860 char *FindFont(pattern, targetPxlSize)
2861      char *pattern;
2862      int targetPxlSize;
2863 {
2864     char **fonts, *p, *best, *scalable, *scalableTail;
2865     int i, j, nfonts, minerr, err, pxlSize;
2866
2867     fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2868     if (nfonts < 1) {
2869         fprintf(stderr, "%s: no fonts match pattern %s\n",
2870                 programName, pattern);
2871         exit(2);
2872     }
2873     best = fonts[0];
2874     scalable = NULL;
2875     minerr = 999999;
2876     for (i=0; i<nfonts; i++) {
2877         j = 0;
2878         p = fonts[i];
2879         if (*p != '-') continue;
2880         while (j < 7) {
2881             if (*p == NULLCHAR) break;
2882             if (*p++ == '-') j++;
2883         }
2884         if (j < 7) continue;
2885         pxlSize = atoi(p);
2886         if (pxlSize == 0) {
2887             scalable = fonts[i];
2888             scalableTail = p;
2889         } else {
2890             err = pxlSize - targetPxlSize;
2891             if (Abs(err) < Abs(minerr) ||
2892                 (minerr > 0 && err < 0 && -err == minerr)) {
2893                 best = fonts[i];
2894                 minerr = err;
2895             }
2896         }
2897     }
2898     if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
2899         /* If the error is too big and there is a scalable font,
2900            use the scalable font. */
2901         int headlen = scalableTail - scalable;
2902         p = (char *) XtMalloc(strlen(scalable) + 10);
2903         while (isdigit(*scalableTail)) scalableTail++;
2904         sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
2905     } else {
2906         p = (char *) XtMalloc(strlen(best) + 1);
2907         strcpy(p, best);
2908     }
2909     if (appData.debugMode) {
2910         fprintf(debugFP, "resolved %s at pixel size %d\n  to %s\n",
2911                 pattern, targetPxlSize, p);
2912     }
2913     XFreeFontNames(fonts);
2914     return p;
2915 }
2916
2917 void CreateGCs()
2918 {
2919     XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
2920       | GCBackground | GCFunction | GCPlaneMask;
2921     XGCValues gc_values;
2922     GC copyInvertedGC;
2923     
2924     gc_values.plane_mask = AllPlanes;
2925     gc_values.line_width = lineGap;
2926     gc_values.line_style = LineSolid;
2927     gc_values.function = GXcopy;
2928     
2929     gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2930     gc_values.background = XBlackPixel(xDisplay, xScreen);
2931     lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2932     
2933     gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2934     gc_values.background = XWhitePixel(xDisplay, xScreen);
2935     coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
2936     XSetFont(xDisplay, coordGC, coordFontID);
2937     
2938     if (appData.monoMode) {
2939         gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2940         gc_values.background = XWhitePixel(xDisplay, xScreen);
2941         highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);      
2942
2943         gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2944         gc_values.background = XBlackPixel(xDisplay, xScreen);
2945         lightSquareGC = wbPieceGC 
2946           = XtGetGC(shellWidget, value_mask, &gc_values);
2947
2948         gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2949         gc_values.background = XWhitePixel(xDisplay, xScreen);
2950         darkSquareGC = bwPieceGC
2951           = XtGetGC(shellWidget, value_mask, &gc_values);
2952
2953         if (DefaultDepth(xDisplay, xScreen) == 1) {
2954             /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
2955             gc_values.function = GXcopyInverted;
2956             copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
2957             gc_values.function = GXcopy;
2958             if (XBlackPixel(xDisplay, xScreen) == 1) {
2959                 bwPieceGC = darkSquareGC;
2960                 wbPieceGC = copyInvertedGC;
2961             } else {
2962                 bwPieceGC = copyInvertedGC;
2963                 wbPieceGC = lightSquareGC;
2964             }
2965         }
2966     } else {
2967         gc_values.foreground = highlightSquareColor;
2968         gc_values.background = highlightSquareColor;
2969         highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);      
2970
2971         gc_values.foreground = premoveHighlightColor;
2972         gc_values.background = premoveHighlightColor;
2973         prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);       
2974
2975         gc_values.foreground = lightSquareColor;
2976         gc_values.background = darkSquareColor;
2977         lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2978         
2979         gc_values.foreground = darkSquareColor;
2980         gc_values.background = lightSquareColor;
2981         darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2982
2983         gc_values.foreground = jailSquareColor;
2984         gc_values.background = jailSquareColor;
2985         jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2986
2987         gc_values.foreground = whitePieceColor;
2988         gc_values.background = darkSquareColor;
2989         wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
2990         
2991         gc_values.foreground = whitePieceColor;
2992         gc_values.background = lightSquareColor;
2993         wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
2994         
2995         gc_values.foreground = whitePieceColor;
2996         gc_values.background = jailSquareColor;
2997         wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
2998         
2999         gc_values.foreground = blackPieceColor;
3000         gc_values.background = darkSquareColor;
3001         bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3002         
3003         gc_values.foreground = blackPieceColor;
3004         gc_values.background = lightSquareColor;
3005         blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3006
3007         gc_values.foreground = blackPieceColor;
3008         gc_values.background = jailSquareColor;
3009         bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3010     }
3011 }
3012
3013 void loadXIM(xim, xmask, filename, dest, mask)
3014      XImage *xim;
3015      XImage *xmask;
3016      char *filename;
3017      Pixmap *dest;
3018      Pixmap *mask;
3019 {
3020     int x, y, w, h, p;
3021     FILE *fp;
3022     Pixmap temp;
3023     XGCValues   values;
3024     GC maskGC;
3025
3026     fp = fopen(filename, "rb");
3027     if (!fp) {
3028         fprintf(stderr, "%s: error loading XIM!\n", programName);
3029         exit(1);
3030     }
3031           
3032     w = fgetc(fp);
3033     h = fgetc(fp);
3034   
3035     for (y=0; y<h; ++y) {
3036         for (x=0; x<h; ++x) {
3037             p = fgetc(fp);
3038
3039             switch (p) {
3040               case 0:   
3041                 XPutPixel(xim, x, y, blackPieceColor); 
3042                 if (xmask)
3043                   XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3044                 break;
3045               case 1:   
3046                 XPutPixel(xim, x, y, darkSquareColor); 
3047                 if (xmask)
3048                   XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3049                 break;
3050               case 2:   
3051                 XPutPixel(xim, x, y, whitePieceColor); 
3052                 if (xmask)
3053                   XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3054                 break;
3055               case 3:   
3056                 XPutPixel(xim, x, y, lightSquareColor);
3057                 if (xmask)
3058                   XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3059                 break;
3060             }
3061         }
3062     }
3063
3064     /* create Pixmap of piece */
3065     *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3066                           w, h, xim->depth);
3067     XPutImage(xDisplay, *dest, lightSquareGC, xim,
3068               0, 0, 0, 0, w, h);  
3069
3070     /* create Pixmap of clipmask 
3071        Note: We assume the white/black pieces have the same
3072              outline, so we make only 6 masks. This is okay
3073              since the XPM clipmask routines do the same. */
3074     if (xmask) {
3075       temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3076                             w, h, xim->depth);
3077       XPutImage(xDisplay, temp, lightSquareGC, xmask,
3078               0, 0, 0, 0, w, h);  
3079
3080       /* now create the 1-bit version */
3081       *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3082                           w, h, 1);
3083
3084       values.foreground = 1;
3085       values.background = 0;
3086
3087       /* Don't use XtGetGC, not read only */
3088       maskGC = XCreateGC(xDisplay, *mask, 
3089                     GCForeground | GCBackground, &values);
3090       XCopyPlane(xDisplay, temp, *mask, maskGC, 
3091                   0, 0, squareSize, squareSize, 0, 0, 1);
3092       XFreePixmap(xDisplay, temp);
3093     }
3094 }
3095
3096 void CreateXIMPieces()
3097 {
3098     int piece, kind;
3099     char buf[MSG_SIZ];
3100     u_int ss;
3101     static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3102     XImage *ximtemp;
3103
3104     ss = squareSize;
3105
3106     /* The XSynchronize calls were copied from CreatePieces.
3107        Not sure if needed, but can't hurt */
3108     XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3109                                      buffering bug */
3110   
3111     /* temp needed by loadXIM() */
3112     ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3113                  0, 0, ss, ss, AllPlanes, XYPixmap);
3114
3115     if (strlen(appData.pixmapDirectory) == 0) {
3116       useImages = 0;
3117     } else {
3118         useImages = 1;
3119         if (appData.monoMode) {
3120           DisplayFatalError("XIM pieces cannot be used in monochrome mode",
3121                             0, 2);
3122           ExitEvent(2);
3123         }
3124         fprintf(stderr, "\nLoading XIMs...\n");
3125         /* Load pieces */
3126         for (piece = (int) WhitePawn; piece <= (int) WhiteKing; piece++) {
3127             fprintf(stderr, "%d", piece+1);
3128             for (kind=0; kind<4; kind++) {
3129                 fprintf(stderr, ".");
3130                 sprintf(buf, "%s/%c%s%u.xim",
3131                         ExpandPathName(appData.pixmapDirectory),
3132                         ToLower(PieceToChar((ChessSquare)piece)),
3133                         ximkind[kind], ss);
3134                 ximPieceBitmap[kind][piece] =
3135                   XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3136                             0, 0, ss, ss, AllPlanes, XYPixmap);
3137                 if (appData.debugMode)
3138                   fprintf(stderr, "(File:%s:) ", buf);
3139                 loadXIM(ximPieceBitmap[kind][piece], 
3140                         ximtemp, buf,
3141                         &(xpmPieceBitmap[kind][piece]),
3142                         &(ximMaskPm[piece%6]));
3143             }
3144             fprintf(stderr," ");
3145         }
3146         /* Load light and dark squares */
3147         /* If the LSQ and DSQ pieces don't exist, we will 
3148            draw them with solid squares. */
3149         sprintf(buf, "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3150         if (access(buf, 0) != 0) {
3151             useImageSqs = 0;
3152         } else {
3153             useImageSqs = 1;
3154             fprintf(stderr, "light square ");
3155             ximLightSquare= 
3156               XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3157                         0, 0, ss, ss, AllPlanes, XYPixmap);
3158             if (appData.debugMode)
3159               fprintf(stderr, "(File:%s:) ", buf);
3160
3161             loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3162             fprintf(stderr, "dark square ");
3163             sprintf(buf, "%s/dsq%u.xim",
3164                     ExpandPathName(appData.pixmapDirectory), ss);
3165             if (appData.debugMode)
3166               fprintf(stderr, "(File:%s:) ", buf);
3167             ximDarkSquare= 
3168               XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3169                         0, 0, ss, ss, AllPlanes, XYPixmap);
3170             loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3171             xpmJailSquare = xpmLightSquare;
3172         }
3173         fprintf(stderr, "Done.\n");
3174     }
3175     XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3176 }
3177
3178 #if HAVE_LIBXPM
3179 void CreateXPMPieces()
3180 {
3181     int piece, kind, r;
3182     char buf[MSG_SIZ];
3183     u_int ss = squareSize;
3184     XpmAttributes attr;
3185     static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3186     XpmColorSymbol symbols[4];
3187
3188 #if 0
3189     /* Apparently some versions of Xpm don't define XpmFormat at all --tpm */
3190     if (appData.debugMode) {
3191         fprintf(stderr, "XPM Library Version: %d.%d%c\n", 
3192                 XpmFormat, XpmVersion, (char)('a' + XpmRevision - 1));
3193     }
3194 #endif
3195   
3196     /* The XSynchronize calls were copied from CreatePieces.
3197        Not sure if needed, but can't hurt */
3198     XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3199   
3200     /* Setup translations so piece colors match square colors */
3201     symbols[0].name = "light_piece";
3202     symbols[0].value = appData.whitePieceColor;
3203     symbols[1].name = "dark_piece";
3204     symbols[1].value = appData.blackPieceColor;
3205     symbols[2].name = "light_square";
3206     symbols[2].value = appData.lightSquareColor;
3207     symbols[3].name = "dark_square";
3208     symbols[3].value = appData.darkSquareColor;
3209
3210     attr.valuemask = XpmColorSymbols;
3211     attr.colorsymbols = symbols;
3212     attr.numsymbols = 4;
3213
3214     if (appData.monoMode) {
3215       DisplayFatalError("XPM pieces cannot be used in monochrome mode",
3216                         0, 2);
3217       ExitEvent(2);
3218     }
3219     if (strlen(appData.pixmapDirectory) == 0) {
3220         XpmPieces* pieces = builtInXpms;
3221         useImages = 1;
3222         /* Load pieces */
3223         while (pieces->size != squareSize && pieces->size) pieces++;
3224         if (!pieces->size) {
3225           fprintf(stderr, "No builtin XPM pieces of size %d\n", squareSize);
3226           exit(1);
3227         }
3228         for (piece = (int) WhitePawn; piece <= (int) WhiteKing; piece++) {
3229             for (kind=0; kind<4; kind++) {
3230
3231                 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3232                                                pieces->xpm[piece][kind],
3233                                                &(xpmPieceBitmap[kind][piece]),
3234                                                NULL, &attr)) != 0) {
3235                   fprintf(stderr, "Error %d loading XPM image \"%s\"\n",
3236                           r, buf);
3237                   exit(1); 
3238                 }       
3239             }   
3240         }
3241         useImageSqs = 0;
3242         xpmJailSquare = xpmLightSquare;
3243     } else {
3244         useImages = 1;
3245         
3246         fprintf(stderr, "\nLoading XPMs...\n");
3247
3248         /* Load pieces */
3249         for (piece = (int) WhitePawn; piece <= (int) WhiteKing; piece++) {
3250             fprintf(stderr, "%d ", piece+1);
3251             for (kind=0; kind<4; kind++) {
3252                 sprintf(buf, "%s/%c%s%u.xpm",
3253                         ExpandPathName(appData.pixmapDirectory),
3254                         ToLower(PieceToChar((ChessSquare)piece)),
3255                         xpmkind[kind], ss);
3256                 if (appData.debugMode) {
3257                     fprintf(stderr, "(File:%s:) ", buf);
3258                 }
3259                 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3260                                            &(xpmPieceBitmap[kind][piece]),
3261                                            NULL, &attr)) != 0) {
3262                     fprintf(stderr, "Error %d loading XPM file \"%s\"\n",
3263                             r, buf);
3264                     exit(1); 
3265                 }       
3266             }   
3267         }
3268         /* Load light and dark squares */
3269         /* If the LSQ and DSQ pieces don't exist, we will 
3270            draw them with solid squares. */
3271         fprintf(stderr, "light square ");
3272         sprintf(buf, "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3273         if (access(buf, 0) != 0) {
3274             useImageSqs = 0;
3275         } else {
3276             useImageSqs = 1;
3277             if (appData.debugMode)
3278               fprintf(stderr, "(File:%s:) ", buf);
3279
3280             if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3281                                        &xpmLightSquare, NULL, &attr)) != 0) {
3282                 fprintf(stderr, "Error %d loading XPM file \"%s\"\n", r, buf);
3283                 exit(1);
3284             }
3285             fprintf(stderr, "dark square ");
3286             sprintf(buf, "%s/dsq%u.xpm",
3287                     ExpandPathName(appData.pixmapDirectory), ss);
3288             if (appData.debugMode) {
3289                 fprintf(stderr, "(File:%s:) ", buf);
3290             }
3291             if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3292                                        &xpmDarkSquare, NULL, &attr)) != 0) {
3293                 fprintf(stderr, "Error %d loading XPM file \"%s\"\n", r, buf);
3294                 exit(1);
3295             }
3296         }
3297         xpmJailSquare = xpmLightSquare;
3298         fprintf(stderr, "Done.\n");
3299     }
3300     XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3301                                       buffering bug */  
3302 }
3303 #endif /* HAVE_LIBXPM */
3304
3305 #if HAVE_LIBXPM
3306 /* No built-in bitmaps */
3307 void CreatePieces()
3308 {
3309     int piece, kind;
3310     char buf[MSG_SIZ];
3311     u_int ss = squareSize;
3312         
3313     XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3314                                      buffering bug */
3315
3316     for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3317         for (piece = (int) WhitePawn; piece <= (int) WhiteKing; piece++) {
3318             sprintf(buf, "%c%u%c.bm", ToLower(PieceToChar((ChessSquare)piece)),
3319                     ss, kind == SOLID ? 's' : 'o');
3320             ReadBitmap(&pieceBitmap[kind][piece], buf, NULL, ss, ss);
3321         }
3322     }
3323     
3324     XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3325                                       buffering bug */
3326 }
3327 #else
3328 /* With built-in bitmaps */
3329 void CreatePieces()
3330 {
3331     BuiltInBits* bib = builtInBits;
3332     int piece, kind;
3333     char buf[MSG_SIZ];
3334     u_int ss = squareSize;
3335         
3336     XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3337                                      buffering bug */
3338
3339     while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3340
3341     for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3342         for (piece = (int) WhitePawn; piece <= (int) WhiteKing; piece++) {
3343             sprintf(buf, "%c%u%c.bm", ToLower(PieceToChar((ChessSquare)piece)),
3344                     ss, kind == SOLID ? 's' : 'o');
3345             ReadBitmap(&pieceBitmap[kind][piece], buf,
3346                        bib->bits[kind][piece], ss, ss);
3347         }
3348     }
3349     
3350     XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3351                                       buffering bug */
3352 }
3353 #endif
3354
3355 void ReadBitmap(pm, name, bits, wreq, hreq)
3356      Pixmap *pm;
3357      String name;
3358      unsigned char bits[];
3359      u_int wreq, hreq;
3360 {
3361     int x_hot, y_hot;
3362     u_int w, h;
3363     int errcode;
3364     char msg[MSG_SIZ], fullname[MSG_SIZ];
3365     
3366     if (*appData.bitmapDirectory != NULLCHAR) {
3367         strcpy(fullname, appData.bitmapDirectory);
3368         strcat(fullname, "/");
3369         strcat(fullname, name);
3370         errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3371                                   &w, &h, pm, &x_hot, &y_hot);
3372         if (errcode != BitmapSuccess) {
3373             switch (errcode) {
3374               case BitmapOpenFailed:
3375                 sprintf(msg, "Can't open bitmap file %s", fullname);
3376                 break;
3377               case BitmapFileInvalid:
3378                 sprintf(msg, "Invalid bitmap in file %s", fullname);
3379                 break;
3380               case BitmapNoMemory:
3381                 sprintf(msg, "Ran out of memory reading bitmap file %s",
3382                         fullname);
3383                 break;
3384               default:
3385                 sprintf(msg, "Unknown XReadBitmapFile error %d on file %s",
3386                         errcode, fullname);
3387                 break;
3388             }
3389             fprintf(stderr, "%s: %s...using built-in\n",
3390                     programName, msg);
3391         } else if (w != wreq || h != hreq) {
3392             fprintf(stderr,
3393                     "%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n",
3394                     programName, fullname, w, h, wreq, hreq);
3395         } else {
3396             return;
3397         }
3398     }
3399     if (bits == NULL) {
3400         fprintf(stderr, "%s: No built-in bitmap for %s; giving up\n",
3401                 programName, name);
3402         exit(1);
3403     } else {
3404         *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3405                                     wreq, hreq);
3406     }
3407 }
3408
3409 void CreateGrid()
3410 {
3411     int i;
3412     
3413     if (lineGap == 0) return;
3414     for (i = 0; i < BOARD_SIZE + 1; i++) {
3415         gridSegments[i].x1 = 0;
3416         gridSegments[i].x2 =
3417           lineGap + BOARD_SIZE * (squareSize + lineGap);
3418         gridSegments[i].y1 = gridSegments[i].y2
3419           = lineGap / 2 + (i * (squareSize + lineGap));
3420
3421         gridSegments[i + BOARD_SIZE + 1].y1 = 0;
3422         gridSegments[i + BOARD_SIZE + 1].y2 =
3423           BOARD_SIZE * (squareSize + lineGap);
3424         gridSegments[i + BOARD_SIZE + 1].x1 =
3425           gridSegments[i + BOARD_SIZE + 1].x2
3426             = lineGap / 2 + (i * (squareSize + lineGap));
3427     }
3428 }
3429
3430 static void MenuBarSelect(w, addr, index)
3431      Widget w;
3432      caddr_t addr;
3433      caddr_t index;
3434 {
3435     XtActionProc proc = (XtActionProc) addr;
3436
3437     (proc)(NULL, NULL, NULL, NULL);
3438 }
3439
3440 void CreateMenuBarPopup(parent, name, mb)
3441      Widget parent;
3442      String name;
3443      Menu *mb;
3444 {
3445     int j;
3446     Widget menu, entry;
3447     MenuItem *mi;
3448     Arg args[16];
3449
3450     menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3451                               parent, NULL, 0);
3452     j = 0;
3453     XtSetArg(args[j], XtNleftMargin, 20);   j++;
3454     XtSetArg(args[j], XtNrightMargin, 20);  j++;
3455     mi = mb->mi;
3456     while (mi->string != NULL) {
3457         if (strcmp(mi->string, "----") == 0) {
3458             entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3459                                           menu, args, j);
3460         } else {
3461             entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3462                                           menu, args, j);
3463             XtAddCallback(entry, XtNcallback,
3464                           (XtCallbackProc) MenuBarSelect,
3465                           (caddr_t) mi->proc);
3466         }
3467         mi++;
3468     }
3469 }       
3470
3471 Widget CreateMenuBar(mb)
3472      Menu *mb;
3473 {
3474     int j;
3475     Widget anchor, menuBar;
3476     Arg args[16];
3477     char menuName[MSG_SIZ];
3478
3479     j = 0;
3480     XtSetArg(args[j], XtNorientation, XtorientHorizontal);  j++;
3481     XtSetArg(args[j], XtNvSpace, 0);                        j++;
3482     XtSetArg(args[j], XtNborderWidth, 0);                   j++;
3483     menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3484                              formWidget, args, j);
3485
3486     while (mb->name != NULL) {
3487         strcpy(menuName, "menu");
3488         strcat(menuName, mb->name);
3489         j = 0;
3490         XtSetArg(args[j], XtNmenuName, XtNewString(menuName));  j++;
3491         if (tinyLayout) {
3492             char shortName[2];
3493             shortName[0] = mb->name[0];
3494             shortName[1] = NULLCHAR;
3495             XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3496         }
3497         XtSetArg(args[j], XtNborderWidth, 0);                   j++;
3498         anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3499                                        menuBar, args, j);
3500         CreateMenuBarPopup(menuBar, menuName, mb);
3501         mb++;
3502     }
3503     return menuBar;
3504 }
3505
3506 Widget CreateButtonBar(mi)
3507      MenuItem *mi;
3508 {
3509     int j;
3510     Widget button, buttonBar;
3511     Arg args[16];
3512
3513     j = 0;
3514     XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3515     if (tinyLayout) {
3516         XtSetArg(args[j], XtNhSpace, 0); j++;
3517     }
3518     XtSetArg(args[j], XtNborderWidth, 0); j++;
3519     XtSetArg(args[j], XtNvSpace, 0);                        j++;
3520     buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3521                                formWidget, args, j);
3522
3523     while (mi->string != NULL) {
3524         j = 0;
3525         if (tinyLayout) {
3526             XtSetArg(args[j], XtNinternalWidth, 2); j++;
3527             XtSetArg(args[j], XtNborderWidth, 0); j++;
3528         }
3529         button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3530                                        buttonBar, args, j);
3531         XtAddCallback(button, XtNcallback,
3532                       (XtCallbackProc) MenuBarSelect,
3533                       (caddr_t) mi->proc);
3534         mi++;
3535     }
3536     return buttonBar;
3537 }     
3538
3539 Widget
3540 CreatePieceMenu(name, color)
3541      char *name;
3542      int color;
3543 {
3544     int i;
3545     Widget entry, menu;
3546     Arg args[16];
3547     ChessSquare selection;
3548
3549     menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3550                               boardWidget, args, 0);
3551     
3552     for (i = 0; i < PIECE_MENU_SIZE; i++) {
3553         String item = pieceMenuStrings[color][i];
3554         
3555         if (strcmp(item, "----") == 0) {
3556             entry = XtCreateManagedWidget(item, smeLineObjectClass,
3557                                           menu, NULL, 0);
3558         } else {
3559             entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3560                                           menu, NULL, 0);
3561             selection = pieceMenuTranslation[color][i];
3562             XtAddCallback(entry, XtNcallback,
3563                           (XtCallbackProc) PieceMenuSelect,
3564                           (caddr_t) selection);
3565             if (selection == WhitePawn || selection == BlackPawn) {
3566                 XtSetArg(args[0], XtNpopupOnEntry, entry);
3567                 XtSetValues(menu, args, 1);
3568             }
3569         }
3570     }
3571     return menu;
3572 }
3573
3574 void
3575 CreatePieceMenus()
3576 {
3577     int i;
3578     Widget entry;
3579     Arg args[16];
3580     ChessSquare selection;
3581
3582     whitePieceMenu = CreatePieceMenu("menuW", 0);
3583     blackPieceMenu = CreatePieceMenu("menuB", 1);
3584     
3585     XtRegisterGrabAction(PieceMenuPopup, True,
3586                          (unsigned)(ButtonPressMask|ButtonReleaseMask),
3587                          GrabModeAsync, GrabModeAsync);
3588
3589     XtSetArg(args[0], XtNlabel, "Drop");
3590     dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3591                                   boardWidget, args, 1);
3592     for (i = 0; i < DROP_MENU_SIZE; i++) {
3593         String item = dropMenuStrings[i];
3594         
3595         if (strcmp(item, "----") == 0) {
3596             entry = XtCreateManagedWidget(item, smeLineObjectClass,
3597                                           dropMenu, NULL, 0);
3598         } else {
3599             entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3600                                           dropMenu, NULL, 0);
3601             selection = dropMenuTranslation[i];
3602             XtAddCallback(entry, XtNcallback,
3603                           (XtCallbackProc) DropMenuSelect,
3604                           (caddr_t) selection);
3605         }
3606     }
3607 }       
3608
3609 void SetupDropMenu()
3610 {
3611     int i, j, count;
3612     char label[32];
3613     Arg args[16];
3614     Widget entry;
3615     char* p;
3616
3617     for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3618         entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3619         p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3620                    dmEnables[i].piece);
3621         XtSetSensitive(entry, p != NULL || !appData.testLegality
3622                        /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3623                                        && !appData.icsActive));
3624         count = 0;
3625         while (p && *p++ == dmEnables[i].piece) count++;
3626         sprintf(label, "%s  %d", dmEnables[i].widget, count);
3627         j = 0;
3628         XtSetArg(args[j], XtNlabel, label); j++;
3629         XtSetValues(entry, args, j);
3630     }
3631 }
3632
3633 void PieceMenuPopup(w, event, params, num_params)
3634      Widget w;
3635      XEvent *event;
3636      String *params;
3637      Cardinal *num_params;
3638 {
3639     String whichMenu;
3640     if (event->type != ButtonPress) return;
3641     if (errorUp) ErrorPopDown();
3642     switch (gameMode) {
3643       case EditPosition:
3644       case IcsExamining:
3645         whichMenu = params[0];
3646         break;
3647       case IcsPlayingWhite:
3648       case IcsPlayingBlack:
3649       case EditGame:
3650       case MachinePlaysWhite:
3651       case MachinePlaysBlack:
3652         if (appData.testLegality &&
3653             gameInfo.variant != VariantBughouse &&
3654             gameInfo.variant != VariantCrazyhouse) return;
3655         SetupDropMenu();
3656         whichMenu = "menuD";
3657         break;
3658       default:
3659         return;
3660     }
3661     
3662     if (((pmFromX = EventToSquare(event->xbutton.x, BOARD_SIZE)) < 0) ||
3663         ((pmFromY = EventToSquare(event->xbutton.y, BOARD_SIZE)) < 0)) {
3664         pmFromX = pmFromY = -1;
3665         return;
3666     }
3667     if (flipView)
3668       pmFromX = BOARD_SIZE - 1 - pmFromX;
3669     else
3670       pmFromY = BOARD_SIZE - 1 - pmFromY;
3671     
3672     XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3673 }
3674
3675 static void PieceMenuSelect(w, piece, junk)
3676      Widget w;
3677      ChessSquare piece;
3678      caddr_t junk;
3679 {
3680     if (pmFromX < 0 || pmFromY < 0) return;
3681     EditPositionMenuEvent(piece, pmFromX, pmFromY);
3682 }
3683
3684 static void DropMenuSelect(w, piece, junk)
3685      Widget w;
3686      ChessSquare piece;
3687      caddr_t junk;
3688 {
3689     if (pmFromX < 0 || pmFromY < 0) return;
3690     DropMenuEvent(piece, pmFromX, pmFromY);
3691 }
3692
3693 void WhiteClock(w, event, prms, nprms)
3694      Widget w;
3695      XEvent *event;
3696      String *prms;
3697      Cardinal *nprms;
3698 {
3699     if (gameMode == EditPosition || gameMode == IcsExamining) {
3700         SetWhiteToPlayEvent();
3701     } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3702         CallFlagEvent();
3703     }
3704 }
3705
3706 void BlackClock(w, event, prms, nprms)
3707      Widget w;
3708      XEvent *event;
3709      String *prms;
3710      Cardinal *nprms;
3711 {
3712     if (gameMode == EditPosition || gameMode == IcsExamining) {
3713         SetBlackToPlayEvent();
3714     } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3715         CallFlagEvent();
3716     }
3717 }
3718
3719
3720 /*
3721  * If the user selects on a border boundary, return -1; if off the board,
3722  *   return -2.  Otherwise map the event coordinate to the square.
3723  */
3724 int EventToSquare(x, limit)
3725      int x;
3726 {
3727     if (x <= 0) 
3728       return -2;
3729     if (x < lineGap)
3730       return -1;
3731     x -= lineGap;
3732     if ((x % (squareSize + lineGap)) >= squareSize)
3733       return -1;
3734     x /= (squareSize + lineGap);
3735     if (x >= limit)
3736       return -2;
3737     return x;
3738 }
3739
3740 static void do_flash_delay(msec)
3741      unsigned long msec;
3742 {
3743     TimeDelay(msec);
3744 }
3745
3746 static void drawHighlight(file, rank, gc)
3747      int file, rank;
3748      GC gc;
3749 {
3750     int x, y;
3751
3752     if (lineGap == 0 || appData.blindfold) return;
3753     
3754     if (flipView) {
3755         x = lineGap/2 + ((BOARD_SIZE-1)-file) * 
3756           (squareSize + lineGap);
3757         y = lineGap/2 + rank * (squareSize + lineGap);
3758     } else {
3759         x = lineGap/2 + file * (squareSize + lineGap);
3760         y = lineGap/2 + ((BOARD_SIZE-1)-rank) * 
3761           (squareSize + lineGap);
3762     }
3763     
3764     XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3765                    squareSize+lineGap, squareSize+lineGap);
3766 }
3767
3768 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3769 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3770
3771 void
3772 SetHighlights(fromX, fromY, toX, toY)
3773      int fromX, fromY, toX, toY;
3774 {
3775     if (hi1X != fromX || hi1Y != fromY) {
3776         if (hi1X >= 0 && hi1Y >= 0) {
3777             drawHighlight(hi1X, hi1Y, lineGC);
3778         }
3779         if (fromX >= 0 && fromY >= 0) {
3780             drawHighlight(fromX, fromY, highlineGC);
3781         }
3782     }
3783     if (hi2X != toX || hi2Y != toY) {
3784         if (hi2X >= 0 && hi2Y >= 0) {
3785             drawHighlight(hi2X, hi2Y, lineGC);
3786         }
3787         if (toX >= 0 && toY >= 0) {
3788             drawHighlight(toX, toY, highlineGC);
3789         }
3790     }
3791     hi1X = fromX;
3792     hi1Y = fromY;
3793     hi2X = toX;
3794     hi2Y = toY;
3795 }
3796
3797 void
3798 ClearHighlights()
3799 {
3800     SetHighlights(-1, -1, -1, -1);
3801 }
3802
3803
3804 void
3805 SetPremoveHighlights(fromX, fromY, toX, toY)
3806      int fromX, fromY, toX, toY;
3807 {
3808     if (pm1X != fromX || pm1Y != fromY) {
3809         if (pm1X >= 0 && pm1Y >= 0) {
3810             drawHighlight(pm1X, pm1Y, lineGC);
3811         }
3812         if (fromX >= 0 && fromY >= 0) {
3813             drawHighlight(fromX, fromY, prelineGC);
3814         }
3815     }
3816     if (pm2X != toX || pm2Y != toY) {
3817         if (pm2X >= 0 && pm2Y >= 0) {
3818             drawHighlight(pm2X, pm2Y, lineGC);
3819         }
3820         if (toX >= 0 && toY >= 0) {
3821             drawHighlight(toX, toY, prelineGC);
3822         }
3823     }
3824     pm1X = fromX;
3825     pm1Y = fromY;
3826     pm2X = toX;
3827     pm2Y = toY;
3828 }
3829
3830 void
3831 ClearPremoveHighlights()
3832 {
3833   SetPremoveHighlights(-1, -1, -1, -1);
3834 }
3835
3836 static void BlankSquare(x, y, color, piece, dest)
3837      int x, y, color;
3838      ChessSquare piece;
3839      Drawable dest;
3840 {
3841     if (useImages && useImageSqs) {
3842         Pixmap pm;
3843         switch (color) {
3844           case 1: /* light */
3845             pm = xpmLightSquare;
3846             break;
3847           case 0: /* dark */
3848             pm = xpmDarkSquare;
3849             break;
3850           case 2: /* neutral */
3851           default:
3852             pm = xpmJailSquare;
3853             break;
3854         }
3855         XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
3856                   squareSize, squareSize, x, y);
3857     } else {
3858         GC gc;
3859         switch (color) {
3860           case 1: /* light */
3861             gc = lightSquareGC;
3862             break;
3863           case 0: /* dark */
3864             gc = darkSquareGC;
3865             break;
3866           case 2: /* neutral */
3867           default:
3868             gc = jailSquareGC;
3869             break;
3870         }
3871         XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
3872     }
3873 }
3874
3875 /*
3876    I split out the routines to draw a piece so that I could
3877    make a generic flash routine.
3878 */
3879 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
3880      ChessSquare piece;
3881      int square_color, x, y;
3882      Drawable dest;
3883 {
3884     /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3885     switch (square_color) {
3886       case 1: /* light */
3887       case 2: /* neutral */
3888       default:
3889         XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3890                   ? *pieceToOutline(piece)
3891                   : *pieceToSolid(piece),
3892                   dest, bwPieceGC, 0, 0,
3893                   squareSize, squareSize, x, y);
3894         break;
3895       case 0: /* dark */
3896         XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3897                   ? *pieceToSolid(piece)
3898                   : *pieceToOutline(piece),
3899                   dest, wbPieceGC, 0, 0,
3900                   squareSize, squareSize, x, y);
3901         break;
3902     }
3903 }
3904
3905 static void monoDrawPiece(piece, square_color, x, y, dest)
3906      ChessSquare piece;
3907      int square_color, x, y;
3908      Drawable dest;
3909 {
3910     switch (square_color) {
3911       case 1: /* light */
3912       case 2: /* neutral */
3913       default:
3914         XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3915                    ? *pieceToOutline(piece)
3916                    : *pieceToSolid(piece),
3917                    dest, bwPieceGC, 0, 0,
3918                    squareSize, squareSize, x, y, 1);
3919         break;
3920       case 0: /* dark */
3921         XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3922                    ? *pieceToSolid(piece)
3923                    : *pieceToOutline(piece),
3924                    dest, wbPieceGC, 0, 0,
3925                    squareSize, squareSize, x, y, 1);
3926         break;
3927     }
3928 }
3929
3930 static void colorDrawPiece(piece, square_color, x, y, dest)
3931      ChessSquare piece;
3932      int square_color, x, y;
3933      Drawable dest;
3934 {
3935     switch (square_color) {
3936       case 1: /* light */
3937         XCopyPlane(xDisplay, *pieceToSolid(piece),
3938                    dest, (int) piece < (int) BlackPawn
3939                    ? wlPieceGC : blPieceGC, 0, 0,
3940                    squareSize, squareSize, x, y, 1);
3941         break;
3942       case 0: /* dark */
3943         XCopyPlane(xDisplay, *pieceToSolid(piece),
3944                    dest, (int) piece < (int) BlackPawn
3945                    ? wdPieceGC : bdPieceGC, 0, 0,
3946                    squareSize, squareSize, x, y, 1);
3947         break;
3948       case 2: /* neutral */
3949       default:
3950         XCopyPlane(xDisplay, *pieceToSolid(piece),
3951                    dest, (int) piece < (int) BlackPawn
3952                    ? wjPieceGC : bjPieceGC, 0, 0,
3953                    squareSize, squareSize, x, y, 1);
3954         break;
3955     }
3956 }
3957
3958 static void colorDrawPieceImage(piece, square_color, x, y, dest)
3959      ChessSquare piece;
3960      int square_color, x, y;
3961      Drawable dest;
3962 {
3963     int kind;
3964
3965     switch (square_color) {
3966       case 1: /* light */
3967       case 2: /* neutral */
3968       default:
3969         if ((int)piece < (int) BlackPawn) {
3970             kind = 0;
3971         } else {
3972             kind = 2;
3973             piece -= BlackPawn;
3974         }
3975         break;
3976       case 0: /* dark */
3977         if ((int)piece < (int) BlackPawn) {
3978             kind = 1;
3979         } else {
3980             kind = 3;
3981             piece -= BlackPawn;
3982         }
3983         break;
3984     }
3985     XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
3986               dest, wlPieceGC, 0, 0,
3987               squareSize, squareSize, x, y);            
3988 }
3989
3990 typedef void (*DrawFunc)();
3991
3992 DrawFunc ChooseDrawFunc()
3993 {
3994     if (appData.monoMode) {
3995         if (DefaultDepth(xDisplay, xScreen) == 1) {
3996             return monoDrawPiece_1bit;
3997         } else {
3998             return monoDrawPiece;
3999         }
4000     } else {
4001         if (useImages)
4002           return colorDrawPieceImage;
4003         else
4004           return colorDrawPiece;
4005     }
4006 }
4007
4008 void DrawSquare(row, column, piece, do_flash)
4009      int row, column, do_flash;
4010      ChessSquare piece;
4011 {
4012     int square_color, x, y, direction, font_ascent, font_descent;
4013     int i;
4014     char string[2];
4015     XCharStruct overall;
4016     DrawFunc drawfunc;
4017     int flash_delay;
4018
4019     /* Calculate delay in milliseconds (2-delays per complete flash) */
4020     flash_delay = 500 / appData.flashRate;
4021         
4022     if (flipView) {
4023         x = lineGap + ((BOARD_SIZE-1)-column) * 
4024           (squareSize + lineGap);
4025         y = lineGap + row * (squareSize + lineGap);
4026     } else {
4027         x = lineGap + column * (squareSize + lineGap);
4028         y = lineGap + ((BOARD_SIZE-1)-row) * 
4029           (squareSize + lineGap);
4030     }
4031     
4032     square_color = ((column + row) % 2) == 1;
4033     
4034     if (piece == EmptySquare || appData.blindfold) {
4035         BlankSquare(x, y, square_color, piece, xBoardWindow);
4036     } else {
4037         drawfunc = ChooseDrawFunc();
4038         if (do_flash && appData.flashCount > 0) {
4039             for (i=0; i<appData.flashCount; ++i) {
4040
4041                 drawfunc(piece, square_color, x, y, xBoardWindow);
4042                 XSync(xDisplay, False);
4043                 do_flash_delay(flash_delay);
4044
4045                 BlankSquare(x, y, square_color, piece, xBoardWindow);
4046                 XSync(xDisplay, False);
4047                 do_flash_delay(flash_delay);
4048             }
4049         }
4050         drawfunc(piece, square_color, x, y, xBoardWindow);
4051     }
4052         
4053     string[1] = NULLCHAR;
4054     if (appData.showCoords && row == (flipView ? 7 : 0)) {
4055         string[0] = 'a' + column;
4056         XTextExtents(coordFontStruct, string, 1, &direction, 
4057                      &font_ascent, &font_descent, &overall);
4058         if (appData.monoMode) {
4059             XDrawImageString(xDisplay, xBoardWindow, coordGC,
4060                              x + squareSize - overall.width - 2, 
4061                              y + squareSize - font_descent - 1, string, 1);
4062         } else {
4063             XDrawString(xDisplay, xBoardWindow, coordGC,
4064                         x + squareSize - overall.width - 2, 
4065                         y + squareSize - font_descent - 1, string, 1);
4066         }
4067     }
4068     if (appData.showCoords && column == (flipView ? 7 : 0)) {
4069         string[0] = '1' + row;
4070         XTextExtents(coordFontStruct, string, 1, &direction, 
4071                      &font_ascent, &font_descent, &overall);
4072         if (appData.monoMode) {
4073             XDrawImageString(xDisplay, xBoardWindow, coordGC,
4074                              x + 2, y + font_ascent + 1, string, 1);
4075         } else {
4076             XDrawString(xDisplay, xBoardWindow, coordGC,
4077                         x + 2, y + font_ascent + 1, string, 1);
4078         }           
4079     }   
4080 }
4081
4082
4083 /* Why is this needed on some versions of X? */
4084 void EventProc(widget, unused, event)
4085      Widget widget;
4086      caddr_t unused;
4087      XEvent *event;
4088 {
4089     if (!XtIsRealized(widget))
4090       return;
4091
4092     switch (event->type) {
4093       case Expose:
4094         if (event->xexpose.count > 0) return;  /* no clipping is done */
4095         XDrawPosition(widget, True, NULL);
4096         break;
4097       default:
4098         return;
4099     }
4100 }
4101 /* end why */
4102
4103 void DrawPosition(fullRedraw, board)
4104      /*Boolean*/int fullRedraw;
4105      Board board;
4106 {
4107     XDrawPosition(boardWidget, fullRedraw, board);
4108 }
4109
4110 /* Returns 1 if there are "too many" differences between b1 and b2
4111    (i.e. more than 1 move was made) */
4112 static int too_many_diffs(b1, b2)
4113      Board b1, b2;
4114 {
4115     int i, j;
4116     int c = 0;
4117   
4118     for (i=0; i<BOARD_SIZE; ++i) {
4119         for (j=0; j<BOARD_SIZE; ++j) {
4120             if (b1[i][j] != b2[i][j]) {
4121                 if (++c > 4)    /* Castling causes 4 diffs */
4122                   return 1;
4123             }
4124         }
4125     }
4126
4127     return 0;
4128 }
4129
4130 /* Matrix describing castling maneuvers */
4131 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4132 static int castling_matrix[4][5] = {
4133     { 0, 0, 4, 3, 2 },          /* 0-0-0, white */
4134     { 0, 7, 4, 5, 6 },          /* 0-0,   white */
4135     { 7, 0, 4, 3, 2 },          /* 0-0-0, black */
4136     { 7, 7, 4, 5, 6 }           /* 0-0,   black */
4137 };
4138
4139 /* Checks whether castling occurred. If it did, *rrow and *rcol
4140    are set to the destination (row,col) of the rook that moved.
4141    
4142    Returns 1 if castling occurred, 0 if not.
4143    
4144    Note: Only handles a max of 1 castling move, so be sure
4145    to call too_many_diffs() first.
4146    */
4147 static int check_castle_draw(newb, oldb, rrow, rcol)
4148      Board newb, oldb;
4149      int *rrow, *rcol;
4150 {
4151     int i, *r, j;
4152     int match;
4153