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