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