Fix ToDo item #406
[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
4154     /* For each type of castling... */
4155     for (i=0; i<4; ++i) {
4156         r = castling_matrix[i];
4157
4158         /* Check the 4 squares involved in the castling move */
4159         match = 0;
4160         for (j=1; j<=4; ++j) {
4161             if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4162                 match = 1;
4163                 break;
4164             }
4165         }
4166
4167         if (!match) {
4168             /* All 4 changed, so it must be a castling move */
4169             *rrow = r[0];
4170             *rcol = r[3];
4171             return 1;
4172         }
4173     }
4174     return 0;
4175 }
4176
4177 static int damage[BOARD_SIZE][BOARD_SIZE];
4178
4179 /*
4180  * event handler for redrawing the board
4181  */
4182 void XDrawPosition(w, repaint, board)
4183      Widget w;
4184      /*Boolean*/int repaint;
4185      Board board;
4186 {
4187     int i, j, do_flash;
4188     static int lastFlipView = 0;
4189     static int lastBoardValid = 0;
4190     static Board lastBoard;
4191     Arg args[16];
4192     int rrow, rcol;
4193     
4194     if (board == NULL) {
4195         if (!lastBoardValid) return;
4196         board = lastBoard;
4197     }
4198     if (!lastBoardValid || lastFlipView != flipView) {
4199         XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4200         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4201                     args, 1);
4202     }
4203
4204     /*
4205      * It would be simpler to clear the window with XClearWindow()
4206      * but this causes a very distracting flicker.
4207      */
4208     
4209     if (!repaint && lastBoardValid && lastFlipView == flipView) {
4210
4211         /* If too much changes (begin observing new game, etc.), don't
4212            do flashing */
4213         do_flash = too_many_diffs(board, lastBoard) ? 0 : 1;
4214
4215         /* Special check for castling so we don't flash both the king
4216            and the rook (just flash the king). */
4217         if (do_flash) {
4218             if (check_castle_draw(board, lastBoard, &rrow, &rcol)) {
4219                 /* Draw rook with NO flashing. King will be drawn flashing later */
4220                 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4221                 lastBoard[rrow][rcol] = board[rrow][rcol];
4222             }
4223         }
4224
4225         /* First pass -- Draw (newly) empty squares and repair damage. 
4226            This prevents you from having a piece show up twice while it 
4227            is flashing on its new square */
4228         for (i = 0; i < BOARD_SIZE; i++)
4229           for (j = 0; j < BOARD_SIZE; j++)
4230             if ((board[i][j] != lastBoard[i][j] && board[i][j] == EmptySquare)
4231                 || damage[i][j]) {
4232                 DrawSquare(i, j, board[i][j], 0);
4233                 damage[i][j] = False;
4234             }
4235
4236         /* Second pass -- Draw piece(s) in new position and flash them */
4237         for (i = 0; i < BOARD_SIZE; i++)
4238           for (j = 0; j < BOARD_SIZE; j++)
4239             if (board[i][j] != lastBoard[i][j]) {
4240                 DrawSquare(i, j, board[i][j], do_flash);          
4241             }
4242     } else {
4243         if (lineGap > 0)
4244           XDrawSegments(xDisplay, xBoardWindow, lineGC,
4245                         gridSegments, (BOARD_SIZE + 1) * 2);
4246         
4247         for (i = 0; i < BOARD_SIZE; i++)
4248           for (j = 0; j < BOARD_SIZE; j++) {
4249               DrawSquare(i, j, board[i][j], 0);
4250               damage[i][j] = False;
4251           }
4252     }
4253
4254     CopyBoard(lastBoard, board);
4255     lastBoardValid = 1;
4256     lastFlipView = flipView;
4257
4258     /* Draw highlights */
4259     if (pm1X >= 0 && pm1Y >= 0) {
4260       drawHighlight(pm1X, pm1Y, prelineGC);
4261     }
4262     if (pm2X >= 0 && pm2Y >= 0) {
4263       drawHighlight(pm2X, pm2Y, prelineGC);
4264     }
4265     if (hi1X >= 0 && hi1Y >= 0) {
4266       drawHighlight(hi1X, hi1Y, highlineGC);
4267     }
4268     if (hi2X >= 0 && hi2Y >= 0) {
4269       drawHighlight(hi2X, hi2Y, highlineGC);
4270     }
4271
4272     /* If piece being dragged around board, must redraw that too */
4273     DrawDragPiece();
4274
4275     XSync(xDisplay, False);
4276 }
4277
4278
4279 /*
4280  * event handler for redrawing the board
4281  */
4282 void DrawPositionProc(w, event, prms, nprms)
4283      Widget w;
4284      XEvent *event;
4285      String *prms;
4286      Cardinal *nprms;
4287 {
4288     XDrawPosition(w, True, NULL);
4289 }
4290
4291
4292 /*
4293  * event handler for parsing user moves
4294  */
4295 void HandleUserMove(w, event, prms, nprms)
4296      Widget w;
4297      XEvent *event;
4298      String *prms;
4299      Cardinal *nprms;
4300 {
4301     int x, y;
4302     Boolean saveAnimate;
4303     static int second = 0;
4304         
4305     if (w != boardWidget || errorExitStatus != -1) return;
4306
4307     if (event->type == ButtonPress) ErrorPopDown();
4308
4309     if (promotionUp) {
4310         if (event->type == ButtonPress) {
4311             XtPopdown(promotionShell);
4312             XtDestroyWidget(promotionShell);
4313             promotionUp = False;
4314             ClearHighlights();
4315             fromX = fromY = -1;
4316         } else {
4317             return;
4318         }
4319     }
4320     
4321     x = EventToSquare(event->xbutton.x, BOARD_SIZE);
4322     y = EventToSquare(event->xbutton.y, BOARD_SIZE);
4323     if (!flipView && y >= 0) {
4324         y = BOARD_SIZE - 1 - y;
4325     }
4326     if (flipView && x >= 0) {
4327         x = BOARD_SIZE - 1 - x;
4328     }
4329
4330     if (fromX == -1) {
4331         if (event->type == ButtonPress) {
4332             /* First square */ 
4333             if (OKToStartUserMove(x, y)) {
4334                 fromX = x;
4335                 fromY = y;
4336                 second = 0;
4337                 DragPieceBegin(event->xbutton.x, event->xbutton.y);
4338                 if (appData.highlightDragging) {
4339                     SetHighlights(x, y, -1, -1);
4340                 }
4341             } 
4342         }
4343         return;
4344     }
4345
4346     /* fromX != -1 */
4347     if (event->type == ButtonPress && gameMode != EditPosition &&
4348         x >= 0 && y >= 0) {
4349         ChessSquare fromP;
4350         ChessSquare toP;
4351         /* Check if clicking again on the same color piece */
4352         fromP = boards[currentMove][fromY][fromX];
4353         toP = boards[currentMove][y][x];
4354         if ((WhitePawn <= fromP && fromP <= WhiteKing &&
4355              WhitePawn <= toP && toP <= WhiteKing) ||
4356             (BlackPawn <= fromP && fromP <= BlackKing &&
4357              BlackPawn <= toP && toP <= BlackKing)) {
4358             /* Clicked again on same color piece -- changed his mind */
4359             second = (x == fromX && y == fromY);
4360             if (appData.highlightDragging) {
4361                 SetHighlights(x, y, -1, -1);
4362             } else {
4363                 ClearHighlights();
4364             }
4365             if (OKToStartUserMove(x, y)) {
4366                 fromX = x;
4367                 fromY = y;
4368                 DragPieceBegin(event->xbutton.x, event->xbutton.y);
4369             }
4370             return;
4371         }
4372     }
4373
4374     if (event->type == ButtonRelease && x == fromX && y == fromY) {
4375         DragPieceEnd(event->xbutton.x, event->xbutton.y);
4376         if (appData.animateDragging) {
4377             /* Undo animation damage if any */
4378             DrawPosition(FALSE, NULL);
4379         }
4380         if (second) {
4381             /* Second up/down in same square; just abort move */
4382             second = 0;
4383             fromX = fromY = -1;
4384             ClearHighlights();
4385             gotPremove = 0;
4386             ClearPremoveHighlights();
4387         } else {
4388             /* First upclick in same square; start click-click mode */
4389             SetHighlights(x, y, -1, -1);
4390         }
4391         return;
4392     }   
4393
4394     /* Completed move */
4395     toX = x;
4396     toY = y;
4397     saveAnimate = appData.animate;
4398     if (event->type == ButtonPress) {
4399         /* Finish clickclick move */
4400         if (appData.animate || appData.highlightLastMove) {
4401             SetHighlights(fromX, fromY, toX, toY);
4402         } else {
4403             ClearHighlights();
4404         }
4405     } else {
4406         /* Finish drag move */
4407         if (appData.highlightLastMove) {
4408             SetHighlights(fromX, fromY, toX, toY);
4409         } else {
4410             ClearHighlights();
4411         }
4412         DragPieceEnd(event->xbutton.x, event->xbutton.y);
4413         /* Don't animate move and drag both */
4414         appData.animate = FALSE;
4415     }
4416     if (IsPromotion(fromX, fromY, toX, toY)) {
4417         if (appData.alwaysPromoteToQueen) {
4418             UserMoveEvent(fromX, fromY, toX, toY, 'q');
4419             if (!appData.highlightLastMove || gotPremove) ClearHighlights();
4420             if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
4421             fromX = fromY = -1;
4422         } else {
4423             SetHighlights(fromX, fromY, toX, toY);
4424             PromotionPopUp();
4425         }
4426     } else {
4427         UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR);
4428         if (!appData.highlightLastMove || gotPremove) ClearHighlights();
4429         if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
4430         fromX = fromY = -1;
4431     }
4432     appData.animate = saveAnimate;
4433     if (appData.animate || appData.animateDragging) {
4434         /* Undo animation damage if needed */
4435         DrawPosition(FALSE, NULL);
4436     }
4437 }
4438
4439 void AnimateUserMove (Widget w, XEvent * event,
4440                       String * params, Cardinal * nParams)
4441 {
4442     DragPieceMove(event->xmotion.x, event->xmotion.y);
4443 }
4444
4445 Widget CommentCreate(name, text, mutable, callback, lines)
4446      char *name, *text;
4447      int /*Boolean*/ mutable;
4448      XtCallbackProc callback;
4449      int lines;
4450 {
4451     Arg args[16];
4452     Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4453     Dimension bw_width;
4454     int j;
4455
4456     j = 0;
4457     XtSetArg(args[j], XtNwidth, &bw_width);  j++;
4458     XtGetValues(boardWidget, args, j);
4459
4460     j = 0;
4461     XtSetArg(args[j], XtNresizable, True);  j++;
4462 #if TOPLEVEL
4463     shell =
4464       XtCreatePopupShell(name, topLevelShellWidgetClass,
4465                          shellWidget, args, j);
4466 #else
4467     shell =
4468       XtCreatePopupShell(name, transientShellWidgetClass,
4469                          shellWidget, args, j);
4470 #endif
4471     layout =
4472       XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4473                             layoutArgs, XtNumber(layoutArgs));
4474     form =
4475       XtCreateManagedWidget("form", formWidgetClass, layout,
4476                             formArgs, XtNumber(formArgs));
4477
4478     j = 0;
4479     if (mutable) {
4480         XtSetArg(args[j], XtNeditType, XawtextEdit);  j++;
4481         XtSetArg(args[j], XtNuseStringInPlace, False);  j++;
4482     }
4483     XtSetArg(args[j], XtNstring, text);  j++;
4484     XtSetArg(args[j], XtNtop, XtChainTop);  j++;
4485     XtSetArg(args[j], XtNbottom, XtChainBottom);  j++;
4486     XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
4487     XtSetArg(args[j], XtNright, XtChainRight);  j++;
4488     XtSetArg(args[j], XtNresizable, True);  j++;
4489     XtSetArg(args[j], XtNwidth, bw_width);  j++; /*force wider than buttons*/
4490 #if 0
4491     XtSetArg(args[j], XtNscrollVertical, XawtextScrollWhenNeeded);  j++;
4492 #else
4493     /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4494     XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways);  j++;
4495 #endif
4496     XtSetArg(args[j], XtNautoFill, True);  j++;
4497     XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4498     edit =
4499       XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4500
4501     if (mutable) {
4502         j = 0;
4503         XtSetArg(args[j], XtNfromVert, edit);  j++;
4504         XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4505         XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4506         XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4507         XtSetArg(args[j], XtNright, XtChainLeft); j++;
4508         b_ok =
4509           XtCreateManagedWidget("ok", commandWidgetClass, form, args, j);
4510         XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4511
4512         j = 0;
4513         XtSetArg(args[j], XtNfromVert, edit);  j++;
4514         XtSetArg(args[j], XtNfromHoriz, b_ok);  j++;
4515         XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4516         XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4517         XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4518         XtSetArg(args[j], XtNright, XtChainLeft); j++;
4519         b_cancel =
4520           XtCreateManagedWidget("cancel", commandWidgetClass, form, args, j);
4521         XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4522
4523         j = 0;
4524         XtSetArg(args[j], XtNfromVert, edit);  j++;
4525         XtSetArg(args[j], XtNfromHoriz, b_cancel);  j++;
4526         XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4527         XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4528         XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4529         XtSetArg(args[j], XtNright, XtChainLeft); j++;
4530         b_clear =
4531           XtCreateManagedWidget("clear", commandWidgetClass, form, args, j);
4532         XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4533     } else {
4534         j = 0;
4535         XtSetArg(args[j], XtNfromVert, edit);  j++;
4536         XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4537         XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4538         XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4539         XtSetArg(args[j], XtNright, XtChainLeft); j++;
4540         b_close =
4541           XtCreateManagedWidget("close", commandWidgetClass, form, args, j);
4542         XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4543
4544         j = 0;
4545         XtSetArg(args[j], XtNfromVert, edit);  j++;
4546         XtSetArg(args[j], XtNfromHoriz, b_close);  j++;
4547         XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4548         XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4549         XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4550         XtSetArg(args[j], XtNright, XtChainLeft); j++;
4551         b_edit =
4552           XtCreateManagedWidget("edit", commandWidgetClass, form, args, j);
4553         XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4554     }
4555
4556     XtRealizeWidget(shell);
4557
4558     if (commentX == -1) {
4559         int xx, yy;
4560         Window junk;
4561         Dimension pw_height;
4562         Dimension ew_height;
4563
4564         j = 0;
4565         XtSetArg(args[j], XtNheight, &ew_height);  j++;
4566         XtGetValues(edit, args, j);
4567
4568         j = 0;
4569         XtSetArg(args[j], XtNheight, &pw_height);  j++;
4570         XtGetValues(shell, args, j);
4571         commentH = pw_height + (lines - 1) * ew_height;
4572         commentW = bw_width - 16;
4573
4574         XSync(xDisplay, False);
4575 #ifdef NOTDEF
4576         /* This code seems to tickle an X bug if it is executed too soon
4577            after xboard starts up.  The coordinates get transformed as if
4578            the main window was positioned at (0, 0).
4579            */
4580         XtTranslateCoords(shellWidget,
4581                           (bw_width - commentW) / 2, 0 - commentH / 2,
4582                           &commentX, &commentY);
4583 #else  /*!NOTDEF*/
4584         XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4585                               RootWindowOfScreen(XtScreen(shellWidget)),
4586                               (bw_width - commentW) / 2, 0 - commentH / 2,
4587                               &xx, &yy, &junk);
4588         commentX = xx;
4589         commentY = yy;
4590 #endif /*!NOTDEF*/
4591         if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4592     }
4593     j = 0;
4594     XtSetArg(args[j], XtNheight, commentH);  j++;
4595     XtSetArg(args[j], XtNwidth, commentW);  j++;
4596     XtSetArg(args[j], XtNx, commentX);  j++;
4597     XtSetArg(args[j], XtNy, commentY);  j++;
4598     XtSetValues(shell, args, j);
4599     XtSetKeyboardFocus(shell, edit);
4600
4601     return shell;
4602 }
4603
4604 /* Used for analysis window and ICS input window */
4605 Widget MiscCreate(name, text, mutable, callback, lines)
4606      char *name, *text;
4607      int /*Boolean*/ mutable;
4608      XtCallbackProc callback;
4609      int lines;
4610 {
4611     Arg args[16];
4612     Widget shell, layout, form, edit;
4613     Position x, y;
4614     Dimension bw_width, pw_height, ew_height, w, h;
4615     int j;
4616     int xx, yy;
4617     Window junk;
4618
4619     j = 0;
4620     XtSetArg(args[j], XtNresizable, True);  j++;
4621 #if TOPLEVEL
4622     shell =
4623       XtCreatePopupShell(name, topLevelShellWidgetClass,
4624                          shellWidget, args, j);
4625 #else
4626     shell =
4627       XtCreatePopupShell(name, transientShellWidgetClass,
4628                          shellWidget, args, j);
4629 #endif
4630     layout =
4631       XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4632                             layoutArgs, XtNumber(layoutArgs));
4633     form =
4634       XtCreateManagedWidget("form", formWidgetClass, layout,
4635                             formArgs, XtNumber(formArgs));
4636
4637     j = 0;
4638     if (mutable) {
4639         XtSetArg(args[j], XtNeditType, XawtextEdit);  j++;
4640         XtSetArg(args[j], XtNuseStringInPlace, False);  j++;
4641     }
4642     XtSetArg(args[j], XtNstring, text);  j++;
4643     XtSetArg(args[j], XtNtop, XtChainTop);  j++;
4644     XtSetArg(args[j], XtNbottom, XtChainBottom);  j++;
4645     XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
4646     XtSetArg(args[j], XtNright, XtChainRight);  j++;
4647     XtSetArg(args[j], XtNresizable, True);  j++;
4648 #if 0
4649     XtSetArg(args[j], XtNscrollVertical, XawtextScrollWhenNeeded);  j++;
4650 #else
4651     /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4652     XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways);  j++;
4653 #endif
4654     XtSetArg(args[j], XtNautoFill, True);  j++;
4655     XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4656     edit =
4657       XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4658
4659     XtRealizeWidget(shell);
4660
4661     j = 0;
4662     XtSetArg(args[j], XtNwidth, &bw_width);  j++;
4663     XtGetValues(boardWidget, args, j);
4664
4665     j = 0;
4666     XtSetArg(args[j], XtNheight, &ew_height);  j++;
4667     XtGetValues(edit, args, j);
4668
4669     j = 0;
4670     XtSetArg(args[j], XtNheight, &pw_height);  j++;
4671     XtGetValues(shell, args, j);
4672     h = pw_height + (lines - 1) * ew_height;
4673     w = bw_width - 16;
4674
4675     XSync(xDisplay, False);
4676 #ifdef NOTDEF
4677     /* This code seems to tickle an X bug if it is executed too soon
4678        after xboard starts up.  The coordinates get transformed as if
4679        the main window was positioned at (0, 0).
4680     */
4681     XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4682 #else  /*!NOTDEF*/
4683     XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4684                           RootWindowOfScreen(XtScreen(shellWidget)),
4685                           (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4686 #endif /*!NOTDEF*/
4687     x = xx;
4688     y = yy;
4689     if (y < 0) y = 0; /*avoid positioning top offscreen*/
4690
4691     j = 0;
4692     XtSetArg(args[j], XtNheight, h);  j++;
4693     XtSetArg(args[j], XtNwidth, w);  j++;
4694     XtSetArg(args[j], XtNx, x);  j++;
4695     XtSetArg(args[j], XtNy, y);  j++;
4696     XtSetValues(shell, args, j);
4697
4698     return shell;
4699 }
4700
4701
4702 static int savedIndex;  /* gross that this is global */
4703
4704 void EditCommentPopUp(index, title, text)
4705      int index;
4706      char *title, *text;
4707 {
4708     Widget edit;
4709     Arg args[16];
4710     int j;
4711
4712     savedIndex = index;
4713     if (text == NULL) text = "";
4714
4715     if (editShell == NULL) {
4716         editShell =
4717           CommentCreate(title, text, True, EditCommentCallback, 4); 
4718         XtRealizeWidget(editShell);
4719         CatchDeleteWindow(editShell, "EditCommentPopDown");
4720     } else {
4721         edit = XtNameToWidget(editShell, "*form.text");
4722         j = 0;
4723         XtSetArg(args[j], XtNstring, text); j++;
4724         XtSetValues(edit, args, j);
4725         j = 0;
4726         XtSetArg(args[j], XtNiconName, (XtArgVal) title);   j++;
4727         XtSetArg(args[j], XtNtitle, (XtArgVal) title);      j++;
4728         XtSetValues(editShell, args, j);
4729     }
4730
4731     XtPopup(editShell, XtGrabNone);
4732
4733     editUp = True;
4734     j = 0;
4735     XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4736     XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4737                 args, j);
4738 }
4739
4740 void EditCommentCallback(w, client_data, call_data)
4741      Widget w;
4742      XtPointer client_data, call_data;
4743 {
4744     String name, val;
4745     Arg args[16];
4746     int j;
4747     Widget edit;
4748
4749     j = 0;
4750     XtSetArg(args[j], XtNlabel, &name);  j++;
4751     XtGetValues(w, args, j);
4752
4753     if (strcmp(name, "ok") == 0) {
4754         edit = XtNameToWidget(editShell, "*form.text");
4755         j = 0;
4756         XtSetArg(args[j], XtNstring, &val); j++;
4757         XtGetValues(edit, args, j);
4758         ReplaceComment(savedIndex, val);
4759         EditCommentPopDown();
4760     } else if (strcmp(name, "cancel") == 0) {
4761         EditCommentPopDown();
4762     } else if (strcmp(name, "clear") == 0) {
4763         edit = XtNameToWidget(editShell, "*form.text");
4764         XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4765         XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4766     }
4767 }
4768
4769 void EditCommentPopDown()
4770 {
4771     Arg args[16];
4772     int j;
4773
4774     if (!editUp) return;
4775     j = 0;
4776     XtSetArg(args[j], XtNx, &commentX); j++;
4777     XtSetArg(args[j], XtNy, &commentY); j++;
4778     XtSetArg(args[j], XtNheight, &commentH); j++;
4779     XtSetArg(args[j], XtNwidth, &commentW); j++;
4780     XtGetValues(editShell, args, j);
4781     XtPopdown(editShell);
4782     editUp = False;
4783     j = 0;
4784     XtSetArg(args[j], XtNleftBitmap, None); j++;
4785     XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4786                 args, j);
4787 }
4788
4789 void ICSInputBoxPopUp()
4790 {
4791     Widget edit;
4792     Arg args[16];
4793     int j;
4794     char *title = "ICS Input";
4795     XtTranslations tr;
4796         
4797     if (ICSInputShell == NULL) {
4798         ICSInputShell = MiscCreate(title, "", True, NULL, 1);
4799         tr = XtParseTranslationTable(ICSInputTranslations);
4800         edit = XtNameToWidget(ICSInputShell, "*form.text");
4801         XtOverrideTranslations(edit, tr);
4802         XtRealizeWidget(ICSInputShell);
4803         CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
4804         
4805     } else {
4806         edit = XtNameToWidget(ICSInputShell, "*form.text");
4807         j = 0;
4808         XtSetArg(args[j], XtNstring, ""); j++;
4809         XtSetValues(edit, args, j);
4810         j = 0;
4811         XtSetArg(args[j], XtNiconName, (XtArgVal) title);   j++;
4812         XtSetArg(args[j], XtNtitle, (XtArgVal) title);      j++;
4813         XtSetValues(ICSInputShell, args, j);
4814     }
4815
4816     XtPopup(ICSInputShell, XtGrabNone);
4817     XtSetKeyboardFocus(ICSInputShell, edit);
4818
4819     ICSInputBoxUp = True;
4820     j = 0;
4821     XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4822     XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4823                 args, j);
4824 }
4825
4826 void ICSInputSendText()
4827 {
4828     Widget edit;
4829     int j;
4830     Arg args[16];
4831     String val;
4832   
4833     edit = XtNameToWidget(ICSInputShell, "*form.text");
4834     j = 0;
4835     XtSetArg(args[j], XtNstring, &val); j++;
4836     XtGetValues(edit, args, j);
4837     SendMultiLineToICS(val);
4838     XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4839     XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4840 }
4841
4842 void ICSInputBoxPopDown()
4843 {
4844     Arg args[16];
4845     int j;
4846
4847     if (!ICSInputBoxUp) return;
4848     j = 0;
4849     XtPopdown(ICSInputShell);
4850     ICSInputBoxUp = False;
4851     j = 0;
4852     XtSetArg(args[j], XtNleftBitmap, None); j++;
4853     XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4854                 args, j);
4855 }
4856
4857 void CommentPopUp(title, text)
4858      char *title, *text;
4859 {
4860     Arg args[16];
4861     int j;
4862     Widget edit;
4863
4864     if (commentShell == NULL) {
4865         commentShell =
4866           CommentCreate(title, text, False, CommentCallback, 4);
4867         XtRealizeWidget(commentShell);
4868         CatchDeleteWindow(commentShell, "CommentPopDown");
4869     } else {
4870         edit = XtNameToWidget(commentShell, "*form.text");
4871         j = 0;
4872         XtSetArg(args[j], XtNstring, text); j++;
4873         XtSetValues(edit, args, j);
4874         j = 0;
4875         XtSetArg(args[j], XtNiconName, (XtArgVal) title);   j++;
4876         XtSetArg(args[j], XtNtitle, (XtArgVal) title);      j++;
4877         XtSetValues(commentShell, args, j);
4878     }
4879
4880     XtPopup(commentShell, XtGrabNone);
4881     XSync(xDisplay, False);
4882
4883     commentUp = True;
4884 }
4885
4886 void AnalysisPopUp(title, text)
4887      char *title, *text;
4888 {
4889     Arg args[16];
4890     int j;
4891     Widget edit;
4892
4893     if (analysisShell == NULL) {
4894         analysisShell = MiscCreate(title, text, False, NULL, 4);
4895         XtRealizeWidget(analysisShell);
4896         CatchDeleteWindow(analysisShell, "AnalysisPopDown");
4897
4898     } else {
4899         edit = XtNameToWidget(analysisShell, "*form.text");
4900         j = 0;
4901         XtSetArg(args[j], XtNstring, text); j++;
4902         XtSetValues(edit, args, j);
4903         j = 0;
4904         XtSetArg(args[j], XtNiconName, (XtArgVal) title);   j++;
4905         XtSetArg(args[j], XtNtitle, (XtArgVal) title);      j++;
4906         XtSetValues(analysisShell, args, j);
4907     }
4908
4909     if (!analysisUp) {
4910         XtPopup(analysisShell, XtGrabNone);
4911     }
4912     XSync(xDisplay, False);
4913
4914     analysisUp = True;
4915 }
4916
4917 void CommentCallback(w, client_data, call_data)
4918      Widget w;
4919      XtPointer client_data, call_data;
4920 {
4921     String name;
4922     Arg args[16];
4923     int j;
4924
4925     j = 0;
4926     XtSetArg(args[j], XtNlabel, &name);  j++;
4927     XtGetValues(w, args, j);
4928
4929     if (strcmp(name, "close") == 0) {
4930         CommentPopDown();
4931     } else if (strcmp(name, "edit") == 0) {
4932         CommentPopDown();
4933         EditCommentEvent();
4934     }
4935 }
4936
4937
4938 void CommentPopDown()
4939 {
4940     Arg args[16];
4941     int j;
4942
4943     if (!commentUp) return;
4944     j = 0;
4945     XtSetArg(args[j], XtNx, &commentX); j++;
4946     XtSetArg(args[j], XtNy, &commentY); j++;
4947     XtSetArg(args[j], XtNwidth, &commentW); j++;
4948     XtSetArg(args[j], XtNheight, &commentH); j++;
4949     XtGetValues(commentShell, args, j);
4950     XtPopdown(commentShell);
4951     XSync(xDisplay, False);
4952     commentUp = False;
4953 }
4954
4955 void AnalysisPopDown()
4956 {
4957     if (!analysisUp) return;
4958     XtPopdown(analysisShell);
4959     XSync(xDisplay, False);
4960     analysisUp = False;
4961 }
4962
4963
4964 void FileNamePopUp(label, def, proc, openMode)
4965      char *label;
4966      char *def;
4967      FileProc proc;
4968      char *openMode;
4969 {
4970     Arg args[16];
4971     Widget popup, layout, dialog, edit;
4972     Window root, child;
4973     int x, y, i;
4974     int win_x, win_y;
4975     unsigned int mask;
4976     
4977     fileProc = proc;            /* I can't see a way not */
4978     fileOpenMode = openMode;    /*   to use globals here */
4979     
4980     i = 0;
4981     XtSetArg(args[i], XtNresizable, True); i++;
4982     XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
4983     fileNameShell = popup =
4984       XtCreatePopupShell("File name prompt", transientShellWidgetClass,
4985                          shellWidget, args, i);
4986     
4987     layout =
4988       XtCreateManagedWidget(layoutName, formWidgetClass, popup,
4989                             layoutArgs, XtNumber(layoutArgs));
4990   
4991     i = 0;
4992     XtSetArg(args[i], XtNlabel, label); i++;
4993     XtSetArg(args[i], XtNvalue, def); i++;
4994     XtSetArg(args[i], XtNborderWidth, 0); i++;
4995     dialog = XtCreateManagedWidget("fileName", dialogWidgetClass,
4996                                    layout, args, i);
4997     
4998     XawDialogAddButton(dialog, "ok", FileNameCallback, (XtPointer) dialog);
4999     XawDialogAddButton(dialog, "cancel", FileNameCallback,
5000                        (XtPointer) dialog);
5001     
5002     XtRealizeWidget(popup);
5003     CatchDeleteWindow(popup, "FileNamePopDown");
5004     
5005     XQueryPointer(xDisplay, xBoardWindow, &root, &child,
5006                   &x, &y, &win_x, &win_y, &mask);
5007     
5008     XtSetArg(args[0], XtNx, x - 10);
5009     XtSetArg(args[1], XtNy, y - 30);
5010     XtSetValues(popup, args, 2);
5011     
5012     XtPopup(popup, XtGrabExclusive);
5013     filenameUp = True;
5014     
5015     edit = XtNameToWidget(dialog, "*value");
5016     XtSetKeyboardFocus(popup, edit);
5017 }
5018
5019 void FileNamePopDown()
5020 {
5021     if (!filenameUp) return;
5022     XtPopdown(fileNameShell);
5023     XtDestroyWidget(fileNameShell);
5024     filenameUp = False;
5025     ModeHighlight();
5026 }
5027
5028 void FileNameCallback(w, client_data, call_data)
5029      Widget w;
5030      XtPointer client_data, call_data;
5031 {
5032     String name;
5033     Arg args[16];
5034     
5035     XtSetArg(args[0], XtNlabel, &name);
5036     XtGetValues(w, args, 1);
5037     
5038     if (strcmp(name, "cancel") == 0) {
5039         FileNamePopDown();
5040         return;
5041     }
5042     
5043     FileNameAction(w, NULL, NULL, NULL);
5044 }
5045
5046 void FileNameAction(w, event, prms, nprms)
5047      Widget w;
5048      XEvent *event;
5049      String *prms;
5050      Cardinal *nprms;
5051 {
5052     char buf[MSG_SIZ];
5053     String name;
5054     FILE *f;
5055     char *p, *fullname;
5056     int index;
5057
5058     name = XawDialogGetValueString(w = XtParent(w));
5059     
5060     if ((name != NULL) && (*name != NULLCHAR)) {
5061         strcpy(buf, name);
5062         XtPopdown(w = XtParent(XtParent(w)));
5063         XtDestroyWidget(w);
5064         filenameUp = False;
5065
5066         p = strrchr(buf, ' ');
5067         if (p == NULL) {
5068             index = 0;
5069         } else {
5070             *p++ = NULLCHAR;
5071             index = atoi(p);
5072         }
5073         fullname = ExpandPathName(buf);
5074         if (!fullname) {
5075             ErrorPopUp("Error", "Can't open file", FALSE);
5076         }
5077         else {
5078             f = fopen(fullname, fileOpenMode);
5079             if (f == NULL) {
5080                 DisplayError("Failed to open file", errno);
5081             } else {
5082                 (void) (*fileProc)(f, index, buf);
5083             }
5084         }
5085         ModeHighlight();
5086         return;
5087     }
5088     
5089     XtPopdown(w = XtParent(XtParent(w)));
5090     XtDestroyWidget(w);
5091     filenameUp = False;
5092     ModeHighlight();
5093 }
5094
5095 void PromotionPopUp()
5096 {
5097     Arg args[16];
5098     Widget dialog, layout;
5099     Position x, y;
5100     Dimension bw_width, pw_width;
5101     int j;
5102
5103     j = 0;
5104     XtSetArg(args[j], XtNwidth, &bw_width); j++;
5105     XtGetValues(boardWidget, args, j);
5106     
5107     j = 0;
5108     XtSetArg(args[j], XtNresizable, True); j++;
5109     promotionShell =
5110       XtCreatePopupShell("Promotion", transientShellWidgetClass,
5111                          shellWidget, args, j);
5112     layout =
5113       XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5114                             layoutArgs, XtNumber(layoutArgs));
5115     
5116     j = 0;
5117     XtSetArg(args[j], XtNlabel, "Promote pawn to what?"); j++;
5118     XtSetArg(args[j], XtNborderWidth, 0); j++;
5119     dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5120                                    layout, args, j);
5121     
5122     XawDialogAddButton(dialog, "Queen", PromotionCallback, 
5123                        (XtPointer) dialog);
5124     XawDialogAddButton(dialog, "Rook", PromotionCallback, 
5125                        (XtPointer) dialog);
5126     XawDialogAddButton(dialog, "Bishop", PromotionCallback, 
5127                        (XtPointer) dialog);
5128     XawDialogAddButton(dialog, "Knight", PromotionCallback, 
5129                        (XtPointer) dialog);
5130     if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5131         gameInfo.variant == VariantGiveaway) {
5132       XawDialogAddButton(dialog, "King", PromotionCallback, 
5133                          (XtPointer) dialog);
5134     }
5135     XawDialogAddButton(dialog, "cancel", PromotionCallback, 
5136                        (XtPointer) dialog);
5137     
5138     XtRealizeWidget(promotionShell);
5139     CatchDeleteWindow(promotionShell, "PromotionPopDown");
5140     
5141     j = 0;
5142     XtSetArg(args[j], XtNwidth, &pw_width); j++;
5143     XtGetValues(promotionShell, args, j);
5144     
5145     XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5146                       lineGap + squareSize/3 +
5147                       ((toY == 7) ^ (flipView) ?
5148                        0 : 6*(squareSize + lineGap)), &x, &y);
5149     
5150     j = 0;
5151     XtSetArg(args[j], XtNx, x); j++;
5152     XtSetArg(args[j], XtNy, y); j++;
5153     XtSetValues(promotionShell, args, j);
5154     
5155     XtPopup(promotionShell, XtGrabNone);
5156     
5157     promotionUp = True;
5158 }
5159
5160 void PromotionPopDown()
5161 {
5162     if (!promotionUp) return;
5163     XtPopdown(promotionShell);
5164     XtDestroyWidget(promotionShell);
5165     promotionUp = False;
5166 }
5167
5168 void PromotionCallback(w, client_data, call_data)
5169      Widget w;
5170      XtPointer client_data, call_data;
5171 {
5172     String name;
5173     Arg args[16];
5174     int promoChar;
5175     
5176     XtSetArg(args[0], XtNlabel, &name);
5177     XtGetValues(w, args, 1);
5178     
5179     PromotionPopDown();
5180     
5181     if (fromX == -1) return;
5182     
5183     if (strcmp(name, "cancel") == 0) {
5184         fromX = fromY = -1;
5185         ClearHighlights();
5186         return;
5187     } else if (strcmp(name, "Knight") == 0) {
5188         promoChar = 'n';
5189     } else {
5190         promoChar = ToLower(name[0]);
5191     }
5192
5193     UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5194
5195     if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5196     if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5197     fromX = fromY = -1;
5198 }
5199
5200
5201 void ErrorCallback(w, client_data, call_data)
5202      Widget w;
5203      XtPointer client_data, call_data;
5204 {
5205     errorUp = False;
5206     XtPopdown(w = XtParent(XtParent(XtParent(w))));
5207     XtDestroyWidget(w);
5208     if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5209 }
5210
5211
5212 void ErrorPopDown()
5213 {
5214     if (!errorUp) return;
5215     errorUp = False;
5216     XtPopdown(errorShell);
5217     XtDestroyWidget(errorShell);
5218     if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5219 }
5220
5221 void ErrorPopUp(title, label, modal)
5222      char *title, *label;
5223      int modal;
5224 {
5225     Arg args[16];
5226     Widget dialog, layout;
5227     Position x, y;
5228     int xx, yy;
5229     Window junk;
5230     Dimension bw_width, pw_width;
5231     Dimension pw_height;
5232     int i;
5233     
5234     i = 0;
5235     XtSetArg(args[i], XtNresizable, True);  i++;
5236     XtSetArg(args[i], XtNtitle, title); i++;
5237     errorShell = 
5238       XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5239                          shellWidget, args, i);
5240     layout =
5241       XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5242                             layoutArgs, XtNumber(layoutArgs));
5243     
5244     i = 0;
5245     XtSetArg(args[i], XtNlabel, label); i++;
5246     XtSetArg(args[i], XtNborderWidth, 0); i++;
5247     dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5248                                    layout, args, i);
5249     
5250     XawDialogAddButton(dialog, "ok", ErrorCallback, (XtPointer) dialog);
5251     
5252     XtRealizeWidget(errorShell);
5253     CatchDeleteWindow(errorShell, "ErrorPopDown");
5254     
5255     i = 0;
5256     XtSetArg(args[i], XtNwidth, &bw_width);  i++;
5257     XtGetValues(boardWidget, args, i);
5258     i = 0;
5259     XtSetArg(args[i], XtNwidth, &pw_width);  i++;
5260     XtSetArg(args[i], XtNheight, &pw_height);  i++;
5261     XtGetValues(errorShell, args, i);
5262
5263 #ifdef NOTDEF
5264     /* This code seems to tickle an X bug if it is executed too soon
5265        after xboard starts up.  The coordinates get transformed as if
5266        the main window was positioned at (0, 0).
5267        */
5268     XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5269                       0 - pw_height + squareSize / 3, &x, &y);
5270 #else
5271     XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5272                           RootWindowOfScreen(XtScreen(boardWidget)),
5273                           (bw_width - pw_width) / 2,
5274                           0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5275     x = xx;
5276     y = yy;
5277 #endif
5278     if (y < 0) y = 0; /*avoid positioning top offscreen*/
5279
5280     i = 0;
5281     XtSetArg(args[i], XtNx, x);  i++;
5282     XtSetArg(args[i], XtNy, y);  i++;
5283     XtSetValues(errorShell, args, i);
5284
5285     errorUp = True;
5286     XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5287 }
5288
5289 /* Disable all user input other than deleting the window */
5290 static int frozen = 0;
5291 void FreezeUI()
5292 {
5293   if (frozen) return;
5294   /* Grab by a widget that doesn't accept input */
5295   XtAddGrab(messageWidget, TRUE, FALSE);
5296   frozen = 1;
5297 }
5298
5299 /* Undo a FreezeUI */
5300 void ThawUI()
5301 {
5302   if (!frozen) return;
5303   XtRemoveGrab(messageWidget);
5304   frozen = 0;
5305 }
5306
5307 char *ModeToWidgetName(mode)
5308      GameMode mode;
5309 {
5310     switch (mode) {
5311       case BeginningOfGame:
5312         if (appData.icsActive)
5313           return "menuMode.ICS Client";
5314         else if (appData.noChessProgram ||
5315                  *appData.cmailGameName != NULLCHAR)
5316           return "menuMode.Edit Game";
5317         else
5318           return "menuMode.Machine Black";
5319       case MachinePlaysBlack:
5320         return "menuMode.Machine Black";
5321       case MachinePlaysWhite:
5322         return "menuMode.Machine White";
5323       case AnalyzeMode:
5324         return "menuMode.Analysis Mode";
5325       case AnalyzeFile:
5326         return "menuMode.Analyze File";
5327       case TwoMachinesPlay:
5328         return "menuMode.Two Machines";
5329       case EditGame:
5330         return "menuMode.Edit Game";
5331       case PlayFromGameFile:
5332         return "menuFile.Load Game";
5333       case EditPosition:
5334         return "menuMode.Edit Position";
5335       case Training:
5336         return "menuMode.Training";
5337       case IcsPlayingWhite:
5338       case IcsPlayingBlack:
5339       case IcsObserving:
5340       case IcsIdle:
5341       case IcsExamining:
5342         return "menuMode.ICS Client";
5343       default:
5344       case EndOfGame:
5345         return NULL;
5346     }
5347 }     
5348
5349 void ModeHighlight()
5350 {
5351     Arg args[16];
5352     static int oldPausing = FALSE;
5353     static GameMode oldmode = (GameMode) -1;
5354     char *wname;
5355     
5356     if (!boardWidget || !XtIsRealized(boardWidget)) return;
5357
5358     if (pausing != oldPausing) {
5359         oldPausing = pausing;
5360         if (pausing) {
5361             XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5362         } else {
5363             XtSetArg(args[0], XtNleftBitmap, None);
5364         }
5365         XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5366                     args, 1);
5367
5368         if (appData.showButtonBar) {
5369 #if 0
5370           if (pausing) {
5371             XtSetArg(args[0], XtNbackground, buttonForegroundPixel);
5372             XtSetArg(args[1], XtNforeground, buttonBackgroundPixel);
5373           } else {
5374             XtSetArg(args[0], XtNbackground, buttonBackgroundPixel);
5375             XtSetArg(args[1], XtNforeground, buttonForegroundPixel);
5376           }
5377 #else
5378           /* Always toggle, don't set.  Previous code messes up when
5379              invoked while the button is pressed, as releasing it
5380              toggles the state again. */
5381           {
5382             Pixel oldbg, oldfg;
5383             XtSetArg(args[0], XtNbackground, &oldbg);
5384             XtSetArg(args[1], XtNforeground, &oldfg);
5385             XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5386                         args, 2);
5387             XtSetArg(args[0], XtNbackground, oldfg);
5388             XtSetArg(args[1], XtNforeground, oldbg);
5389           }
5390 #endif
5391           XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5392         }
5393     }
5394
5395     wname = ModeToWidgetName(oldmode);
5396     if (wname != NULL) {
5397         XtSetArg(args[0], XtNleftBitmap, None);
5398         XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5399     }
5400     wname = ModeToWidgetName(gameMode);
5401     if (wname != NULL) {
5402         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5403         XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5404     }
5405     oldmode = gameMode;
5406
5407     /* Maybe all the enables should be handled here, not just this one */
5408     XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5409                    gameMode == Training || gameMode == PlayFromGameFile);
5410 }
5411
5412
5413 /*
5414  * Button/menu procedures
5415  */
5416 void ResetProc(w, event, prms, nprms)
5417      Widget w;
5418      XEvent *event;
5419      String *prms;
5420      Cardinal *nprms;
5421 {
5422     ResetGameEvent();
5423     AnalysisPopDown();
5424 }
5425
5426 int LoadGamePopUp(f, gameNumber, title)
5427      FILE *f;
5428      int gameNumber;
5429      char *title;
5430 {
5431     cmailMsgLoaded = FALSE;
5432     if (gameNumber == 0) {
5433         int error = GameListBuild(f);
5434         if (error) {
5435             DisplayError("Cannot build game list", error);
5436         } else if (!ListEmpty(&gameList) &&
5437                    ((ListGame *) gameList.tailPred)->number > 1) {
5438             GameListPopUp(f, title);
5439             return TRUE;
5440         }
5441         GameListDestroy();
5442         gameNumber = 1;
5443     }
5444     return LoadGame(f, gameNumber, title, FALSE);
5445 }
5446
5447 void LoadGameProc(w, event, prms, nprms)
5448      Widget w;
5449      XEvent *event;
5450      String *prms;
5451      Cardinal *nprms;
5452 {
5453     if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5454         Reset(FALSE, TRUE);
5455     }
5456     FileNamePopUp("Load game file name?", "", LoadGamePopUp, "rb");
5457 }
5458
5459 void LoadNextGameProc(w, event, prms, nprms)
5460      Widget w;
5461      XEvent *event;
5462      String *prms;
5463      Cardinal *nprms;
5464 {
5465     ReloadGame(1);
5466 }
5467
5468 void LoadPrevGameProc(w, event, prms, nprms)
5469      Widget w;
5470      XEvent *event;
5471      String *prms;
5472      Cardinal *nprms;
5473 {
5474     ReloadGame(-1);
5475 }
5476
5477 void ReloadGameProc(w, event, prms, nprms)
5478      Widget w;
5479      XEvent *event;
5480      String *prms;
5481      Cardinal *nprms;
5482 {
5483     ReloadGame(0);
5484 }
5485
5486 void LoadNextPositionProc(w, event, prms, nprms)
5487      Widget w;
5488      XEvent *event;
5489      String *prms;
5490      Cardinal *nprms;
5491 {
5492     ReloadPosition(1);
5493 }
5494
5495 void LoadPrevPositionProc(w, event, prms, nprms)
5496      Widget w;
5497      XEvent *event;
5498      String *prms;
5499      Cardinal *nprms;
5500 {
5501     ReloadPosition(-1);
5502 }
5503
5504 void ReloadPositionProc(w, event, prms, nprms)
5505      Widget w;
5506      XEvent *event;
5507      String *prms;
5508      Cardinal *nprms;
5509 {
5510     ReloadPosition(0);
5511 }
5512
5513 void LoadPositionProc(w, event, prms, nprms)
5514      Widget w;
5515      XEvent *event;
5516      String *prms;
5517      Cardinal *nprms;
5518 {
5519     if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5520         Reset(FALSE, TRUE);
5521     }
5522     FileNamePopUp("Load position file name?", "", LoadPosition, "rb");
5523 }
5524
5525 void SaveGameProc(w, event, prms, nprms)
5526      Widget w;
5527      XEvent *event;
5528      String *prms;
5529      Cardinal *nprms;
5530 {
5531     FileNamePopUp("Save game file name?",
5532                   DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5533                   SaveGame, "a");
5534 }
5535
5536 void SavePositionProc(w, event, prms, nprms)
5537      Widget w;
5538      XEvent *event;
5539      String *prms;
5540      Cardinal *nprms;
5541 {
5542     FileNamePopUp("Save position file name?",
5543                   DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5544                   SavePosition, "a");
5545 }
5546
5547 void ReloadCmailMsgProc(w, event, prms, nprms)
5548      Widget w;
5549      XEvent *event;
5550      String *prms;
5551      Cardinal *nprms;
5552 {
5553     ReloadCmailMsgEvent(FALSE);
5554 }
5555
5556 void MailMoveProc(w, event, prms, nprms)
5557      Widget w;
5558      XEvent *event;
5559      String *prms;
5560      Cardinal *nprms;
5561 {
5562     MailMoveEvent();
5563 }
5564
5565 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5566 static char *selected_fen_position=NULL;
5567
5568 static Boolean
5569 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5570                  Atom *type_return, XtPointer *value_return,
5571                  unsigned long *length_return, int *format_return)
5572 {
5573   char *selection_tmp;
5574
5575   if (!selected_fen_position) return False; /* should never happen */
5576   if (*target == XA_STRING){
5577     /* note: since no XtSelectionDoneProc was registered, Xt will
5578      * automatically call XtFree on the value returned.  So have to
5579      * make a copy of it allocated with XtMalloc */
5580     selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5581     strcpy(selection_tmp, selected_fen_position);
5582
5583     *value_return=selection_tmp;
5584     *length_return=strlen(selection_tmp);
5585     *type_return=XA_STRING;
5586     *format_return = 8; /* bits per byte */
5587     return True;
5588   } else {
5589     return False;
5590   } 
5591 }
5592
5593 /* note: when called from menu all parameters are NULL, so no clue what the
5594  * Widget which was clicked on was, or what the click event was
5595  */
5596 void CopyPositionProc(w, event, prms, nprms)
5597   Widget w;
5598   XEvent *event;
5599   String *prms;
5600   Cardinal *nprms;
5601   {
5602     int ret;
5603
5604     if (selected_fen_position) free(selected_fen_position);
5605     selected_fen_position = (char *)PositionToFEN(currentMove);
5606     if (!selected_fen_position) return;
5607     ret = XtOwnSelection(menuBarWidget, XA_PRIMARY,
5608                          CurrentTime,
5609                          SendPositionSelection,
5610                          NULL/* lose_ownership_proc */ ,
5611                          NULL/* transfer_done_proc */);
5612     if (!ret) {
5613       free(selected_fen_position);
5614       selected_fen_position=NULL;
5615     }
5616   }
5617
5618 /* function called when the data to Paste is ready */
5619 static void
5620 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5621            Atom *type, XtPointer value, unsigned long *len, int *format)
5622 {
5623   char *fenstr=value;
5624   if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5625   fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5626   EditPositionPasteFEN(fenstr);
5627   XtFree(value);
5628 }
5629
5630 /* called when Paste Position button is pressed,
5631  * all parameters will be NULL */
5632 void PastePositionProc(w, event, prms, nprms)
5633   Widget w;
5634   XEvent *event;
5635   String *prms;
5636   Cardinal *nprms;
5637 {
5638     XtGetSelectionValue(menuBarWidget, XA_PRIMARY, XA_STRING,
5639       /* (XtSelectionCallbackProc) */ PastePositionCB,
5640       NULL, /* client_data passed to PastePositionCB */
5641
5642       /* better to use the time field from the event that triggered the
5643        * call to this function, but that isn't trivial to get
5644        */
5645       CurrentTime
5646     );
5647     return;
5648 }
5649
5650 static Boolean
5651 SendGameSelection(Widget w, Atom *selection, Atom *target,
5652                   Atom *type_return, XtPointer *value_return,
5653                   unsigned long *length_return, int *format_return)
5654 {
5655   char *selection_tmp;
5656
5657   if (*target == XA_STRING){
5658     FILE* f = fopen(gameCopyFilename, "r");
5659     long len;
5660     size_t count;
5661     if (f == NULL) return False;
5662     fseek(f, 0, 2);
5663     len = ftell(f);
5664     rewind(f);
5665     selection_tmp = XtMalloc(len + 1);
5666     count = fread(selection_tmp, 1, len, f);
5667     if (len != count) {
5668       XtFree(selection_tmp);
5669       return False;
5670     }
5671     selection_tmp[len] = NULLCHAR;
5672     *value_return = selection_tmp;
5673     *length_return = len;
5674     *type_return = XA_STRING;
5675     *format_return = 8; /* bits per byte */
5676     return True;
5677   } else {
5678     return False;
5679   } 
5680 }
5681
5682 /* note: when called from menu all parameters are NULL, so no clue what the
5683  * Widget which was clicked on was, or what the click event was
5684  */
5685 void CopyGameProc(w, event, prms, nprms)
5686   Widget w;
5687   XEvent *event;
5688   String *prms;
5689   Cardinal *nprms;
5690 {
5691   int ret;
5692
5693   ret = SaveGameToFile(gameCopyFilename, FALSE);
5694   if (!ret) return;
5695
5696   ret = XtOwnSelection(menuBarWidget, XA_PRIMARY,
5697                        CurrentTime,
5698                        SendGameSelection,
5699                        NULL/* lose_ownership_proc */ ,
5700                        NULL/* transfer_done_proc */);
5701 }
5702
5703 /* function called when the data to Paste is ready */
5704 static void
5705 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5706             Atom *type, XtPointer value, unsigned long *len, int *format)
5707 {
5708   FILE* f;
5709   if (value == NULL || *len == 0) {
5710     return; /* nothing had been selected to copy */
5711   }
5712   f = fopen(gamePasteFilename, "w");
5713   if (f == NULL) {
5714     DisplayError("Can't open temp file", errno);
5715     return;
5716   }
5717   fwrite(value, 1, *len, f);
5718   fclose(f);
5719   XtFree(value);
5720   LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5721 }
5722
5723 /* called when Paste Game button is pressed,
5724  * all parameters will be NULL */
5725 void PasteGameProc(w, event, prms, nprms)
5726   Widget w;
5727   XEvent *event;
5728   String *prms;
5729   Cardinal *nprms;
5730 {
5731     XtGetSelectionValue(menuBarWidget, XA_PRIMARY, XA_STRING,
5732       /* (XtSelectionCallbackProc) */ PasteGameCB,
5733       NULL, /* client_data passed to PasteGameCB */
5734
5735       /* better to use the time field from the event that triggered the
5736        * call to this function, but that isn't trivial to get
5737        */
5738       CurrentTime
5739     );
5740     return;
5741 }
5742
5743
5744 void AutoSaveGame()
5745 {
5746     SaveGameProc(NULL, NULL, NULL, NULL);
5747 }
5748
5749
5750 void QuitProc(w, event, prms, nprms)
5751      Widget w;
5752      XEvent *event;
5753      String *prms;
5754      Cardinal *nprms;
5755 {
5756     ExitEvent(0);
5757 }
5758
5759 void PauseProc(w, event, prms, nprms)
5760      Widget w;
5761      XEvent *event;
5762      String *prms;
5763      Cardinal *nprms;
5764 {
5765     PauseEvent();
5766 }
5767
5768
5769 void MachineBlackProc(w, event, prms, nprms)
5770      Widget w;
5771      XEvent *event;
5772      String *prms;
5773      Cardinal *nprms;
5774 {
5775     MachineBlackEvent();
5776 }
5777
5778 void MachineWhiteProc(w, event, prms, nprms)
5779      Widget w;
5780      XEvent *event;
5781      String *prms;
5782      Cardinal *nprms;
5783 {
5784     MachineWhiteEvent();
5785 }
5786
5787 void AnalyzeModeProc(w, event, prms, nprms)
5788      Widget w;
5789      XEvent *event;
5790      String *prms;
5791      Cardinal *nprms;
5792 {
5793     if (!first.analysisSupport) {
5794       char buf[MSG_SIZ];
5795       sprintf(buf, "%s does not support analysis", first.tidy);
5796       DisplayError(buf, 0);
5797       return;
5798     }
5799     if (!appData.showThinking)
5800       ShowThinkingProc(w,event,prms,nprms);
5801
5802     AnalyzeModeEvent();
5803 }
5804
5805 void AnalyzeFileProc(w, event, prms, nprms)
5806      Widget w;
5807      XEvent *event;
5808      String *prms;
5809      Cardinal *nprms;
5810 {
5811     if (!first.analysisSupport) {
5812       char buf[MSG_SIZ];
5813       sprintf(buf, "%s does not support analysis", first.tidy);
5814       DisplayError(buf, 0);
5815       return;
5816     }
5817     Reset(FALSE, TRUE);
5818
5819     if (!appData.showThinking)
5820       ShowThinkingProc(w,event,prms,nprms);
5821
5822     AnalyzeFileEvent();
5823     FileNamePopUp("File to analyze", "", LoadGamePopUp, "rb");
5824     AnalysisPeriodicEvent(1);
5825 }
5826
5827 void TwoMachinesProc(w, event, prms, nprms)
5828      Widget w;
5829      XEvent *event;
5830      String *prms;
5831      Cardinal *nprms;
5832 {
5833     TwoMachinesEvent();
5834 }
5835
5836 void IcsClientProc(w, event, prms, nprms)
5837      Widget w;
5838      XEvent *event;
5839      String *prms;
5840      Cardinal *nprms;
5841 {
5842     IcsClientEvent();
5843 }
5844
5845 void EditGameProc(w, event, prms, nprms)
5846      Widget w;
5847      XEvent *event;
5848      String *prms;
5849      Cardinal *nprms;
5850 {
5851     EditGameEvent();
5852 }
5853
5854 void EditPositionProc(w, event, prms, nprms)
5855      Widget w;
5856      XEvent *event;
5857      String *prms;
5858      Cardinal *nprms;
5859 {
5860     EditPositionEvent();
5861 }
5862
5863 void TrainingProc(w, event, prms, nprms)
5864      Widget w;
5865      XEvent *event;
5866      String *prms;
5867      Cardinal *nprms;
5868 {
5869     TrainingEvent();
5870 }
5871
5872 void EditCommentProc(w, event, prms, nprms)
5873      Widget w;
5874      XEvent *event;
5875      String *prms;
5876      Cardinal *nprms;
5877 {
5878     if (editUp) {
5879         EditCommentPopDown();
5880     } else {
5881         EditCommentEvent();
5882     }
5883 }
5884
5885 void IcsInputBoxProc(w, event, prms, nprms)
5886      Widget w;
5887      XEvent *event;
5888      String *prms;
5889      Cardinal *nprms;
5890 {
5891     if (ICSInputBoxUp) {
5892         ICSInputBoxPopDown();
5893     } else {
5894         ICSInputBoxPopUp();
5895     }
5896 }
5897
5898 void AcceptProc(w, event, prms, nprms)
5899      Widget w;
5900      XEvent *event;
5901      String *prms;
5902      Cardinal *nprms;
5903 {
5904     AcceptEvent();
5905 }
5906
5907 void DeclineProc(w, event, prms, nprms)
5908      Widget w;
5909      XEvent *event;
5910      String *prms;
5911      Cardinal *nprms;
5912 {
5913     DeclineEvent();
5914 }
5915
5916 void RematchProc(w, event, prms, nprms)
5917      Widget w;
5918      XEvent *event;
5919      String *prms;
5920      Cardinal *nprms;
5921 {
5922     RematchEvent();
5923 }
5924
5925 void CallFlagProc(w, event, prms, nprms)
5926      Widget w;
5927      XEvent *event;
5928      String *prms;
5929      Cardinal *nprms;
5930 {
5931     CallFlagEvent();
5932 }
5933
5934 void DrawProc(w, event, prms, nprms)
5935      Widget w;
5936      XEvent *event;
5937      String *prms;
5938      Cardinal *nprms;
5939 {
5940     DrawEvent();
5941 }
5942
5943 void AbortProc(w, event, prms, nprms)
5944      Widget w;
5945      XEvent *event;
5946      String *prms;
5947      Cardinal *nprms;
5948 {
5949     AbortEvent();
5950 }
5951
5952 void AdjournProc(w, event, prms, nprms)
5953      Widget w;
5954      XEvent *event;
5955      String *prms;
5956      Cardinal *nprms;
5957 {
5958     AdjournEvent();
5959 }
5960
5961 void ResignProc(w, event, prms, nprms)
5962      Widget w;
5963      XEvent *event;
5964      String *prms;
5965      Cardinal *nprms;
5966 {
5967     ResignEvent();
5968 }
5969
5970 void EnterKeyProc(w, event, prms, nprms)
5971      Widget w;
5972      XEvent *event;
5973      String *prms;
5974      Cardinal *nprms;
5975 {
5976     if (ICSInputBoxUp == True)
5977       ICSInputSendText();
5978 }
5979
5980 void StopObservingProc(w, event, prms, nprms)
5981      Widget w;
5982      XEvent *event;
5983      String *prms;
5984      Cardinal *nprms;
5985 {
5986     StopObservingEvent();
5987 }
5988
5989 void StopExaminingProc(w, event, prms, nprms)
5990      Widget w;
5991      XEvent *event;
5992      String *prms;
5993      Cardinal *nprms;
5994 {
5995     StopExaminingEvent();
5996 }
5997
5998
5999 void ForwardProc(w, event, prms, nprms)
6000      Widget w;
6001      XEvent *event;
6002      String *prms;
6003      Cardinal *nprms;
6004 {
6005     ForwardEvent();
6006 }
6007
6008
6009 void BackwardProc(w, event, prms, nprms)
6010      Widget w;
6011      XEvent *event;
6012      String *prms;
6013      Cardinal *nprms;
6014 {
6015     BackwardEvent();
6016 }
6017
6018 void ToStartProc(w, event, prms, nprms)
6019      Widget w;
6020      XEvent *event;
6021      String *prms;
6022      Cardinal *nprms;
6023 {
6024     ToStartEvent();
6025 }
6026
6027 void ToEndProc(w, event, prms, nprms)
6028      Widget w;
6029      XEvent *event;
6030      String *prms;
6031      Cardinal *nprms;
6032 {
6033     ToEndEvent();
6034 }
6035
6036 void RevertProc(w, event, prms, nprms)
6037      Widget w;
6038      XEvent *event;
6039      String *prms;
6040      Cardinal *nprms;
6041 {
6042     RevertEvent();
6043 }
6044
6045 void TruncateGameProc(w, event, prms, nprms)
6046      Widget w;
6047      XEvent *event;
6048      String *prms;
6049      Cardinal *nprms;
6050 {
6051     TruncateGameEvent();
6052 }
6053 void RetractMoveProc(w, event, prms, nprms)
6054      Widget w;
6055      XEvent *event;
6056      String *prms;
6057      Cardinal *nprms;
6058 {
6059     RetractMoveEvent();
6060 }
6061
6062 void MoveNowProc(w, event, prms, nprms)
6063      Widget w;
6064      XEvent *event;
6065      String *prms;
6066      Cardinal *nprms;
6067 {
6068     MoveNowEvent();
6069 }
6070
6071
6072 void AlwaysQueenProc(w, event, prms, nprms)
6073      Widget w;
6074      XEvent *event;
6075      String *prms;
6076      Cardinal *nprms;
6077 {
6078     Arg args[16];
6079
6080     appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6081
6082     if (appData.alwaysPromoteToQueen) {
6083         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6084     } else {
6085         XtSetArg(args[0], XtNleftBitmap, None);
6086     }
6087     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6088                 args, 1);
6089 }
6090
6091 void AnimateDraggingProc(w, event, prms, nprms)
6092      Widget w;
6093      XEvent *event;
6094      String *prms;
6095      Cardinal *nprms;
6096 {
6097     Arg args[16];
6098
6099     appData.animateDragging = !appData.animateDragging;
6100
6101     if (appData.animateDragging) {
6102         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6103         CreateAnimVars();
6104     } else {
6105         XtSetArg(args[0], XtNleftBitmap, None);
6106     }
6107     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6108                 args, 1);
6109 }
6110
6111 void AnimateMovingProc(w, event, prms, nprms)
6112      Widget w;
6113      XEvent *event;
6114      String *prms;
6115      Cardinal *nprms;
6116 {
6117     Arg args[16];
6118
6119     appData.animate = !appData.animate;
6120
6121     if (appData.animate) {
6122         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6123         CreateAnimVars();
6124     } else {
6125         XtSetArg(args[0], XtNleftBitmap, None);
6126     }
6127     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6128                 args, 1);
6129 }
6130
6131 void AutocommProc(w, event, prms, nprms)
6132      Widget w;
6133      XEvent *event;
6134      String *prms;
6135      Cardinal *nprms;
6136 {
6137     Arg args[16];
6138
6139     appData.autoComment = !appData.autoComment;
6140
6141     if (appData.autoComment) {
6142         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6143     } else {
6144         XtSetArg(args[0], XtNleftBitmap, None);
6145     }
6146     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6147                 args, 1);
6148 }
6149
6150
6151 void AutoflagProc(w, event, prms, nprms)
6152      Widget w;
6153      XEvent *event;
6154      String *prms;
6155      Cardinal *nprms;
6156 {
6157     Arg args[16];
6158
6159     appData.autoCallFlag = !appData.autoCallFlag;
6160
6161     if (appData.autoCallFlag) {
6162         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6163     } else {
6164         XtSetArg(args[0], XtNleftBitmap, None);
6165     }
6166     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6167                 args, 1);
6168 }
6169
6170 void AutoflipProc(w, event, prms, nprms)
6171      Widget w;
6172      XEvent *event;
6173      String *prms;
6174      Cardinal *nprms;
6175 {
6176     Arg args[16];
6177
6178     appData.autoFlipView = !appData.autoFlipView;
6179
6180     if (appData.autoFlipView) {
6181         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6182     } else {
6183         XtSetArg(args[0], XtNleftBitmap, None);
6184     }
6185     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6186                 args, 1);
6187 }
6188
6189 void AutobsProc(w, event, prms, nprms)
6190      Widget w;
6191      XEvent *event;
6192      String *prms;
6193      Cardinal *nprms;
6194 {
6195     Arg args[16];
6196
6197     appData.autoObserve = !appData.autoObserve;
6198
6199     if (appData.autoObserve) {
6200         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6201     } else {
6202         XtSetArg(args[0], XtNleftBitmap, None);
6203     }
6204     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6205                 args, 1);
6206 }
6207
6208 void AutoraiseProc(w, event, prms, nprms)
6209      Widget w;
6210      XEvent *event;
6211      String *prms;
6212      Cardinal *nprms;
6213 {
6214     Arg args[16];
6215
6216     appData.autoRaiseBoard = !appData.autoRaiseBoard;
6217
6218     if (appData.autoRaiseBoard) {
6219         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6220     } else {
6221         XtSetArg(args[0], XtNleftBitmap, None);
6222     }
6223     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6224                 args, 1);
6225 }
6226
6227 void AutosaveProc(w, event, prms, nprms)
6228      Widget w;
6229      XEvent *event;
6230      String *prms;
6231      Cardinal *nprms;
6232 {
6233     Arg args[16];
6234
6235     appData.autoSaveGames = !appData.autoSaveGames;
6236
6237     if (appData.autoSaveGames) {
6238         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6239     } else {
6240         XtSetArg(args[0], XtNleftBitmap, None);
6241     }
6242     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6243                 args, 1);
6244 }
6245
6246 void BlindfoldProc(w, event, prms, nprms)
6247      Widget w;
6248      XEvent *event;
6249      String *prms;
6250      Cardinal *nprms;
6251 {
6252     Arg args[16];
6253
6254     appData.blindfold = !appData.blindfold;
6255
6256     if (appData.blindfold) {
6257         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6258     } else {
6259         XtSetArg(args[0], XtNleftBitmap, None);
6260     }
6261     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6262                 args, 1);
6263
6264     DrawPosition(True, NULL);
6265 }
6266
6267 void TestLegalityProc(w, event, prms, nprms)
6268      Widget w;
6269      XEvent *event;
6270      String *prms;
6271      Cardinal *nprms;
6272 {
6273     Arg args[16];
6274
6275     appData.testLegality = !appData.testLegality;
6276
6277     if (appData.testLegality) {
6278         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6279     } else {
6280         XtSetArg(args[0], XtNleftBitmap, None);
6281     }
6282     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6283                 args, 1);
6284 }
6285
6286
6287 void FlashMovesProc(w, event, prms, nprms)
6288      Widget w;
6289      XEvent *event;
6290      String *prms;
6291      Cardinal *nprms;
6292 {
6293     Arg args[16];
6294
6295     if (appData.flashCount == 0) {
6296         appData.flashCount = 3;
6297     } else {
6298         appData.flashCount = -appData.flashCount;
6299     }
6300
6301     if (appData.flashCount > 0) {
6302         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6303     } else {
6304         XtSetArg(args[0], XtNleftBitmap, None);
6305     }
6306     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6307                 args, 1);
6308 }
6309
6310 void FlipViewProc(w, event, prms, nprms)
6311      Widget w;
6312      XEvent *event;
6313      String *prms;
6314      Cardinal *nprms;
6315 {
6316     flipView = !flipView;
6317     DrawPosition(True, NULL);
6318 }
6319
6320 void GetMoveListProc(w, event, prms, nprms)
6321      Widget w;
6322      XEvent *event;
6323      String *prms;
6324      Cardinal *nprms;
6325 {
6326     Arg args[16];
6327
6328     appData.getMoveList = !appData.getMoveList;
6329
6330     if (appData.getMoveList) {
6331         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6332         GetMoveListEvent();
6333     } else {
6334         XtSetArg(args[0], XtNleftBitmap, None);
6335     }
6336     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6337                 args, 1);
6338 }
6339
6340 #if HIGHDRAG
6341 void HighlightDraggingProc(w, event, prms, nprms)
6342      Widget w;
6343      XEvent *event;
6344      String *prms;
6345      Cardinal *nprms;
6346 {
6347     Arg args[16];
6348
6349     appData.highlightDragging = !appData.highlightDragging;
6350
6351     if (appData.highlightDragging) {
6352         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6353     } else {
6354         XtSetArg(args[0], XtNleftBitmap, None);
6355     }
6356     XtSetValues(XtNameToWidget(menuBarWidget,
6357                                "menuOptions.Highlight Dragging"), args, 1);
6358 }
6359 #endif
6360
6361 void HighlightLastMoveProc(w, event, prms, nprms)
6362      Widget w;
6363      XEvent *event;
6364      String *prms;
6365      Cardinal *nprms;
6366 {
6367     Arg args[16];
6368
6369     appData.highlightLastMove = !appData.highlightLastMove;
6370
6371     if (appData.highlightLastMove) {
6372         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6373     } else {
6374         XtSetArg(args[0], XtNleftBitmap, None);
6375     }
6376     XtSetValues(XtNameToWidget(menuBarWidget,
6377                                "menuOptions.Highlight Last Move"), args, 1);
6378 }
6379
6380 void IcsAlarmProc(w, event, prms, nprms)
6381      Widget w;
6382      XEvent *event;
6383      String *prms;
6384      Cardinal *nprms;
6385 {
6386     Arg args[16];
6387
6388     appData.icsAlarm = !appData.icsAlarm;
6389
6390     if (appData.icsAlarm) {
6391         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6392     } else {
6393         XtSetArg(args[0], XtNleftBitmap, None);
6394     }
6395     XtSetValues(XtNameToWidget(menuBarWidget,
6396                                "menuOptions.ICS Alarm"), args, 1);
6397 }
6398
6399 void MoveSoundProc(w, event, prms, nprms)
6400      Widget w;
6401      XEvent *event;
6402      String *prms;
6403      Cardinal *nprms;
6404 {
6405     Arg args[16];
6406
6407     appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6408
6409     if (appData.ringBellAfterMoves) {
6410         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6411     } else {
6412         XtSetArg(args[0], XtNleftBitmap, None);
6413     }
6414     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6415                 args, 1);
6416 }
6417
6418
6419 void OldSaveStyleProc(w, event, prms, nprms)
6420      Widget w;
6421      XEvent *event;
6422      String *prms;
6423      Cardinal *nprms;
6424 {
6425     Arg args[16];
6426
6427     appData.oldSaveStyle = !appData.oldSaveStyle;
6428
6429     if (appData.oldSaveStyle) {
6430         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6431     } else {
6432         XtSetArg(args[0], XtNleftBitmap, None);
6433     }
6434     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6435                 args, 1);
6436 }
6437
6438 void PeriodicUpdatesProc(w, event, prms, nprms)
6439      Widget w;
6440      XEvent *event;
6441      String *prms;
6442      Cardinal *nprms;
6443 {
6444     Arg args[16];
6445
6446     PeriodicUpdatesEvent(!appData.periodicUpdates);
6447         
6448     if (appData.periodicUpdates) {
6449         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6450     } else {
6451         XtSetArg(args[0], XtNleftBitmap, None);
6452     }
6453     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6454                 args, 1);
6455 }
6456
6457 void PonderNextMoveProc(w, event, prms, nprms)
6458      Widget w;
6459      XEvent *event;
6460      String *prms;
6461      Cardinal *nprms;
6462 {
6463     Arg args[16];
6464
6465     PonderNextMoveEvent(!appData.ponderNextMove);
6466
6467     if (appData.ponderNextMove) {
6468         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6469     } else {
6470         XtSetArg(args[0], XtNleftBitmap, None);
6471     }
6472     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6473                 args, 1);
6474 }
6475
6476 void PopupExitMessageProc(w, event, prms, nprms)
6477      Widget w;
6478      XEvent *event;
6479      String *prms;
6480      Cardinal *nprms;
6481 {
6482     Arg args[16];
6483
6484     appData.popupExitMessage = !appData.popupExitMessage;
6485
6486     if (appData.popupExitMessage) {
6487         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6488     } else {
6489         XtSetArg(args[0], XtNleftBitmap, None);
6490     }
6491     XtSetValues(XtNameToWidget(menuBarWidget,
6492                                "menuOptions.Popup Exit Message"), args, 1);
6493 }
6494
6495 void PopupMoveErrorsProc(w, event, prms, nprms)
6496      Widget w;
6497      XEvent *event;
6498      String *prms;
6499      Cardinal *nprms;
6500 {
6501     Arg args[16];
6502
6503     appData.popupMoveErrors = !appData.popupMoveErrors;
6504
6505     if (appData.popupMoveErrors) {
6506         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6507     } else {
6508         XtSetArg(args[0], XtNleftBitmap, None);
6509     }
6510     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6511                 args, 1);
6512 }
6513
6514 void PremoveProc(w, event, prms, nprms)
6515      Widget w;
6516      XEvent *event;
6517      String *prms;
6518      Cardinal *nprms;
6519 {
6520     Arg args[16];
6521
6522     appData.premove = !appData.premove;
6523
6524     if (appData.premove) {
6525         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6526     } else {
6527         XtSetArg(args[0], XtNleftBitmap, None);
6528     }
6529     XtSetValues(XtNameToWidget(menuBarWidget,
6530                                "menuOptions.Premove"), args, 1);
6531 }
6532
6533 void QuietPlayProc(w, event, prms, nprms)
6534      Widget w;
6535      XEvent *event;
6536      String *prms;
6537      Cardinal *nprms;
6538 {
6539     Arg args[16];
6540
6541     appData.quietPlay = !appData.quietPlay;
6542
6543     if (appData.quietPlay) {
6544         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6545     } else {
6546         XtSetArg(args[0], XtNleftBitmap, None);
6547     }
6548     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6549                 args, 1);
6550 }
6551
6552 void ShowCoordsProc(w, event, prms, nprms)
6553      Widget w;
6554      XEvent *event;
6555      String *prms;
6556      Cardinal *nprms;
6557 {
6558     Arg args[16];
6559
6560     appData.showCoords = !appData.showCoords;
6561
6562     if (appData.showCoords) {
6563         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6564     } else {
6565         XtSetArg(args[0], XtNleftBitmap, None);
6566     }
6567     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6568                 args, 1);
6569
6570     DrawPosition(True, NULL);
6571 }
6572
6573 void ShowThinkingProc(w, event, prms, nprms)
6574      Widget w;
6575      XEvent *event;
6576      String *prms;
6577      Cardinal *nprms;
6578 {
6579     Arg args[16];
6580
6581     ShowThinkingEvent(!appData.showThinking);
6582
6583     if (appData.showThinking) {
6584         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6585     } else {
6586         XtSetArg(args[0], XtNleftBitmap, None);
6587     }
6588     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Thinking"),
6589                 args, 1);
6590 }
6591
6592 void InfoProc(w, event, prms, nprms)
6593      Widget w;
6594      XEvent *event;
6595      String *prms;
6596      Cardinal *nprms;
6597 {
6598     char buf[MSG_SIZ];
6599     sprintf(buf, "xterm -e info --directory %s --directory . -f %s &",
6600             INFODIR, INFOFILE);
6601     system(buf);
6602 }
6603
6604 void ManProc(w, event, prms, nprms)
6605      Widget w;
6606      XEvent *event;
6607      String *prms;
6608      Cardinal *nprms;
6609 {
6610     char buf[MSG_SIZ];
6611     String name;
6612     if (nprms && *nprms > 0)
6613       name = prms[0];
6614     else
6615       name = "xboard";
6616     sprintf(buf, "xterm -e man %s &", name);
6617     system(buf);
6618 }
6619
6620 void HintProc(w, event, prms, nprms)
6621      Widget w;
6622      XEvent *event;
6623      String *prms;
6624      Cardinal *nprms;
6625 {
6626     HintEvent();
6627 }
6628
6629 void BookProc(w, event, prms, nprms)
6630      Widget w;
6631      XEvent *event;
6632      String *prms;
6633      Cardinal *nprms;
6634 {
6635     BookEvent();
6636 }
6637
6638 void AboutProc(w, event, prms, nprms)
6639      Widget w;
6640      XEvent *event;
6641      String *prms;
6642      Cardinal *nprms;
6643 {
6644     char buf[MSG_SIZ];
6645 #if ZIPPY
6646     char *zippy = " (with Zippy code)";
6647 #else
6648     char *zippy = "";
6649 #endif
6650     sprintf(buf, "%s%s\n\n%s\n%s\n\n%s%s\n%s",
6651             programVersion, zippy,
6652             "Copyright 1991 Digital Equipment Corporation",
6653             "Enhancements Copyright 1992-2001 Free Software Foundation",
6654             PRODUCT, " is free software and carries NO WARRANTY;",
6655             "see the file COPYING for more information.");
6656     ErrorPopUp("About XBoard", buf, FALSE);
6657 }
6658
6659 void DebugProc(w, event, prms, nprms)
6660      Widget w;
6661      XEvent *event;
6662      String *prms;
6663      Cardinal *nprms;
6664 {
6665     appData.debugMode = !appData.debugMode;
6666 }
6667
6668 void AboutGameProc(w, event, prms, nprms)
6669      Widget w;
6670      XEvent *event;
6671      String *prms;
6672      Cardinal *nprms;
6673 {
6674     AboutGameEvent();
6675 }
6676
6677 void NothingProc(w, event, prms, nprms)
6678      Widget w;
6679      XEvent *event;
6680      String *prms;
6681      Cardinal *nprms;
6682 {
6683     return;
6684 }
6685
6686 void Iconify(w, event, prms, nprms)
6687      Widget w;
6688      XEvent *event;
6689      String *prms;
6690      Cardinal *nprms;
6691 {
6692     Arg args[16];
6693     
6694     fromX = fromY = -1;
6695     XtSetArg(args[0], XtNiconic, True);
6696     XtSetValues(shellWidget, args, 1);
6697 }
6698
6699 void DisplayMessage(message, extMessage)
6700      char *message, *extMessage;
6701 {
6702     char buf[MSG_SIZ];
6703     Arg arg;
6704     
6705     if (extMessage) {
6706         if (*message) {
6707             sprintf(buf, "%s  %s", message, extMessage);
6708             message = buf;
6709         } else {
6710             message = extMessage;
6711         }
6712     }
6713     XtSetArg(arg, XtNlabel, message);
6714     XtSetValues(messageWidget, &arg, 1);
6715 }
6716
6717 void DisplayTitle(text)
6718      char *text;
6719 {
6720     Arg args[16];
6721     int i;
6722     char title[MSG_SIZ];
6723     char icon[MSG_SIZ];
6724
6725     if (text == NULL) text = "";
6726
6727     if (appData.titleInWindow) {
6728         i = 0;
6729         XtSetArg(args[i], XtNlabel, text);   i++;
6730         XtSetValues(titleWidget, args, i);
6731     }
6732
6733     if (*text != NULLCHAR) {
6734         strcpy(icon, text);
6735         strcpy(title, text);
6736     } else if (appData.icsActive) {
6737         sprintf(icon, "%s", appData.icsHost);
6738         sprintf(title, "%s: %s", programName, appData.icsHost);
6739     } else if (appData.cmailGameName[0] != NULLCHAR) {
6740         sprintf(icon, "%s", "CMail");
6741         sprintf(title, "%s: %s", programName, "CMail");
6742     } else if (appData.noChessProgram) {
6743         strcpy(icon, programName);
6744         strcpy(title, programName);
6745     } else {
6746         strcpy(icon, first.tidy);
6747         sprintf(title, "%s: %s", programName, first.tidy);
6748     }
6749     i = 0;
6750     XtSetArg(args[i], XtNiconName, (XtArgVal) icon);    i++;
6751     XtSetArg(args[i], XtNtitle, (XtArgVal) title);      i++;
6752     XtSetValues(shellWidget, args, i);
6753 }
6754
6755
6756 void DisplayError(message, error)
6757      String message;
6758      int error;
6759 {
6760     char buf[MSG_SIZ];
6761
6762     if (error == 0) {
6763         if (appData.debugMode || appData.matchMode) {
6764             fprintf(stderr, "%s: %s\n", programName, message);
6765         }
6766     } else {
6767         if (appData.debugMode || appData.matchMode) {
6768             fprintf(stderr, "%s: %s: %s\n",
6769                     programName, message, strerror(error));
6770         }
6771         sprintf(buf, "%s: %s", message, strerror(error));
6772         message = buf;
6773     }   
6774     ErrorPopUp("Error", message, FALSE);
6775 }
6776
6777
6778 void DisplayMoveError(message)
6779      String message;
6780 {
6781     fromX = fromY = -1;
6782     ClearHighlights();
6783     DrawPosition(FALSE, NULL);
6784     if (appData.debugMode || appData.matchMode) {
6785         fprintf(stderr, "%s: %s\n", programName, message);
6786     }
6787     if (appData.popupMoveErrors) {
6788         ErrorPopUp("Error", message, FALSE);
6789     } else {
6790         DisplayMessage(message, "");
6791     }
6792 }
6793
6794
6795 void DisplayFatalError(message, error, status)
6796      String message;
6797      int error, status;
6798 {
6799     char buf[MSG_SIZ];
6800
6801     errorExitStatus = status;
6802     if (error == 0) {
6803         fprintf(stderr, "%s: %s\n", programName, message);
6804     } else {
6805         fprintf(stderr, "%s: %s: %s\n",
6806                 programName, message, strerror(error));
6807         sprintf(buf, "%s: %s", message, strerror(error));
6808         message = buf;
6809     }
6810     if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
6811       ErrorPopUp(status ? "Fatal Error" : "Exiting", message, TRUE);
6812     } else {
6813       ExitEvent(status);
6814     }
6815 }
6816
6817 void DisplayInformation(message)
6818      String message;
6819 {
6820     ErrorPopDown();
6821     ErrorPopUp("Information", message, TRUE);
6822 }
6823
6824 void DisplayNote(message)
6825      String message;
6826 {
6827     ErrorPopDown();
6828     ErrorPopUp("Note", message, FALSE);
6829 }
6830
6831 static int
6832 NullXErrorCheck(dpy, error_event)
6833      Display *dpy;
6834      XErrorEvent *error_event;
6835 {
6836     return 0;
6837 }
6838
6839 void DisplayIcsInteractionTitle(message)
6840      String message;
6841 {
6842   if (oldICSInteractionTitle == NULL) {
6843     /* Magic to find the old window title, adapted from vim */
6844     char *wina = getenv("WINDOWID");
6845     if (wina != NULL) {
6846       Window win = (Window) atoi(wina);
6847       Window root, parent, *children;
6848       unsigned int nchildren;
6849       int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
6850       for (;;) {
6851         if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
6852         if (!XQueryTree(xDisplay, win, &root, &parent,
6853                         &children, &nchildren)) break;
6854         if (children) XFree((void *)children);
6855         if (parent == root || parent == 0) break;
6856         win = parent;
6857       }
6858       XSetErrorHandler(oldHandler);
6859     }
6860     if (oldICSInteractionTitle == NULL) {
6861       oldICSInteractionTitle = "xterm"; 
6862     }
6863   }  
6864   printf("\033]0;%s\007", message);
6865   fflush(stdout);
6866 }
6867
6868 char pendingReplyPrefix[MSG_SIZ];
6869 ProcRef pendingReplyPR;
6870
6871 void AskQuestionProc(w, event, prms, nprms)
6872      Widget w;
6873      XEvent *event;
6874      String *prms;
6875      Cardinal *nprms;
6876 {
6877     if (*nprms != 4) {
6878         fprintf(stderr, "AskQuestionProc needed 4 parameters, got %d\n",
6879                 *nprms);
6880         return;
6881     }
6882     AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
6883 }
6884
6885 void AskQuestionPopDown()
6886 {
6887     if (!askQuestionUp) return;
6888     XtPopdown(askQuestionShell);
6889     XtDestroyWidget(askQuestionShell);
6890     askQuestionUp = False;
6891 }
6892
6893 void AskQuestionReplyAction(w, event, prms, nprms)
6894      Widget w;
6895      XEvent *event;
6896      String *prms;
6897      Cardinal *nprms;
6898 {
6899     char buf[MSG_SIZ];
6900     int err;
6901     String reply;
6902
6903     reply = XawDialogGetValueString(w = XtParent(w));
6904     strcpy(buf, pendingReplyPrefix);
6905     if (*buf) strcat(buf, " ");
6906     strcat(buf, reply);
6907     strcat(buf, "\n");
6908     OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
6909     AskQuestionPopDown();
6910
6911     if (err) DisplayFatalError("Error writing to chess program", err, 0);
6912 }
6913
6914 void AskQuestionCallback(w, client_data, call_data)
6915      Widget w;
6916      XtPointer client_data, call_data;
6917 {
6918     String name;
6919     Arg args[16];
6920
6921     XtSetArg(args[0], XtNlabel, &name);
6922     XtGetValues(w, args, 1);
6923     
6924     if (strcmp(name, "cancel") == 0) {
6925         AskQuestionPopDown();
6926     } else {
6927         AskQuestionReplyAction(w, NULL, NULL, NULL);
6928     }
6929 }
6930
6931 void AskQuestion(title, question, replyPrefix, pr)
6932      char *title, *question, *replyPrefix;
6933      ProcRef pr;
6934 {
6935     Arg args[16];
6936     Widget popup, layout, dialog, edit;
6937     Window root, child;
6938     int x, y, i;
6939     int win_x, win_y;
6940     unsigned int mask;
6941     
6942     strcpy(pendingReplyPrefix, replyPrefix);
6943     pendingReplyPR = pr;
6944     
6945     i = 0;
6946     XtSetArg(args[i], XtNresizable, True); i++;
6947     XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
6948     askQuestionShell = popup =
6949       XtCreatePopupShell(title, transientShellWidgetClass,
6950                          shellWidget, args, i);
6951     
6952     layout =
6953       XtCreateManagedWidget(layoutName, formWidgetClass, popup,
6954                             layoutArgs, XtNumber(layoutArgs));
6955   
6956     i = 0;
6957     XtSetArg(args[i], XtNlabel, question); i++;
6958     XtSetArg(args[i], XtNvalue, ""); i++;
6959     XtSetArg(args[i], XtNborderWidth, 0); i++;
6960     dialog = XtCreateManagedWidget("question", dialogWidgetClass,
6961                                    layout, args, i);
6962     
6963     XawDialogAddButton(dialog, "enter", AskQuestionCallback,
6964                        (XtPointer) dialog);
6965     XawDialogAddButton(dialog, "cancel", AskQuestionCallback,
6966                        (XtPointer) dialog);
6967
6968     XtRealizeWidget(popup);
6969     CatchDeleteWindow(popup, "AskQuestionPopDown");
6970     
6971     XQueryPointer(xDisplay, xBoardWindow, &root, &child,
6972                   &x, &y, &win_x, &win_y, &mask);
6973     
6974     XtSetArg(args[0], XtNx, x - 10);
6975     XtSetArg(args[1], XtNy, y - 30);
6976     XtSetValues(popup, args, 2);
6977     
6978     XtPopup(popup, XtGrabExclusive);
6979     askQuestionUp = True;
6980     
6981     edit = XtNameToWidget(dialog, "*value");
6982     XtSetKeyboardFocus(popup, edit);
6983 }
6984
6985
6986 void
6987 PlaySound(name)
6988      char *name;
6989 {
6990   if (*name == NULLCHAR) {
6991     return;
6992   } else if (strcmp(name, "$") == 0) {
6993     putc(BELLCHAR, stderr);
6994   } else {
6995     char buf[2048];
6996     sprintf(buf, "%s '%s' &", appData.soundProgram, name);
6997     system(buf);
6998   }
6999 }
7000
7001 void
7002 RingBell()
7003 {
7004   PlaySound(appData.soundMove);
7005 }
7006
7007 void
7008 PlayIcsWinSound()
7009 {
7010   PlaySound(appData.soundIcsWin);
7011 }
7012
7013 void
7014 PlayIcsLossSound()
7015 {
7016   PlaySound(appData.soundIcsLoss);
7017 }
7018
7019 void
7020 PlayIcsDrawSound()
7021 {
7022   PlaySound(appData.soundIcsDraw);
7023 }
7024
7025 void
7026 PlayIcsUnfinishedSound()
7027 {
7028   PlaySound(appData.soundIcsUnfinished);
7029 }
7030
7031 void
7032 PlayAlarmSound()
7033 {
7034   PlaySound(appData.soundIcsAlarm);
7035 }
7036
7037 void
7038 EchoOn()
7039 {
7040     system("stty echo");
7041 }
7042
7043 void
7044 EchoOff()
7045 {
7046     system("stty -echo");
7047 }
7048
7049 void
7050 Colorize(cc, continuation)
7051      ColorClass cc;
7052      int continuation;
7053 {
7054     char buf[MSG_SIZ];
7055     int count, outCount, error;
7056
7057     if (textColors[(int)cc].bg > 0) {
7058         if (textColors[(int)cc].fg > 0) {
7059             sprintf(buf, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7060                     textColors[(int)cc].fg, textColors[(int)cc].bg);
7061         } else {
7062             sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7063                     textColors[(int)cc].bg);
7064         }
7065     } else {
7066         if (textColors[(int)cc].fg > 0) {
7067             sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7068                     textColors[(int)cc].fg);
7069         } else {
7070             sprintf(buf, "\033[0;%dm", textColors[(int)cc].attr);
7071         }
7072     }
7073     count = strlen(buf);
7074     outCount = OutputToProcess(NoProc, buf, count, &error);
7075     if (outCount < count) {
7076         DisplayFatalError("Error writing to display", error, 1);
7077     }
7078
7079     if (continuation) return;
7080     switch (cc) {
7081     case ColorShout:
7082       PlaySound(appData.soundShout);
7083       break;
7084     case ColorSShout:
7085       PlaySound(appData.soundSShout);
7086       break;
7087     case ColorChannel1:
7088       PlaySound(appData.soundChannel1);
7089       break;
7090     case ColorChannel:
7091       PlaySound(appData.soundChannel);
7092       break;
7093     case ColorKibitz:
7094       PlaySound(appData.soundKibitz);
7095       break;
7096     case ColorTell:
7097       PlaySound(appData.soundTell);
7098       break;
7099     case ColorChallenge:
7100       PlaySound(appData.soundChallenge);
7101       break;
7102     case ColorRequest:
7103       PlaySound(appData.soundRequest);
7104       break;
7105     case ColorSeek:
7106       PlaySound(appData.soundSeek);
7107       break;
7108     case ColorNormal:
7109     case ColorNone:
7110     default:
7111       break;
7112     }
7113 }
7114
7115 char *UserName()
7116 {
7117     return getpwuid(getuid())->pw_name;
7118 }
7119
7120 static char *ExpandPathName(path)
7121      char *path;
7122 {
7123     static char static_buf[2000];
7124     char *d, *s, buf[2000];
7125     struct passwd *pwd;
7126   
7127     s = path;
7128     d = static_buf;
7129
7130     while (*s && isspace(*s))
7131       ++s;
7132
7133     if (!*s) {
7134         *d = 0;
7135         return static_buf;
7136     }
7137
7138     if (*s == '~') {
7139         if (*(s+1) == '/') {
7140             strcpy(d, getpwuid(getuid())->pw_dir);
7141             strcat(d, s+1);
7142         }
7143         else {
7144             strcpy(buf, s+1);
7145             *strchr(buf, '/') = 0;
7146             pwd = getpwnam(buf);
7147             if (!pwd)
7148               {
7149                   fprintf(stderr, "ERROR: Unknown user %s (in path %s)\n",
7150                           buf, path);
7151                   return NULL;
7152               }
7153             strcpy(d, pwd->pw_dir);
7154             strcat(d, strchr(s+1, '/'));
7155         }
7156     }
7157     else
7158       strcpy(d, s);
7159
7160     return static_buf;
7161 }  
7162
7163 char *HostName()
7164 {
7165     static char host_name[MSG_SIZ];
7166     
7167 #if HAVE_GETHOSTNAME
7168     gethostname(host_name, MSG_SIZ);
7169     return host_name;
7170 #else  /* not HAVE_GETHOSTNAME */
7171 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7172     sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7173     return host_name;
7174 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7175     return "localhost";
7176 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7177 #endif /* not HAVE_GETHOSTNAME */
7178 }
7179
7180 XtIntervalId delayedEventTimerXID = 0;
7181 DelayedEventCallback delayedEventCallback = 0;
7182
7183 void
7184 FireDelayedEvent()
7185 {
7186     delayedEventTimerXID = 0;
7187     delayedEventCallback();
7188 }
7189
7190 void
7191 ScheduleDelayedEvent(cb, millisec)
7192      DelayedEventCallback cb; long millisec;
7193 {
7194     delayedEventCallback = cb;
7195     delayedEventTimerXID =
7196       XtAppAddTimeOut(appContext, millisec,
7197                       (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7198 }
7199
7200 DelayedEventCallback
7201 GetDelayedEvent()
7202 {
7203   if (delayedEventTimerXID) {
7204     return delayedEventCallback;
7205   } else {
7206     return NULL;
7207   }
7208 }
7209
7210 void
7211 CancelDelayedEvent()
7212 {
7213   if (delayedEventTimerXID) {
7214     XtRemoveTimeOut(delayedEventTimerXID);
7215     delayedEventTimerXID = 0;
7216   }
7217 }
7218
7219 XtIntervalId loadGameTimerXID = 0;
7220
7221 int LoadGameTimerRunning()
7222 {
7223     return loadGameTimerXID != 0;
7224 }
7225
7226 int StopLoadGameTimer()
7227 {
7228     if (loadGameTimerXID != 0) {
7229         XtRemoveTimeOut(loadGameTimerXID);
7230         loadGameTimerXID = 0;
7231         return TRUE;
7232     } else {
7233         return FALSE;
7234     }
7235 }
7236
7237 void
7238 LoadGameTimerCallback(arg, id)
7239      XtPointer arg;
7240      XtIntervalId *id;
7241 {
7242     loadGameTimerXID = 0;
7243     AutoPlayGameLoop();
7244 }
7245
7246 void
7247 StartLoadGameTimer(millisec)
7248      long millisec;
7249 {
7250     loadGameTimerXID =
7251       XtAppAddTimeOut(appContext, millisec,
7252                       (XtTimerCallbackProc) LoadGameTimerCallback,
7253                       (XtPointer) 0);
7254 }
7255
7256 XtIntervalId analysisClockXID = 0;
7257
7258 void
7259 AnalysisClockCallback(arg, id)
7260      XtPointer arg;
7261      XtIntervalId *id;
7262 {
7263     if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
7264         AnalysisPeriodicEvent(0);
7265         StartAnalysisClock();
7266     }
7267 }
7268
7269 void
7270 StartAnalysisClock()
7271 {
7272     analysisClockXID =
7273       XtAppAddTimeOut(appContext, 2000,
7274                       (XtTimerCallbackProc) AnalysisClockCallback,
7275                       (XtPointer) 0);
7276 }
7277
7278 XtIntervalId clockTimerXID = 0;
7279
7280 int ClockTimerRunning()
7281 {
7282     return clockTimerXID != 0;
7283 }
7284
7285 int StopClockTimer()
7286 {
7287     if (clockTimerXID != 0) {
7288         XtRemoveTimeOut(clockTimerXID);
7289         clockTimerXID = 0;
7290         return TRUE;
7291     } else {
7292         return FALSE;
7293     }
7294 }
7295
7296 void
7297 ClockTimerCallback(arg, id)
7298      XtPointer arg;
7299      XtIntervalId *id;
7300 {
7301     clockTimerXID = 0;
7302     DecrementClocks();
7303 }
7304
7305 void
7306 StartClockTimer(millisec)
7307      long millisec;
7308 {
7309     clockTimerXID =
7310       XtAppAddTimeOut(appContext, millisec,
7311                       (XtTimerCallbackProc) ClockTimerCallback,
7312                       (XtPointer) 0);
7313 }
7314
7315 void
7316 DisplayTimerLabel(w, color, timer, highlight)
7317      Widget w;
7318      char *color;
7319      long timer;
7320      int highlight;
7321 {
7322     char buf[MSG_SIZ];
7323     Arg args[16];
7324     
7325     if (appData.clockMode) {
7326         sprintf(buf, "%s: %s", color, TimeString(timer));
7327         XtSetArg(args[0], XtNlabel, buf);
7328     } else {
7329         sprintf(buf, "%s  ", color);
7330         XtSetArg(args[0], XtNlabel, buf);
7331     }
7332     
7333     if (highlight) {
7334         XtSetArg(args[1], XtNbackground, timerForegroundPixel);
7335         XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7336     } else {
7337         XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7338         XtSetArg(args[2], XtNforeground, timerForegroundPixel);
7339     }
7340     
7341     XtSetValues(w, args, 3);
7342 }
7343
7344 void
7345 DisplayWhiteClock(timeRemaining, highlight)
7346      long timeRemaining;
7347      int highlight;
7348 {
7349     Arg args[16];
7350     DisplayTimerLabel(whiteTimerWidget, "White", timeRemaining, highlight);
7351     if (highlight && iconPixmap == bIconPixmap) {
7352         iconPixmap = wIconPixmap;
7353         XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7354         XtSetValues(shellWidget, args, 1);
7355     }
7356 }
7357
7358 void
7359 DisplayBlackClock(timeRemaining, highlight)
7360      long timeRemaining;
7361      int highlight;
7362 {
7363     Arg args[16];
7364     DisplayTimerLabel(blackTimerWidget, "Black", timeRemaining, highlight);
7365     if (highlight && iconPixmap == wIconPixmap) {
7366         iconPixmap = bIconPixmap;
7367         XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7368         XtSetValues(shellWidget, args, 1);
7369     }
7370 }
7371
7372 #define CPNone 0
7373 #define CPReal 1
7374 #define CPComm 2
7375 #define CPSock 3
7376 #define CPLoop 4
7377 typedef int CPKind;
7378
7379 typedef struct {
7380     CPKind kind;
7381     int pid;
7382     int fdTo, fdFrom;  
7383 } ChildProc;
7384
7385
7386 int StartChildProcess(cmdLine, dir, pr)
7387      char *cmdLine; 
7388      char *dir;
7389      ProcRef *pr;
7390 {
7391     char *argv[64], *p;
7392     int i, pid;
7393     int to_prog[2], from_prog[2];
7394     ChildProc *cp;
7395     char buf[MSG_SIZ];
7396     
7397     if (appData.debugMode) {
7398         fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7399     }
7400
7401     /* We do NOT feed the cmdLine to the shell; we just
7402        parse it into blank-separated arguments in the
7403        most simple-minded way possible.
7404        */
7405     i = 0;
7406     strcpy(buf, cmdLine);
7407     p = buf;
7408     for (;;) {
7409         argv[i++] = p;
7410         p = strchr(p, ' ');
7411         if (p == NULL) break;
7412         *p++ = NULLCHAR;
7413     }
7414     argv[i] = NULL;
7415
7416     SetUpChildIO(to_prog, from_prog);
7417
7418     if ((pid = fork()) == 0) {
7419         /* Child process */
7420         dup2(to_prog[0], 0);
7421         dup2(from_prog[1], 1);
7422         close(to_prog[0]);
7423         close(to_prog[1]);
7424         close(from_prog[0]);
7425         close(from_prog[1]);
7426         dup2(1, fileno(stderr)); /* force stderr to the pipe */
7427
7428         if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7429             perror(dir);
7430             exit(1);
7431         }
7432
7433         execvp(argv[0], argv);
7434         
7435         /* If we get here, exec failed */
7436         perror(argv[0]);
7437         exit(1);
7438     }
7439     
7440     /* Parent process */
7441     close(to_prog[0]);
7442     close(from_prog[1]);
7443     
7444     cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7445     cp->kind = CPReal;
7446     cp->pid = pid;
7447     cp->fdFrom = from_prog[0];
7448     cp->fdTo = to_prog[1];
7449     *pr = (ProcRef) cp;
7450     return 0;
7451 }
7452
7453 void
7454 DestroyChildProcess(pr, signal)
7455      ProcRef pr;
7456      int signal;
7457 {
7458     ChildProc *cp = (ChildProc *) pr;
7459
7460     if (cp->kind != CPReal) return;
7461     cp->kind = CPNone;
7462     if (signal) {
7463       kill(cp->pid, SIGTERM);
7464     }
7465     /* Process is exiting either because of the kill or because of
7466        a quit command sent by the backend; either way, wait for it to die.
7467     */
7468     wait((int *) 0);
7469     close(cp->fdFrom);
7470     close(cp->fdTo);
7471 }
7472
7473 void
7474 InterruptChildProcess(pr)
7475      ProcRef pr;
7476 {
7477     ChildProc *cp = (ChildProc *) pr;
7478
7479     if (cp->kind != CPReal) return;
7480     (void) kill(cp->pid, SIGINT); /* stop it thinking */
7481 }
7482
7483 int OpenTelnet(host, port, pr)
7484      char *host;
7485      char *port;
7486      ProcRef *pr;
7487 {
7488     char cmdLine[MSG_SIZ];
7489
7490     if (port[0] == NULLCHAR) {
7491         sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
7492     } else {
7493         sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
7494     }
7495     return StartChildProcess(cmdLine, "", pr);
7496 }
7497
7498 int OpenTCP(host, port, pr)
7499      char *host;
7500      char *port;
7501      ProcRef *pr;
7502 {
7503 #if OMIT_SOCKETS
7504     DisplayFatalError("Socket support is not configured in", 0, 2);
7505 #else  /* !OMIT_SOCKETS */
7506     int s;
7507     struct sockaddr_in sa;
7508     struct hostent     *hp;
7509     unsigned short uport;
7510     ChildProc *cp;
7511
7512     if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7513         return errno;
7514     }
7515
7516     memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7517     sa.sin_family = AF_INET;
7518     sa.sin_addr.s_addr = INADDR_ANY;
7519     uport = (unsigned short) 0;
7520     sa.sin_port = htons(uport);
7521     if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7522         return errno;
7523     }
7524
7525     memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7526     if (!(hp = gethostbyname(host))) {
7527         int b0, b1, b2, b3;
7528         if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7529             hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7530             hp->h_addrtype = AF_INET;
7531             hp->h_length = 4;
7532             hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7533             hp->h_addr_list[0] = (char *) malloc(4);
7534             hp->h_addr_list[0][0] = b0;
7535             hp->h_addr_list[0][1] = b1;
7536             hp->h_addr_list[0][2] = b2;
7537             hp->h_addr_list[0][3] = b3;
7538         } else {
7539             return ENOENT;
7540         }
7541     }
7542     sa.sin_family = hp->h_addrtype;
7543     uport = (unsigned short) atoi(port);
7544     sa.sin_port = htons(uport);
7545     memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7546
7547     if (connect(s, (struct sockaddr *) &sa, 
7548                 sizeof(struct sockaddr_in)) < 0) {
7549         return errno;
7550     }
7551
7552     cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7553     cp->kind = CPSock;
7554     cp->pid = 0;
7555     cp->fdFrom = s;
7556     cp->fdTo = s;
7557     *pr = (ProcRef) cp;
7558
7559 #endif /* !OMIT_SOCKETS */
7560
7561     return 0;
7562 }
7563
7564 int OpenCommPort(name, pr)
7565      char *name;
7566      ProcRef *pr;
7567 {
7568     int fd;
7569     ChildProc *cp;
7570
7571     fd = open(name, 2, 0);
7572     if (fd < 0) return errno;
7573
7574     cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7575     cp->kind = CPComm;
7576     cp->pid = 0;
7577     cp->fdFrom = fd;
7578     cp->fdTo = fd;
7579     *pr = (ProcRef) cp;
7580
7581     return 0;
7582 }
7583
7584 int OpenLoopback(pr)
7585      ProcRef *pr;
7586 {
7587     ChildProc *cp;
7588     int to[2], from[2];
7589
7590     SetUpChildIO(to, from);
7591
7592     cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7593     cp->kind = CPLoop;
7594     cp->pid = 0;
7595     cp->fdFrom = to[0];         /* note not from[0]; we are doing a loopback */
7596     cp->fdTo = to[1];
7597     *pr = (ProcRef) cp;
7598
7599     return 0;
7600 }
7601
7602 int OpenRcmd(host, user, cmd, pr)
7603      char *host, *user, *cmd;
7604      ProcRef *pr;
7605 {
7606     DisplayFatalError("internal rcmd not implemented for Unix", 0, 1);
7607     return -1;
7608 }    
7609
7610 #define INPUT_SOURCE_BUF_SIZE 8192
7611
7612 typedef struct {
7613     CPKind kind;
7614     int fd;
7615     int lineByLine;
7616     char *unused;
7617     InputCallback func;
7618     XtInputId xid;
7619     char buf[INPUT_SOURCE_BUF_SIZE];
7620     VOIDSTAR closure;
7621 } InputSource;
7622
7623 void
7624 DoInputCallback(closure, source, xid) 
7625      caddr_t closure;
7626      int *source;
7627      XtInputId *xid;
7628 {
7629     InputSource *is = (InputSource *) closure;
7630     int count;
7631     int error;
7632     char *p, *q;
7633
7634     if (is->lineByLine) {
7635         count = read(is->fd, is->unused,
7636                      INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7637         if (count <= 0) {
7638             (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7639             return;
7640         }
7641         is->unused += count;
7642         p = is->buf;
7643         while (p < is->unused) {
7644             q = memchr(p, '\n', is->unused - p);
7645             if (q == NULL) break;
7646             q++;
7647             (is->func)(is, is->closure, p, q - p, 0);
7648             p = q;
7649         }
7650         q = is->buf;
7651         while (p < is->unused) {
7652             *q++ = *p++;
7653         }
7654         is->unused = q;
7655     } else {
7656         count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
7657         if (count == -1)
7658           error = errno;
7659         else
7660           error = 0;
7661         (is->func)(is, is->closure, is->buf, count, error);
7662     }   
7663 }
7664
7665 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
7666      ProcRef pr;
7667      int lineByLine;
7668      InputCallback func;
7669      VOIDSTAR closure;
7670 {
7671     InputSource *is;
7672     ChildProc *cp = (ChildProc *) pr;
7673
7674     is = (InputSource *) calloc(1, sizeof(InputSource));
7675     is->lineByLine = lineByLine;
7676     is->func = func;
7677     if (pr == NoProc) {
7678         is->kind = CPReal;
7679         is->fd = fileno(stdin);
7680     } else {
7681         is->kind = cp->kind;
7682         is->fd = cp->fdFrom;
7683     }
7684     if (lineByLine) {
7685         is->unused = is->buf;
7686     }
7687     
7688     is->xid = XtAppAddInput(appContext, is->fd,
7689                             (XtPointer) (XtInputReadMask),
7690                             (XtInputCallbackProc) DoInputCallback,
7691                             (XtPointer) is);
7692     is->closure = closure;
7693     return (InputSourceRef) is;
7694 }
7695
7696 void
7697 RemoveInputSource(isr)
7698      InputSourceRef isr;
7699 {
7700     InputSource *is = (InputSource *) isr;
7701
7702     if (is->xid == 0) return;
7703     XtRemoveInput(is->xid);
7704     is->xid = 0;
7705 }
7706
7707 int OutputToProcess(pr, message, count, outError)
7708      ProcRef pr;
7709      char *message;
7710      int count;
7711      int *outError;
7712 {
7713     ChildProc *cp = (ChildProc *) pr;
7714     int outCount;
7715
7716     if (pr == NoProc)
7717       outCount = fwrite(message, 1, count, stdout);
7718     else
7719       outCount = write(cp->fdTo, message, count);
7720
7721     if (outCount == -1)
7722       *outError = errno;
7723     else
7724       *outError = 0;
7725
7726     return outCount;
7727 }
7728
7729 /* Output message to process, with "ms" milliseconds of delay
7730    between each character. This is needed when sending the logon
7731    script to ICC, which for some reason doesn't like the
7732    instantaneous send. */
7733 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
7734      ProcRef pr;
7735      char *message;
7736      int count;
7737      int *outError;
7738      long msdelay;
7739 {
7740     ChildProc *cp = (ChildProc *) pr;
7741     int outCount = 0;
7742     int r;
7743     
7744     while (count--) {
7745         r = write(cp->fdTo, message++, 1);
7746         if (r == -1) {
7747             *outError = errno;
7748             return outCount;
7749         }
7750         ++outCount;
7751         if (msdelay >= 0)
7752           TimeDelay(msdelay);
7753     }
7754
7755     return outCount;
7756 }
7757
7758 /****   Animation code by Hugh Fisher, DCS, ANU.
7759
7760         Known problem: if a window overlapping the board is
7761         moved away while a piece is being animated underneath,
7762         the newly exposed area won't be updated properly.
7763         I can live with this.
7764
7765         Known problem: if you look carefully at the animation
7766         of pieces in mono mode, they are being drawn as solid
7767         shapes without interior detail while moving. Fixing
7768         this would be a major complication for minimal return.
7769 ****/
7770
7771 /*      Masks for XPM pieces. Black and white pieces can have
7772         different shapes, but in the interest of retaining my
7773         sanity pieces must have the same outline on both light
7774         and dark squares, and all pieces must use the same
7775         background square colors/images.                */
7776
7777 static void
7778 CreateAnimMasks (pieceDepth)
7779      int pieceDepth;
7780 {
7781   ChessSquare   piece;
7782   Pixmap        buf;
7783   GC            bufGC, maskGC;
7784   int           kind, n;
7785   unsigned long plane;
7786   XGCValues     values;
7787
7788   /* Need a bitmap just to get a GC with right depth */
7789   buf = XCreatePixmap(xDisplay, xBoardWindow,
7790                         8, 8, 1);
7791   values.foreground = 1;
7792   values.background = 0;
7793   /* Don't use XtGetGC, not read only */
7794   maskGC = XCreateGC(xDisplay, buf,
7795                     GCForeground | GCBackground, &values);
7796   XFreePixmap(xDisplay, buf);
7797
7798   buf = XCreatePixmap(xDisplay, xBoardWindow,
7799                       squareSize, squareSize, pieceDepth);            
7800   values.foreground = XBlackPixel(xDisplay, xScreen);
7801   values.background = XWhitePixel(xDisplay, xScreen);
7802   bufGC = XCreateGC(xDisplay, buf,
7803                     GCForeground | GCBackground, &values);
7804
7805   for (piece = WhitePawn; piece <= BlackKing; piece++) {
7806     /* Begin with empty mask */
7807     xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
7808                                  squareSize, squareSize, 1);
7809     XSetFunction(xDisplay, maskGC, GXclear);
7810     XFillRectangle(xDisplay, xpmMask[piece], maskGC,
7811                    0, 0, squareSize, squareSize);
7812                    
7813     /* Take a copy of the piece */
7814     if (White(piece))
7815       kind = 0;
7816     else
7817       kind = 2;
7818     XSetFunction(xDisplay, bufGC, GXcopy);
7819     XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % 6],
7820               buf, bufGC,
7821               0, 0, squareSize, squareSize, 0, 0);
7822               
7823     /* XOR the background (light) over the piece */
7824     XSetFunction(xDisplay, bufGC, GXxor);
7825     if (useImageSqs)
7826       XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
7827                 0, 0, squareSize, squareSize, 0, 0);
7828     else {
7829       XSetForeground(xDisplay, bufGC, lightSquareColor);
7830       XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
7831     }
7832     
7833     /* We now have an inverted piece image with the background
7834        erased. Construct mask by just selecting all the non-zero
7835        pixels - no need to reconstruct the original image.      */
7836     XSetFunction(xDisplay, maskGC, GXor);
7837     plane = 1;
7838     /* Might be quicker to download an XImage and create bitmap
7839        data from it rather than this N copies per piece, but it
7840        only takes a fraction of a second and there is a much
7841        longer delay for loading the pieces.             */
7842     for (n = 0; n < pieceDepth; n ++) {
7843       XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
7844                  0, 0, squareSize, squareSize,
7845                  0, 0, plane);
7846       plane = plane << 1;
7847     }
7848   }
7849   /* Clean up */
7850   XFreePixmap(xDisplay, buf);
7851   XFreeGC(xDisplay, bufGC);
7852   XFreeGC(xDisplay, maskGC);
7853 }
7854
7855 static void
7856 InitAnimState (anim, info)
7857   AnimState * anim;
7858   XWindowAttributes * info;
7859 {
7860   XtGCMask  mask;
7861   XGCValues values;
7862   
7863   /* Each buffer is square size, same depth as window */
7864   anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
7865                         squareSize, squareSize, info->depth);
7866   anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
7867                         squareSize, squareSize, info->depth);
7868
7869   /* Create a plain GC for blitting */
7870   mask = GCForeground | GCBackground | GCFunction |
7871          GCPlaneMask | GCGraphicsExposures;
7872   values.foreground = XBlackPixel(xDisplay, xScreen);
7873   values.background = XWhitePixel(xDisplay, xScreen);
7874   values.function   = GXcopy;
7875   values.plane_mask = AllPlanes;
7876   values.graphics_exposures = False;
7877   anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
7878
7879   /* Piece will be copied from an existing context at
7880      the start of each new animation/drag. */
7881   anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
7882
7883   /* Outline will be a read-only copy of an existing */
7884   anim->outlineGC = None;
7885 }
7886
7887 static void
7888 CreateAnimVars ()
7889 {
7890   static int done = 0;
7891   XWindowAttributes info;
7892
7893   if (done) return;
7894   done = 1;
7895   XGetWindowAttributes(xDisplay, xBoardWindow, &info);
7896   
7897   InitAnimState(&game, &info);
7898   InitAnimState(&player, &info);
7899   
7900   /* For XPM pieces, we need bitmaps to use as masks. */
7901   if (useImages)
7902     CreateAnimMasks(info.depth);
7903 }
7904
7905 #ifndef HAVE_USLEEP
7906
7907 static Boolean frameWaiting;
7908
7909 static RETSIGTYPE FrameAlarm (sig)
7910      int sig;
7911 {
7912   frameWaiting = False;
7913   /* In case System-V style signals.  Needed?? */
7914   signal(SIGALRM, FrameAlarm);
7915 }
7916
7917 static void
7918 FrameDelay (time)
7919      int time;
7920 {
7921   struct itimerval delay;
7922   
7923   XSync(xDisplay, False);
7924
7925   if (time > 0) {
7926     frameWaiting = True;
7927     signal(SIGALRM, FrameAlarm);
7928     delay.it_interval.tv_sec = 
7929       delay.it_value.tv_sec = time / 1000;
7930     delay.it_interval.tv_usec = 
7931       delay.it_value.tv_usec = (time % 1000) * 1000;
7932     setitimer(ITIMER_REAL, &delay, NULL);
7933 #if 0
7934     /* Ugh -- busy-wait! --tpm */
7935     while (frameWaiting); 
7936 #else
7937     while (frameWaiting) pause();
7938 #endif
7939     delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
7940     delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
7941     setitimer(ITIMER_REAL, &delay, NULL);
7942   }
7943 }
7944
7945 #else
7946
7947 static void
7948 FrameDelay (time)
7949      int time;
7950 {
7951   XSync(xDisplay, False);
7952   if (time > 0)
7953     usleep(time * 1000);
7954 }
7955
7956 #endif
7957
7958 /*      Convert board position to corner of screen rect and color       */
7959
7960 static void
7961 ScreenSquare(column, row, pt, color)
7962      int column; int row; XPoint * pt; int * color;
7963 {
7964   if (flipView) {
7965     pt->x = lineGap + ((BOARD_SIZE-1)-column) * (squareSize + lineGap);
7966     pt->y = lineGap + row * (squareSize + lineGap);
7967   } else {
7968     pt->x = lineGap + column * (squareSize + lineGap);
7969     pt->y = lineGap + ((BOARD_SIZE-1)-row) * (squareSize + lineGap);
7970   }
7971   *color = ((column + row) % 2) == 1;
7972 }
7973
7974 /*      Convert window coords to square                 */
7975
7976 static void
7977 BoardSquare(x, y, column, row)
7978      int x; int y; int * column; int * row;
7979 {
7980   *column = EventToSquare(x, BOARD_SIZE);
7981   if (flipView && *column >= 0)
7982     *column = BOARD_SIZE - 1 - *column;
7983   *row = EventToSquare(y, BOARD_SIZE);
7984   if (!flipView && *row >= 0)
7985     *row = BOARD_SIZE - 1 - *row;
7986 }
7987
7988 /*   Utilities  */
7989
7990 #undef Max  /* just in case */
7991 #undef Min
7992 #define Max(a, b) ((a) > (b) ? (a) : (b))
7993 #define Min(a, b) ((a) < (b) ? (a) : (b))
7994
7995 static void
7996 SetRect(rect, x, y, width, height)
7997      XRectangle * rect; int x; int y; int width; int height;
7998 {
7999   rect->x = x;
8000   rect->y = y;
8001   rect->width  = width;
8002   rect->height = height;
8003 }
8004
8005 /*      Test if two frames overlap. If they do, return
8006         intersection rect within old and location of
8007         that rect within new. */
8008         
8009 static Boolean
8010 Intersect(old, new, size, area, pt)
8011      XPoint * old; XPoint * new;
8012      int size; XRectangle * area; XPoint * pt;
8013 {
8014   if (old->x > new->x + size || new->x > old->x + size ||
8015       old->y > new->y + size || new->y > old->y + size) {
8016     return False;
8017   } else {
8018     SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8019             size - abs(old->x - new->x), size - abs(old->y - new->y));
8020     pt->x = Max(old->x - new->x, 0);
8021     pt->y = Max(old->y - new->y, 0);
8022     return True;
8023   }
8024 }
8025
8026 /*      For two overlapping frames, return the rect(s)
8027         in the old that do not intersect with the new.   */
8028         
8029 static void
8030 CalcUpdateRects(old, new, size, update, nUpdates)
8031      XPoint * old; XPoint * new; int size;
8032      XRectangle update[]; int * nUpdates;
8033 {
8034   int        count;
8035
8036   /* If old = new (shouldn't happen) then nothing to draw */
8037   if (old->x == new->x && old->y == new->y) {
8038     *nUpdates = 0;
8039     return;
8040   }
8041   /* Work out what bits overlap. Since we know the rects
8042      are the same size we don't need a full intersect calc. */
8043   count = 0;
8044   /* Top or bottom edge? */
8045   if (new->y > old->y) {
8046     SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8047     count ++;
8048   } else if (old->y > new->y) {
8049     SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8050                               size, old->y - new->y);
8051     count ++;
8052   }
8053   /* Left or right edge - don't overlap any update calculated above. */
8054   if (new->x > old->x) {
8055     SetRect(&(update[count]), old->x, Max(new->y, old->y),
8056                               new->x - old->x, size - abs(new->y - old->y));
8057     count ++;
8058   } else if (old->x > new->x) {
8059     SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8060                               old->x - new->x, size - abs(new->y - old->y));
8061     count ++;
8062   }
8063   /* Done */
8064   *nUpdates = count;
8065 }
8066
8067 /*      Generate a series of frame coords from start->mid->finish.
8068         The movement rate doubles until the half way point is
8069         reached, then halves back down to the final destination,
8070         which gives a nice slow in/out effect. The algorithmn
8071         may seem to generate too many intermediates for short
8072         moves, but remember that the purpose is to attract the
8073         viewers attention to the piece about to be moved and
8074         then to where it ends up. Too few frames would be less
8075         noticeable.                                             */
8076
8077 static void
8078 Tween(start, mid, finish, factor, frames, nFrames)
8079      XPoint * start; XPoint * mid;
8080      XPoint * finish; int factor;
8081      XPoint frames[]; int * nFrames;
8082 {
8083   int fraction, n, count;
8084
8085   count = 0;
8086
8087   /* Slow in, stepping 1/16th, then 1/8th, ... */
8088   fraction = 1;
8089   for (n = 0; n < factor; n++)
8090     fraction *= 2;
8091   for (n = 0; n < factor; n++) {
8092     frames[count].x = start->x + (mid->x - start->x) / fraction;
8093     frames[count].y = start->y + (mid->y - start->y) / fraction;
8094     count ++;
8095     fraction = fraction / 2;
8096   }
8097   
8098   /* Midpoint */
8099   frames[count] = *mid;
8100   count ++;
8101   
8102   /* Slow out, stepping 1/2, then 1/4, ... */
8103   fraction = 2;
8104   for (n = 0; n < factor; n++) {
8105     frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8106     frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8107     count ++;
8108     fraction = fraction * 2;
8109   }
8110   *nFrames = count;
8111 }
8112
8113 /*      Draw a piece on the screen without disturbing what's there      */
8114
8115 static void
8116 SelectGCMask(piece, clip, outline, mask)
8117      ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8118 {
8119   GC source;
8120
8121   /* Bitmap for piece being moved. */
8122   if (appData.monoMode) {
8123       *mask = *pieceToSolid(piece);
8124   } else if (useImages) {
8125 #if HAVE_LIBXPM
8126       *mask = xpmMask[piece];
8127 #else
8128       *mask = ximMaskPm[piece%6];
8129 #endif
8130   } else {
8131       *mask = *pieceToSolid(piece);
8132   }
8133
8134   /* GC for piece being moved. Square color doesn't matter, but
8135      since it gets modified we make a copy of the original. */
8136   if (White(piece)) {
8137     if (appData.monoMode)
8138       source = bwPieceGC;
8139     else
8140       source = wlPieceGC;
8141   } else {
8142     if (appData.monoMode)
8143       source = wbPieceGC;
8144     else
8145       source = blPieceGC;
8146   }
8147   XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8148   
8149   /* Outline only used in mono mode and is not modified */
8150   if (White(piece))
8151     *outline = bwPieceGC;
8152   else
8153     *outline = wbPieceGC;
8154 }
8155
8156 static void
8157 OverlayPiece(piece, clip, outline,  dest)
8158      ChessSquare piece; GC clip; GC outline; Drawable dest;
8159 {
8160   int   kind;
8161   
8162   if (!useImages) {
8163     /* Draw solid rectangle which will be clipped to shape of piece */
8164     XFillRectangle(xDisplay, dest, clip,
8165                    0, 0, squareSize, squareSize);
8166     if (appData.monoMode)
8167       /* Also draw outline in contrasting color for black
8168          on black / white on white cases                */
8169       XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8170                  0, 0, squareSize, squareSize, 0, 0, 1);
8171   } else {
8172     /* Copy the piece */
8173     if (White(piece))
8174       kind = 0;
8175     else
8176       kind = 2;
8177     XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % 6],
8178               dest, clip,
8179               0, 0, squareSize, squareSize,
8180               0, 0);            
8181   }
8182 }
8183
8184 /* Animate the movement of a single piece */
8185
8186 static void 
8187 BeginAnimation(anim, piece, startColor, start)
8188      AnimState *anim;
8189      ChessSquare piece;
8190      int startColor;
8191      XPoint * start;
8192 {
8193   Pixmap mask;
8194   
8195   /* The old buffer is initialised with the start square (empty) */
8196   BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8197   anim->prevFrame = *start;
8198   
8199   /* The piece will be drawn using its own bitmap as a matte    */
8200   SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8201   XSetClipMask(xDisplay, anim->pieceGC, mask);
8202 }
8203
8204 static void
8205 AnimationFrame(anim, frame, piece)
8206      AnimState *anim;
8207      XPoint *frame;
8208      ChessSquare piece;
8209 {
8210   XRectangle updates[4];
8211   XRectangle overlap;
8212   XPoint     pt;
8213   int        count, i;
8214   
8215   /* Save what we are about to draw into the new buffer */
8216   XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8217             frame->x, frame->y, squareSize, squareSize,
8218             0, 0);
8219                 
8220   /* Erase bits of the previous frame */
8221   if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8222     /* Where the new frame overlapped the previous,
8223        the contents in newBuf are wrong. */
8224     XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8225               overlap.x, overlap.y,
8226               overlap.width, overlap.height,
8227               pt.x, pt.y);
8228     /* Repaint the areas in the old that don't overlap new */
8229     CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8230     for (i = 0; i < count; i++)
8231       XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8232                 updates[i].x - anim->prevFrame.x,
8233                 updates[i].y - anim->prevFrame.y,
8234                 updates[i].width, updates[i].height,
8235                 updates[i].x, updates[i].y);
8236   } else {
8237     /* Easy when no overlap */
8238     XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8239                   0, 0, squareSize, squareSize,
8240                   anim->prevFrame.x, anim->prevFrame.y);
8241   }
8242
8243   /* Save this frame for next time round */
8244   XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8245                 0, 0, squareSize, squareSize,
8246                 0, 0);
8247   anim->prevFrame = *frame;
8248   
8249   /* Draw piece over original screen contents, not current,
8250      and copy entire rect. Wipes out overlapping piece images. */
8251   OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8252   XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8253                 0, 0, squareSize, squareSize,
8254                 frame->x, frame->y);
8255 }
8256
8257 static void
8258 EndAnimation (anim, finish)
8259      AnimState *anim;
8260      XPoint *finish;
8261 {
8262   XRectangle updates[4];
8263   XRectangle overlap;
8264   XPoint     pt;
8265   int        count, i;
8266
8267   /* The main code will redraw the final square, so we
8268      only need to erase the bits that don't overlap.    */
8269   if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8270     CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8271     for (i = 0; i < count; i++)
8272       XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8273                 updates[i].x - anim->prevFrame.x,
8274                 updates[i].y - anim->prevFrame.y,
8275                 updates[i].width, updates[i].height,
8276                 updates[i].x, updates[i].y);
8277   } else {
8278     XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8279                 0, 0, squareSize, squareSize,
8280                 anim->prevFrame.x, anim->prevFrame.y);
8281   }
8282 }
8283
8284 static void
8285 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8286      AnimState *anim;
8287      ChessSquare piece; int startColor;
8288      XPoint * start; XPoint * finish;
8289      XPoint frames[]; int nFrames;
8290 {
8291   int n;
8292
8293   BeginAnimation(anim, piece, startColor, start);
8294   for (n = 0; n < nFrames; n++) {
8295     AnimationFrame(anim, &(frames[n]), piece);
8296     FrameDelay(appData.animSpeed);
8297   }
8298   EndAnimation(anim, finish);
8299 }
8300
8301 /* Main control logic for deciding what to animate and how */
8302
8303 void
8304 AnimateMove(board, fromX, fromY, toX, toY)
8305      Board board;
8306      int fromX;
8307      int fromY;
8308      int toX;
8309      int toY;
8310 {
8311   ChessSquare piece;
8312   int hop;
8313   XPoint      start, finish, mid;
8314   XPoint      frames[kFactor * 2 + 1];
8315   int         nFrames, startColor, endColor;
8316
8317   /* Are we animating? */
8318   if (!appData.animate || appData.blindfold)
8319     return;
8320
8321   if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8322   piece = board[fromY][fromX];
8323   if (piece >= EmptySquare) return;
8324
8325 #if DONT_HOP
8326   hop = FALSE;
8327 #else
8328   hop = (piece == WhiteKnight || piece == BlackKnight);
8329 #endif
8330
8331   if (appData.debugMode) {
8332       printf("AnimateMove: piece %d %s from %d,%d to %d,%d \n",
8333              piece, hop ? "hops" : "slides", fromX, fromY, toX, toY);
8334   }
8335
8336   ScreenSquare(fromX, fromY, &start, &startColor);
8337   ScreenSquare(toX, toY, &finish, &endColor);
8338
8339   if (hop) {
8340     /* Knight: make diagonal movement then straight */
8341     if (abs(toY - fromY) < abs(toX - fromX)) {
8342        mid.x = start.x + (finish.x - start.x) / 2;
8343        mid.y = finish.y;
8344      } else {
8345        mid.x = finish.x;
8346        mid.y = start.y + (finish.y - start.y) / 2;
8347      }
8348   } else {
8349     mid.x = start.x + (finish.x - start.x) / 2;
8350     mid.y = start.y + (finish.y - start.y) / 2;
8351   }
8352   
8353   /* Don't use as many frames for very short moves */
8354   if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8355     Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8356   else
8357     Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8358   FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8359   
8360   /* Be sure end square is redrawn */
8361   damage[toY][toX] = True;
8362 }
8363
8364 static void
8365 DragPieceBegin(x, y)
8366      int x; int y;
8367 {
8368     int  boardX, boardY, color;
8369     XPoint corner;
8370
8371     /* Are we animating? */
8372     if (!appData.animateDragging || appData.blindfold)
8373       return;
8374      
8375     /* Figure out which square we start in and the
8376        mouse position relative to top left corner. */
8377     BoardSquare(x, y, &boardX, &boardY);
8378     player.startBoardX = boardX;
8379     player.startBoardY = boardY;
8380     ScreenSquare(boardX, boardY, &corner, &color);
8381     player.startSquare  = corner;
8382     player.startColor   = color;
8383 #if 0
8384     /* Start from exactly where the piece is.  This can be confusing
8385        if you start dragging far from the center of the square; most
8386        or all of the piece can be over a different square from the one
8387        the mouse pointer is in. */
8388     player.mouseDelta.x = x - corner.x;
8389     player.mouseDelta.y = y - corner.y;
8390 #else
8391     /* As soon as we start dragging, the piece will jump slightly to
8392        be centered over the mouse pointer. */
8393     player.mouseDelta.x = squareSize/2;
8394     player.mouseDelta.y = squareSize/2;
8395 #endif
8396     /* Initialise animation */
8397     player.dragPiece = PieceForSquare(boardX, boardY);
8398     /* Sanity check */
8399     if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8400         player.dragActive = True;
8401         BeginAnimation(&player, player.dragPiece, color, &corner);
8402         /* Mark this square as needing to be redrawn. Note that
8403            we don't remove the piece though, since logically (ie
8404            as seen by opponent) the move hasn't been made yet. */
8405         damage[boardY][boardX] = True;
8406     } else {
8407         player.dragActive = False;
8408     }
8409 }
8410
8411 static void
8412 DragPieceMove(x, y)
8413      int x; int y;
8414 {
8415     XPoint corner;
8416
8417     /* Are we animating? */
8418     if (!appData.animateDragging || appData.blindfold)
8419       return;
8420      
8421     /* Sanity check */
8422     if (! player.dragActive)
8423       return;
8424     /* Move piece, maintaining same relative position
8425        of mouse within square    */
8426     corner.x = x - player.mouseDelta.x;
8427     corner.y = y - player.mouseDelta.y;
8428     AnimationFrame(&player, &corner, player.dragPiece);
8429 #if HIGHDRAG
8430     if (appData.highlightDragging) {
8431         int boardX, boardY;
8432         BoardSquare(x, y, &boardX, &boardY);
8433         SetHighlights(fromX, fromY, boardX, boardY);
8434     }
8435 #endif
8436 }
8437
8438 static void
8439 DragPieceEnd(x, y)
8440      int x; int y;
8441 {
8442     int boardX, boardY, color;
8443     XPoint corner;
8444
8445     /* Are we animating? */
8446     if (!appData.animateDragging || appData.blindfold)
8447       return;
8448      
8449     /* Sanity check */
8450     if (! player.dragActive)
8451       return;
8452     /* Last frame in sequence is square piece is
8453        placed on, which may not match mouse exactly. */
8454     BoardSquare(x, y, &boardX, &boardY);
8455     ScreenSquare(boardX, boardY, &corner, &color);
8456     EndAnimation(&player, &corner);
8457
8458     /* Be sure end square is redrawn */
8459     damage[boardY][boardX] = True;
8460
8461     /* This prevents weird things happening with fast successive
8462        clicks which on my Sun at least can cause motion events
8463        without corresponding press/release. */
8464     player.dragActive = False;
8465 }
8466
8467 /* Handle expose event while piece being dragged */
8468
8469 static void
8470 DrawDragPiece ()
8471 {
8472   if (!player.dragActive || appData.blindfold)
8473     return;
8474
8475   /* What we're doing: logically, the move hasn't been made yet,
8476      so the piece is still in it's original square. But visually
8477      it's being dragged around the board. So we erase the square
8478      that the piece is on and draw it at the last known drag point. */
8479   BlankSquare(player.startSquare.x, player.startSquare.y,
8480                 player.startColor, EmptySquare, xBoardWindow);
8481   AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8482   damage[player.startBoardY][player.startBoardX] = TRUE;
8483 }
8484