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