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