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