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