Insert autoKibitz continuation lines at end of line
[xboard.git] / xboard.c
1 /*
2  * xboard.c -- X front end for XBoard
3  *
4  * Copyright 1991 by Digital Equipment Corporation, Maynard,
5  * Massachusetts. 
6  *
7  * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
8  * 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
9  *
10  * The following terms apply to Digital Equipment Corporation's copyright
11  * interest in XBoard:
12  * ------------------------------------------------------------------------
13  * All Rights Reserved
14  *
15  * Permission to use, copy, modify, and distribute this software and its
16  * documentation for any purpose and without fee is hereby granted,
17  * provided that the above copyright notice appear in all copies and that
18  * both that copyright notice and this permission notice appear in
19  * supporting documentation, and that the name of Digital not be
20  * used in advertising or publicity pertaining to distribution of the
21  * software without specific, written prior permission.
22  *
23  * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25  * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26  * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
29  * SOFTWARE.
30  * ------------------------------------------------------------------------
31  *
32  * The following terms apply to the enhanced version of XBoard
33  * distributed by the Free Software Foundation:
34  * ------------------------------------------------------------------------
35  *
36  * GNU XBoard is free software: you can redistribute it and/or modify
37  * it under the terms of the GNU General Public License as published by
38  * the Free Software Foundation, either version 3 of the License, or (at
39  * your option) any later version.
40  *
41  * GNU XBoard is distributed in the hope that it will be useful, but
42  * WITHOUT ANY WARRANTY; without even the implied warranty of
43  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44  * General Public License for more details.
45  *
46  * You should have received a copy of the GNU General Public License
47  * along with this program. If not, see http://www.gnu.org/licenses/.  *
48  *
49  *------------------------------------------------------------------------
50  ** See the file ChangeLog for a revision history.  */
51
52 #define HIGHDRAG 1
53
54 #include "config.h"
55
56 #include <stdio.h>
57 #include <ctype.h>
58 #include <signal.h>
59 #include <errno.h>
60 #include <sys/types.h>
61 #include <sys/stat.h>
62 #include <pwd.h>
63
64 #if !OMIT_SOCKETS
65 # if HAVE_SYS_SOCKET_H
66 #  include <sys/socket.h>
67 #  include <netinet/in.h>
68 #  include <netdb.h>
69 # else /* not HAVE_SYS_SOCKET_H */
70 #  if HAVE_LAN_SOCKET_H
71 #   include <lan/socket.h>
72 #   include <lan/in.h>
73 #   include <lan/netdb.h>
74 #  else /* not HAVE_LAN_SOCKET_H */
75 #   define OMIT_SOCKETS 1
76 #  endif /* not HAVE_LAN_SOCKET_H */
77 # endif /* not HAVE_SYS_SOCKET_H */
78 #endif /* !OMIT_SOCKETS */
79
80 #if STDC_HEADERS
81 # include <stdlib.h>
82 # include <string.h>
83 #else /* not STDC_HEADERS */
84 extern char *getenv();
85 # if HAVE_STRING_H
86 #  include <string.h>
87 # else /* not HAVE_STRING_H */
88 #  include <strings.h>
89 # endif /* not HAVE_STRING_H */
90 #endif /* not STDC_HEADERS */
91
92 #if HAVE_SYS_FCNTL_H
93 # include <sys/fcntl.h>
94 #else /* not HAVE_SYS_FCNTL_H */
95 # if HAVE_FCNTL_H
96 #  include <fcntl.h>
97 # endif /* HAVE_FCNTL_H */
98 #endif /* not HAVE_SYS_FCNTL_H */
99
100 #if HAVE_SYS_SYSTEMINFO_H
101 # include <sys/systeminfo.h>
102 #endif /* HAVE_SYS_SYSTEMINFO_H */
103
104 #if TIME_WITH_SYS_TIME
105 # include <sys/time.h>
106 # include <time.h>
107 #else
108 # if HAVE_SYS_TIME_H
109 #  include <sys/time.h>
110 # else
111 #  include <time.h>
112 # endif
113 #endif
114
115 #if HAVE_UNISTD_H
116 # include <unistd.h>
117 #endif
118
119 #if HAVE_SYS_WAIT_H
120 # include <sys/wait.h>
121 #endif
122
123 #if HAVE_DIRENT_H
124 # include <dirent.h>
125 # define NAMLEN(dirent) strlen((dirent)->d_name)
126 # define HAVE_DIR_STRUCT
127 #else
128 # define dirent direct
129 # define NAMLEN(dirent) (dirent)->d_namlen
130 # if HAVE_SYS_NDIR_H
131 #  include <sys/ndir.h>
132 #  define HAVE_DIR_STRUCT
133 # endif
134 # if HAVE_SYS_DIR_H
135 #  include <sys/dir.h>
136 #  define HAVE_DIR_STRUCT
137 # endif
138 # if HAVE_NDIR_H
139 #  include <ndir.h>
140 #  define HAVE_DIR_STRUCT
141 # endif
142 #endif
143
144 #include <X11/Intrinsic.h>
145 #include <X11/StringDefs.h>
146 #include <X11/Shell.h>
147 #include <X11/cursorfont.h>
148 #include <X11/Xatom.h>
149 #include <X11/Xmu/Atoms.h>
150 #if USE_XAW3D
151 #include <X11/Xaw3d/Dialog.h>
152 #include <X11/Xaw3d/Form.h>
153 #include <X11/Xaw3d/List.h>
154 #include <X11/Xaw3d/Label.h>
155 #include <X11/Xaw3d/SimpleMenu.h>
156 #include <X11/Xaw3d/SmeBSB.h>
157 #include <X11/Xaw3d/SmeLine.h>
158 #include <X11/Xaw3d/Box.h>
159 #include <X11/Xaw3d/MenuButton.h>
160 #include <X11/Xaw3d/Text.h>
161 #include <X11/Xaw3d/AsciiText.h>
162 #else
163 #include <X11/Xaw/Dialog.h>
164 #include <X11/Xaw/Form.h>
165 #include <X11/Xaw/List.h>
166 #include <X11/Xaw/Label.h>
167 #include <X11/Xaw/SimpleMenu.h>
168 #include <X11/Xaw/SmeBSB.h>
169 #include <X11/Xaw/SmeLine.h>
170 #include <X11/Xaw/Box.h>
171 #include <X11/Xaw/MenuButton.h>
172 #include <X11/Xaw/Text.h>
173 #include <X11/Xaw/AsciiText.h>
174 #endif
175
176 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
177 #include "common.h"
178
179 #if HAVE_LIBXPM
180 #include <X11/xpm.h>
181 #include "pixmaps/pixmaps.h"
182 #define IMAGE_EXT "xpm"
183 #else
184 #define IMAGE_EXT "xim"
185 #include "bitmaps/bitmaps.h"
186 #endif
187
188 #include "bitmaps/icon_white.bm"
189 #include "bitmaps/icon_black.bm"
190 #include "bitmaps/checkmark.bm"
191
192 #include "frontend.h"
193 #include "backend.h"
194 #include "moves.h"
195 #include "xboard.h"
196 #include "childio.h"
197 #include "xgamelist.h"
198 #include "xhistory.h"
199 #include "xedittags.h"
200 #include "gettext.h"
201
202 // must be moved to xengineoutput.h
203
204 void EngineOutputProc P((Widget w, XEvent *event,
205                          String *prms, Cardinal *nprms));
206 void EvalGraphProc P((Widget w, XEvent *event,
207                       String *prms, Cardinal *nprms));
208
209
210 #ifdef __EMX__
211 #ifndef HAVE_USLEEP
212 #define HAVE_USLEEP
213 #endif
214 #define usleep(t)   _sleep2(((t)+500)/1000)
215 #endif
216
217 #ifdef ENABLE_NLS
218 # define  _(s) gettext (s)
219 # define N_(s) gettext_noop (s)
220 #else
221 # define  _(s) (s)
222 # define N_(s)  s
223 #endif
224
225 typedef struct {
226     String string;
227     XtActionProc proc;
228 } MenuItem;
229
230 typedef struct {
231     String name;
232     MenuItem *mi;
233 } Menu;
234
235 int main P((int argc, char **argv));
236 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
237                 char *init_path, char *mode, int (*show_entry)(), char **name_return));
238 RETSIGTYPE CmailSigHandler P((int sig));
239 RETSIGTYPE IntSigHandler P((int sig));
240 RETSIGTYPE TermSizeSigHandler P((int sig));
241 void CreateGCs P((void));
242 void CreateXIMPieces P((void));
243 void CreateXPMPieces P((void));
244 void CreatePieces P((void));
245 void CreatePieceMenus P((void));
246 Widget CreateMenuBar P((Menu *mb));
247 Widget CreateButtonBar P ((MenuItem *mi));
248 char *FindFont P((char *pattern, int targetPxlSize));
249 void PieceMenuPopup P((Widget w, XEvent *event,
250                        String *params, Cardinal *num_params));
251 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
252 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
253 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
254                    u_int wreq, u_int hreq));
255 void CreateGrid P((void));
256 int EventToSquare P((int x, int limit));
257 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
258 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
259 void HandleUserMove P((Widget w, XEvent *event,
260                      String *prms, Cardinal *nprms));
261 void AnimateUserMove P((Widget w, XEvent * event,
262                      String * params, Cardinal * nParams));
263 void HandlePV P((Widget w, XEvent * event,
264                      String * params, Cardinal * nParams));
265 void WhiteClock P((Widget w, XEvent *event,
266                    String *prms, Cardinal *nprms));
267 void BlackClock P((Widget w, XEvent *event,
268                    String *prms, Cardinal *nprms));
269 void DrawPositionProc P((Widget w, XEvent *event,
270                      String *prms, Cardinal *nprms));
271 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
272                      Board board));
273 void CommentPopUp P((char *title, char *label));
274 void CommentPopDown P((void));
275 void CommentCallback P((Widget w, XtPointer client_data,
276                         XtPointer call_data));
277 void ICSInputBoxPopUp P((void));
278 void ICSInputBoxPopDown P((void));
279 void FileNamePopUp P((char *label, char *def,
280                       FileProc proc, char *openMode));
281 void FileNamePopDown P((void));
282 void FileNameCallback P((Widget w, XtPointer client_data,
283                          XtPointer call_data));
284 void FileNameAction P((Widget w, XEvent *event,
285                        String *prms, Cardinal *nprms));
286 void AskQuestionReplyAction P((Widget w, XEvent *event,
287                           String *prms, Cardinal *nprms));
288 void AskQuestionProc P((Widget w, XEvent *event,
289                           String *prms, Cardinal *nprms));
290 void AskQuestionPopDown P((void));
291 void PromotionPopDown P((void));
292 void PromotionCallback P((Widget w, XtPointer client_data,
293                           XtPointer call_data));
294 void EditCommentPopDown P((void));
295 void EditCommentCallback P((Widget w, XtPointer client_data,
296                             XtPointer call_data));
297 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
298 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
299 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
300 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
301                          Cardinal *nprms));
302 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
303                          Cardinal *nprms));
304 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
305                        Cardinal *nprms));
306 void LoadPositionProc P((Widget w, XEvent *event,
307                          String *prms, Cardinal *nprms));
308 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
309                          Cardinal *nprms));
310 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
311                          Cardinal *nprms));
312 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
313                        Cardinal *nprms));
314 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
315                          Cardinal *nprms));
316 void PastePositionProc P((Widget w, XEvent *event, String *prms,
317                           Cardinal *nprms));
318 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
319 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
320 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
321 void SavePositionProc P((Widget w, XEvent *event,
322                          String *prms, Cardinal *nprms));
323 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
324 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
325                             Cardinal *nprms));
326 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
327 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
328 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
329                          Cardinal *nprms));
330 void MachineWhiteProc P((Widget w, XEvent *event,
331                          String *prms, Cardinal *nprms));
332 void AnalyzeModeProc P((Widget w, XEvent *event,
333                          String *prms, Cardinal *nprms));
334 void AnalyzeFileProc P((Widget w, XEvent *event,
335                          String *prms, Cardinal *nprms));
336 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
337                         Cardinal *nprms));
338 void IcsClientProc P((Widget w, XEvent *event, String *prms,
339                       Cardinal *nprms));
340 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
341 void EditPositionProc P((Widget w, XEvent *event,
342                          String *prms, Cardinal *nprms));
343 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
344 void EditCommentProc P((Widget w, XEvent *event,
345                         String *prms, Cardinal *nprms));
346 void IcsInputBoxProc P((Widget w, XEvent *event,
347                         String *prms, Cardinal *nprms));
348 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
349 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
350 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
351 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
352 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
353 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
354 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
355 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
356 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
357 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
358 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
359 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void StopObservingProc P((Widget w, XEvent *event, String *prms,
363                           Cardinal *nprms));
364 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
365                           Cardinal *nprms));
366 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
369 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
370 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
371 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
372 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
373 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
374                          Cardinal *nprms));
375 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
376                         Cardinal *nprms));
377 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
379                         Cardinal *nprms));
380 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
381                          Cardinal *nprms));
382 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
383                          Cardinal *nprms));
384 void AutocommProc P((Widget w, XEvent *event, String *prms,
385                      Cardinal *nprms));
386 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
387 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
388 void AutobsProc P((Widget w, XEvent *event, String *prms,
389                         Cardinal *nprms));
390 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
391 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
392 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
393 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
394                        Cardinal *nprms));
395 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
396 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
397                         Cardinal *nprms));
398 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
399                               Cardinal *nprms));
400 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
401                               Cardinal *nprms));
402 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
403 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
404 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
405                          Cardinal *nprms));
406 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
407                          Cardinal *nprms));
408 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
409                            Cardinal *nprms));
410 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
411                         Cardinal *nprms));
412 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
413                              Cardinal *nprms));
414 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
415 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
416 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
417                        Cardinal *nprms));
418 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
419                          Cardinal *nprms));
420 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
421                          Cardinal *nprms));
422 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
423                           Cardinal *nprms));
424 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
425 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
426 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
427 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
428 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
429 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
430 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
431 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
432 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
433 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
434 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
435 void DisplayMove P((int moveNumber));
436 void DisplayTitle P((char *title));
437 void ICSInitScript P((void));
438 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
439 void ErrorPopUp P((char *title, char *text, int modal));
440 void ErrorPopDown P((void));
441 static char *ExpandPathName P((char *path));
442 static void CreateAnimVars P((void));
443 static void DragPieceMove P((int x, int y));
444 static void DrawDragPiece P((void));
445 char *ModeToWidgetName P((GameMode mode));
446 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
447 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
448 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
449 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
450 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
451 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
452 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
453 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
454 void GameListOptionsPopDown P(());
455 void ShufflePopDown P(());
456 void EnginePopDown P(());
457 void UciPopDown P(());
458 void TimeControlPopDown P(());
459 void NewVariantPopDown P(());
460 void SettingsPopDown P(());
461 void update_ics_width P(());
462 int get_term_width P(());
463 int CopyMemoProc P(());
464 /*
465 * XBoard depends on Xt R4 or higher
466 */
467 int xtVersion = XtSpecificationRelease;
468
469 int xScreen;
470 Display *xDisplay;
471 Window xBoardWindow;
472 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
473   jailSquareColor, highlightSquareColor, premoveHighlightColor;
474 Pixel lowTimeWarningColor;
475 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
476   bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
477   wjPieceGC, bjPieceGC, prelineGC, countGC;
478 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
479 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
480   whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
481   commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
482   menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
483   ICSInputShell, fileNameShell, askQuestionShell;
484 Widget historyShell, evalGraphShell, gameListShell;
485 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
486 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
487 Font clockFontID, coordFontID, countFontID;
488 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
489 XtAppContext appContext;
490 char *layoutName;
491 char *oldICSInteractionTitle;
492
493 FileProc fileProc;
494 char *fileOpenMode;
495 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
496
497 Position commentX = -1, commentY = -1;
498 Dimension commentW, commentH;
499 typedef unsigned int BoardSize;
500 BoardSize boardSize;
501 Boolean chessProgram;
502
503 int  minX, minY; // [HGM] placement: volatile limits on upper-left corner
504 int squareSize, smallLayout = 0, tinyLayout = 0,
505   marginW, marginH, // [HGM] for run-time resizing
506   fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
507   ICSInputBoxUp = False, askQuestionUp = False,
508   filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
509   editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
510 Pixel timerForegroundPixel, timerBackgroundPixel;
511 Pixel buttonForegroundPixel, buttonBackgroundPixel;
512 char *chessDir, *programName, *programVersion,
513   *gameCopyFilename, *gamePasteFilename;
514 Boolean alwaysOnTop = False;
515 Boolean saveSettingsOnExit;
516 char *settingsFileName;
517 char *icsTextMenuString;
518 char *icsNames;
519 char *firstChessProgramNames;
520 char *secondChessProgramNames;
521
522 WindowPlacement wpMain;
523 WindowPlacement wpConsole;
524 WindowPlacement wpComment;
525 WindowPlacement wpMoveHistory;
526 WindowPlacement wpEvalGraph;
527 WindowPlacement wpEngineOutput;
528 WindowPlacement wpGameList;
529 WindowPlacement wpTags;
530
531 #define SOLID 0
532 #define OUTLINE 1
533 Pixmap pieceBitmap[2][(int)BlackPawn];
534 Pixmap pieceBitmap2[2][(int)BlackPawn+4];       /* [HGM] pieces */
535 Pixmap xpmPieceBitmap[4][(int)BlackPawn];       /* LL, LD, DL, DD actually used*/
536 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4];    /* LL, LD, DL, DD set to select from */
537 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
538 int useImages, useImageSqs;
539 XImage *ximPieceBitmap[4][(int)BlackPawn+4];    /* LL, LD, DL, DD */
540 Pixmap ximMaskPm[(int)BlackPawn];               /* clipmasks, used for XIM pieces */
541 Pixmap ximMaskPm2[(int)BlackPawn+4];            /* clipmasks, used for XIM pieces */
542 XImage *ximLightSquare, *ximDarkSquare;
543 XImage *xim_Cross;
544
545 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
546 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
547
548 #define White(piece) ((int)(piece) < (int)BlackPawn)
549
550 /* Variables for doing smooth animation. This whole thing
551    would be much easier if the board was double-buffered,
552    but that would require a fairly major rewrite.       */
553
554 typedef struct {
555         Pixmap  saveBuf;
556         Pixmap  newBuf;
557         GC      blitGC, pieceGC, outlineGC;
558         XPoint  startSquare, prevFrame, mouseDelta;
559         int     startColor;
560         int     dragPiece;
561         Boolean dragActive;
562         int     startBoardX, startBoardY;
563     } AnimState;
564
565 /* There can be two pieces being animated at once: a player
566    can begin dragging a piece before the remote opponent has moved. */
567
568 static AnimState game, player;
569
570 /* Bitmaps for use as masks when drawing XPM pieces.
571    Need one for each black and white piece.             */
572 static Pixmap xpmMask[BlackKing + 1];
573
574 /* This magic number is the number of intermediate frames used
575    in each half of the animation. For short moves it's reduced
576    by 1. The total number of frames will be factor * 2 + 1.  */
577 #define kFactor    4
578
579 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
580
581 MenuItem fileMenu[] = {
582     {N_("New Game"), ResetProc},
583     {N_("New Shuffle Game ..."), ShuffleMenuProc},
584     {N_("New Variant ..."), NewVariantProc},      // [HGM] variant: not functional yet
585     {"----", NothingProc},
586     {N_("Load Game"), LoadGameProc},
587     {N_("Load Next Game"), LoadNextGameProc},
588     {N_("Load Previous Game"), LoadPrevGameProc},
589     {N_("Reload Same Game"), ReloadGameProc},
590     {N_("Save Game"), SaveGameProc},
591     {"----", NothingProc},
592     {N_("Copy Game"), CopyGameProc},
593     {N_("Paste Game"), PasteGameProc},
594     {"----", NothingProc},
595     {N_("Load Position"), LoadPositionProc},
596     {N_("Load Next Position"), LoadNextPositionProc},
597     {N_("Load Previous Position"), LoadPrevPositionProc},
598     {N_("Reload Same Position"), ReloadPositionProc},
599     {N_("Save Position"), SavePositionProc},
600     {"----", NothingProc},
601     {N_("Copy Position"), CopyPositionProc},
602     {N_("Paste Position"), PastePositionProc},
603     {"----", NothingProc},
604     {N_("Mail Move"), MailMoveProc},
605     {N_("Reload CMail Message"), ReloadCmailMsgProc},
606     {"----", NothingProc},
607     {N_("Exit"), QuitProc},
608     {NULL, NULL}
609 };
610
611 MenuItem modeMenu[] = {
612     {N_("Machine White"), MachineWhiteProc},
613     {N_("Machine Black"), MachineBlackProc},
614     {N_("Two Machines"), TwoMachinesProc},
615     {N_("Analysis Mode"), AnalyzeModeProc},
616     {N_("Analyze File"), AnalyzeFileProc },
617     {N_("ICS Client"), IcsClientProc},
618     {N_("Edit Game"), EditGameProc},
619     {N_("Edit Position"), EditPositionProc},
620     {N_("Training"), TrainingProc},
621     {"----", NothingProc},
622     {N_("Show Engine Output"), EngineOutputProc},
623     {N_("Show Evaluation Graph"), EvalGraphProc},
624     {N_("Show Game List"), ShowGameListProc},
625     {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
626     {"----", NothingProc},
627     {N_("Edit Tags"), EditTagsProc},
628     {N_("Edit Comment"), EditCommentProc},
629     {N_("ICS Input Box"), IcsInputBoxProc},
630     {N_("Pause"), PauseProc},
631     {NULL, NULL}
632 };
633
634 MenuItem actionMenu[] = {
635     {N_("Accept"), AcceptProc},
636     {N_("Decline"), DeclineProc},
637     {N_("Rematch"), RematchProc},
638     {"----", NothingProc},
639     {N_("Call Flag"), CallFlagProc},
640     {N_("Draw"), DrawProc},
641     {N_("Adjourn"), AdjournProc},
642     {N_("Abort"), AbortProc},
643     {N_("Resign"), ResignProc},
644     {"----", NothingProc},
645     {N_("Stop Observing"), StopObservingProc},
646     {N_("Stop Examining"), StopExaminingProc},
647     {N_("Upload to Examine"), UploadProc},
648     {"----", NothingProc},
649     {N_("Adjudicate to White"), AdjuWhiteProc},
650     {N_("Adjudicate to Black"), AdjuBlackProc},
651     {N_("Adjudicate Draw"), AdjuDrawProc},
652     {NULL, NULL}
653 };
654
655 MenuItem stepMenu[] = {
656     {N_("Backward"), BackwardProc},
657     {N_("Forward"), ForwardProc},
658     {N_("Back to Start"), ToStartProc},
659     {N_("Forward to End"), ToEndProc},
660     {N_("Revert"), RevertProc},
661     {N_("Annotate"), AnnotateProc},
662     {N_("Truncate Game"), TruncateGameProc},
663     {"----", NothingProc},
664     {N_("Move Now"), MoveNowProc},
665     {N_("Retract Move"), RetractMoveProc},
666     {NULL, NULL}
667 };
668
669 MenuItem optionsMenu[] = {
670     {N_("Flip View"), FlipViewProc},
671     {"----", NothingProc},
672     {N_("Adjudications ..."), EngineMenuProc},
673     {N_("General Settings ..."), UciMenuProc},
674     {N_("Engine #1 Settings ..."), FirstSettingsProc},
675     {N_("Engine #2 Settings ..."), SecondSettingsProc},
676     {N_("Time Control ..."), TimeControlProc},
677     {N_("Game List ..."), GameListOptionsPopUp},
678     {"----", NothingProc},
679     {N_("Always Queen"), AlwaysQueenProc},
680     {N_("Animate Dragging"), AnimateDraggingProc},
681     {N_("Animate Moving"), AnimateMovingProc},
682     {N_("Auto Comment"), AutocommProc},
683     {N_("Auto Flag"), AutoflagProc},
684     {N_("Auto Flip View"), AutoflipProc},
685     {N_("Auto Observe"), AutobsProc},
686     {N_("Auto Raise Board"), AutoraiseProc},
687     {N_("Auto Save"), AutosaveProc},
688     {N_("Blindfold"), BlindfoldProc},
689     {N_("Flash Moves"), FlashMovesProc},
690     {N_("Get Move List"), GetMoveListProc},
691 #if HIGHDRAG
692     {N_("Highlight Dragging"), HighlightDraggingProc},
693 #endif
694     {N_("Highlight Last Move"), HighlightLastMoveProc},
695     {N_("Move Sound"), MoveSoundProc},
696     {N_("ICS Alarm"), IcsAlarmProc},
697     {N_("Old Save Style"), OldSaveStyleProc},
698     {N_("Periodic Updates"), PeriodicUpdatesProc},
699     {N_("Ponder Next Move"), PonderNextMoveProc},
700     {N_("Popup Exit Message"), PopupExitMessageProc},
701     {N_("Popup Move Errors"), PopupMoveErrorsProc},
702     {N_("Premove"), PremoveProc},
703     {N_("Quiet Play"), QuietPlayProc},
704     {N_("Show Coords"), ShowCoordsProc},
705     {N_("Hide Thinking"), HideThinkingProc},
706     {N_("Test Legality"), TestLegalityProc},
707     {"----", NothingProc},
708     {N_("Save Settings Now"), SaveSettingsProc},
709     {N_("Save Settings on Exit"), SaveOnExitProc},
710     {NULL, NULL}
711 };
712
713 MenuItem helpMenu[] = {
714     {N_("Info XBoard"), InfoProc},
715     {N_("Man XBoard"), ManProc},
716     {"----", NothingProc},
717     {N_("Hint"), HintProc},
718     {N_("Book"), BookProc},
719     {"----", NothingProc},
720     {N_("About XBoard"), AboutProc},
721     {NULL, NULL}
722 };
723
724 Menu menuBar[] = {
725     {N_("File"), fileMenu},
726     {N_("Mode"), modeMenu},
727     {N_("Action"), actionMenu},
728     {N_("Step"), stepMenu},
729     {N_("Options"), optionsMenu},
730     {N_("Help"), helpMenu},
731     {NULL, NULL}
732 };
733
734 #define PAUSE_BUTTON N_("P")
735 MenuItem buttonBar[] = {
736     {"<<", ToStartProc},
737     {"<", BackwardProc},
738     {PAUSE_BUTTON, PauseProc},
739     {">", ForwardProc},
740     {">>", ToEndProc},
741     {NULL, NULL}
742 };
743
744 #define PIECE_MENU_SIZE 18
745 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
746     { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
747       N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"), 
748       N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"), 
749       N_("Empty square"), N_("Clear board") },
750     { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
751       N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"), 
752       N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"), 
753       N_("Empty square"), N_("Clear board") }
754 };
755 /* must be in same order as PieceMenuStrings! */
756 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
757     { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
758         WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
759         WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0, 
760         PromotePiece, DemotePiece, EmptySquare, ClearBoard },
761     { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
762         BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
763         BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0, 
764         PromotePiece, DemotePiece, EmptySquare, ClearBoard },
765 };
766
767 #define DROP_MENU_SIZE 6
768 String dropMenuStrings[DROP_MENU_SIZE] = {
769     "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
770   };
771 /* must be in same order as PieceMenuStrings! */
772 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
773     (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
774     WhiteRook, WhiteQueen
775 };
776
777 typedef struct {
778     char piece;
779     char* widget;
780 } DropMenuEnables;
781
782 DropMenuEnables dmEnables[] = {
783     { 'P', "Pawn" },
784     { 'N', "Knight" },
785     { 'B', "Bishop" },
786     { 'R', "Rook" },
787     { 'Q', "Queen" }
788 };
789
790 Arg shellArgs[] = {
791     { XtNwidth, 0 },
792     { XtNheight, 0 },
793     { XtNminWidth, 0 },
794     { XtNminHeight, 0 },
795     { XtNmaxWidth, 0 },
796     { XtNmaxHeight, 0 }
797 };
798
799 Arg layoutArgs[] = {
800     { XtNborderWidth, 0 },
801     { XtNdefaultDistance, 0 },
802 };
803
804 Arg formArgs[] = {
805     { XtNborderWidth, 0 },
806     { XtNresizable, (XtArgVal) True },
807 };
808
809 Arg boardArgs[] = {
810     { XtNborderWidth, 0 },
811     { XtNwidth, 0 },
812     { XtNheight, 0 }
813 };
814
815 Arg titleArgs[] = {
816     { XtNjustify, (XtArgVal) XtJustifyRight },
817     { XtNlabel, (XtArgVal) "..." },
818     { XtNresizable, (XtArgVal) True },
819     { XtNresize, (XtArgVal) False }
820 };
821
822 Arg messageArgs[] = {
823     { XtNjustify, (XtArgVal) XtJustifyLeft },
824     { XtNlabel, (XtArgVal) "..." },
825     { XtNresizable, (XtArgVal) True },
826     { XtNresize, (XtArgVal) False }
827 };
828
829 Arg timerArgs[] = {
830     { XtNborderWidth, 0 },
831     { XtNjustify, (XtArgVal) XtJustifyLeft }
832 };
833
834 XtResource clientResources[] = {
835     { "flashCount", "flashCount", XtRInt, sizeof(int),
836         XtOffset(AppDataPtr, flashCount), XtRImmediate,
837         (XtPointer) FLASH_COUNT  },
838 };
839
840 XrmOptionDescRec shellOptions[] = {
841     { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
842     { "-flash", "flashCount", XrmoptionNoArg, "3" },
843     { "-xflash", "flashCount", XrmoptionNoArg, "0" },
844 };
845
846 XtActionsRec boardActions[] = {
847     { "DrawPosition", DrawPositionProc },
848     { "HandleUserMove", HandleUserMove },
849     { "AnimateUserMove", AnimateUserMove },
850     { "HandlePV", HandlePV },
851     { "UnLoadPV", UnLoadPV },
852     { "FileNameAction", FileNameAction },
853     { "AskQuestionProc", AskQuestionProc },
854     { "AskQuestionReplyAction", AskQuestionReplyAction },
855     { "PieceMenuPopup", PieceMenuPopup },
856     { "WhiteClock", WhiteClock },
857     { "BlackClock", BlackClock },
858     { "Iconify", Iconify },
859     { "ResetProc", ResetProc },
860     { "LoadGameProc", LoadGameProc },
861     { "LoadNextGameProc", LoadNextGameProc },
862     { "LoadPrevGameProc", LoadPrevGameProc },
863     { "LoadSelectedProc", LoadSelectedProc },
864     { "SetFilterProc", SetFilterProc },
865     { "ReloadGameProc", ReloadGameProc },
866     { "LoadPositionProc", LoadPositionProc },
867     { "LoadNextPositionProc", LoadNextPositionProc },
868     { "LoadPrevPositionProc", LoadPrevPositionProc },
869     { "ReloadPositionProc", ReloadPositionProc },
870     { "CopyPositionProc", CopyPositionProc },
871     { "PastePositionProc", PastePositionProc },
872     { "CopyGameProc", CopyGameProc },
873     { "PasteGameProc", PasteGameProc },
874     { "SaveGameProc", SaveGameProc },
875     { "SavePositionProc", SavePositionProc },
876     { "MailMoveProc", MailMoveProc },
877     { "ReloadCmailMsgProc", ReloadCmailMsgProc },
878     { "QuitProc", QuitProc },
879     { "MachineWhiteProc", MachineWhiteProc },
880     { "MachineBlackProc", MachineBlackProc },
881     { "AnalysisModeProc", AnalyzeModeProc },
882     { "AnalyzeFileProc", AnalyzeFileProc },
883     { "TwoMachinesProc", TwoMachinesProc },
884     { "IcsClientProc", IcsClientProc },
885     { "EditGameProc", EditGameProc },
886     { "EditPositionProc", EditPositionProc },
887     { "TrainingProc", EditPositionProc },
888     { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
889     { "EvalGraphProc", EvalGraphProc},       // [HGM] Winboard_x avaluation graph window
890     { "ShowGameListProc", ShowGameListProc },
891     { "ShowMoveListProc", HistoryShowProc},
892     { "EditTagsProc", EditCommentProc },
893     { "EditCommentProc", EditCommentProc },
894     { "IcsAlarmProc", IcsAlarmProc },
895     { "IcsInputBoxProc", IcsInputBoxProc },
896     { "PauseProc", PauseProc },
897     { "AcceptProc", AcceptProc },
898     { "DeclineProc", DeclineProc },
899     { "RematchProc", RematchProc },
900     { "CallFlagProc", CallFlagProc },
901     { "DrawProc", DrawProc },
902     { "AdjournProc", AdjournProc },
903     { "AbortProc", AbortProc },
904     { "ResignProc", ResignProc },
905     { "AdjuWhiteProc", AdjuWhiteProc },
906     { "AdjuBlackProc", AdjuBlackProc },
907     { "AdjuDrawProc", AdjuDrawProc },
908     { "EnterKeyProc", EnterKeyProc },
909     { "UpKeyProc", UpKeyProc },
910     { "DownKeyProc", DownKeyProc },
911     { "StopObservingProc", StopObservingProc },
912     { "StopExaminingProc", StopExaminingProc },
913     { "UploadProc", UploadProc },
914     { "BackwardProc", BackwardProc },
915     { "ForwardProc", ForwardProc },
916     { "ToStartProc", ToStartProc },
917     { "ToEndProc", ToEndProc },
918     { "RevertProc", RevertProc },
919     { "AnnotateProc", AnnotateProc },
920     { "TruncateGameProc", TruncateGameProc },
921     { "MoveNowProc", MoveNowProc },
922     { "RetractMoveProc", RetractMoveProc },
923     { "AlwaysQueenProc", AlwaysQueenProc },
924     { "AnimateDraggingProc", AnimateDraggingProc },
925     { "AnimateMovingProc", AnimateMovingProc },
926     { "AutoflagProc", AutoflagProc },
927     { "AutoflipProc", AutoflipProc },
928     { "AutobsProc", AutobsProc },
929     { "AutoraiseProc", AutoraiseProc },
930     { "AutosaveProc", AutosaveProc },
931     { "BlindfoldProc", BlindfoldProc },
932     { "FlashMovesProc", FlashMovesProc },
933     { "FlipViewProc", FlipViewProc },
934     { "GetMoveListProc", GetMoveListProc },
935 #if HIGHDRAG
936     { "HighlightDraggingProc", HighlightDraggingProc },
937 #endif
938     { "HighlightLastMoveProc", HighlightLastMoveProc },
939     { "IcsAlarmProc", IcsAlarmProc },
940     { "MoveSoundProc", MoveSoundProc },
941     { "OldSaveStyleProc", OldSaveStyleProc },
942     { "PeriodicUpdatesProc", PeriodicUpdatesProc },
943     { "PonderNextMoveProc", PonderNextMoveProc },
944     { "PopupExitMessageProc", PopupExitMessageProc },
945     { "PopupMoveErrorsProc", PopupMoveErrorsProc },
946     { "PremoveProc", PremoveProc },
947     { "QuietPlayProc", QuietPlayProc },
948     { "ShowCoordsProc", ShowCoordsProc },
949     { "ShowThinkingProc", ShowThinkingProc },
950     { "HideThinkingProc", HideThinkingProc },
951     { "TestLegalityProc", TestLegalityProc },
952     { "SaveSettingsProc", SaveSettingsProc },
953     { "SaveOnExitProc", SaveOnExitProc },
954     { "InfoProc", InfoProc },
955     { "ManProc", ManProc },
956     { "HintProc", HintProc },
957     { "BookProc", BookProc },
958     { "AboutGameProc", AboutGameProc },
959     { "AboutProc", AboutProc },
960     { "DebugProc", DebugProc },
961     { "NothingProc", NothingProc },
962     { "CommentPopDown", (XtActionProc) CommentPopDown },
963     { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
964     { "TagsPopDown", (XtActionProc) TagsPopDown },
965     { "ErrorPopDown", (XtActionProc) ErrorPopDown },
966     { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
967     { "FileNamePopDown", (XtActionProc) FileNamePopDown },
968     { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
969     { "GameListPopDown", (XtActionProc) GameListPopDown },
970     { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
971     { "PromotionPopDown", (XtActionProc) PromotionPopDown },
972     { "HistoryPopDown", (XtActionProc) HistoryPopDown },
973     { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
974     { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
975     { "ShufflePopDown", (XtActionProc) ShufflePopDown },
976     { "EnginePopDown", (XtActionProc) EnginePopDown },
977     { "UciPopDown", (XtActionProc) UciPopDown },
978     { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
979     { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
980     { "SettingsPopDown", (XtActionProc) SettingsPopDown },
981     { "CopyMemoProc", (XtActionProc) CopyMemoProc },
982 };
983
984 char globalTranslations[] =
985   ":<Key>R: ResignProc() \n \
986    :<Key>r: ResetProc() \n \
987    :<Key>g: LoadGameProc() \n \
988    :<Key>N: LoadNextGameProc() \n \
989    :<Key>P: LoadPrevGameProc() \n \
990    :<Key>Q: QuitProc() \n \
991    :<Key>F: ToEndProc() \n \
992    :<Key>f: ForwardProc() \n \
993    :<Key>B: ToStartProc() \n \
994    :<Key>b: BackwardProc() \n \
995    :<Key>p: PauseProc() \n \
996    :<Key>d: DrawProc() \n \
997    :<Key>t: CallFlagProc() \n \
998    :<Key>i: Iconify() \n \
999    :<Key>c: Iconify() \n \
1000    :<Key>v: FlipViewProc() \n \
1001    <KeyDown>Control_L: BackwardProc() \n \
1002    <KeyUp>Control_L: ForwardProc() \n \
1003    <KeyDown>Control_R: BackwardProc() \n \
1004    <KeyUp>Control_R: ForwardProc() \n \
1005    Shift<Key>1: AskQuestionProc(\"Direct command\",\
1006                                 \"Send to chess program:\",,1) \n \
1007    Shift<Key>2: AskQuestionProc(\"Direct command\",\
1008                                 \"Send to second chess program:\",,2) \n";
1009
1010 char boardTranslations[] =
1011    "<Btn1Down>: HandleUserMove() \n \
1012    <Btn1Up>: HandleUserMove() \n \
1013    <Btn1Motion>: AnimateUserMove() \n \
1014    <Btn3Motion>: HandlePV() \n \
1015    <Btn3Up>: PieceMenuPopup(menuB) \n \
1016    Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1017                  PieceMenuPopup(menuB) \n \
1018    Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1019                  PieceMenuPopup(menuW) \n \
1020    Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1021                  PieceMenuPopup(menuW) \n \
1022    Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1023                  PieceMenuPopup(menuB) \n";
1024
1025 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1026 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1027
1028 char ICSInputTranslations[] =
1029     "<Key>Up: UpKeyProc() \n "
1030     "<Key>Down: DownKeyProc() \n "
1031     "<Key>Return: EnterKeyProc() \n";
1032
1033 String xboardResources[] = {
1034     "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1035     "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1036     "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1037     NULL
1038   };
1039
1040
1041 /* Max possible square size */
1042 #define MAXSQSIZE 256
1043
1044 static int xpm_avail[MAXSQSIZE];
1045
1046 #ifdef HAVE_DIR_STRUCT
1047
1048 /* Extract piece size from filename */
1049 static int
1050 xpm_getsize(name, len, ext)
1051      char *name;
1052      int len;
1053      char *ext;
1054 {
1055     char *p, *d;
1056     char buf[10];
1057
1058     if (len < 4)
1059       return 0;
1060
1061     if ((p=strchr(name, '.')) == NULL ||
1062         StrCaseCmp(p+1, ext) != 0)
1063       return 0;
1064
1065     p = name + 3;
1066     d = buf;
1067
1068     while (*p && isdigit(*p))
1069       *(d++) = *(p++);
1070
1071     *d = 0;
1072     return atoi(buf);
1073 }
1074
1075 /* Setup xpm_avail */
1076 static int
1077 xpm_getavail(dirname, ext)
1078      char *dirname;
1079      char *ext;
1080 {
1081     DIR *dir;
1082     struct dirent *ent;
1083     int  i;
1084
1085     for (i=0; i<MAXSQSIZE; ++i)
1086       xpm_avail[i] = 0;
1087
1088     if (appData.debugMode)
1089       fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1090
1091     dir = opendir(dirname);
1092     if (!dir)
1093       {
1094           fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1095                   programName, dirname);
1096           exit(1);
1097       }
1098
1099     while ((ent=readdir(dir)) != NULL) {
1100         i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1101         if (i > 0 && i < MAXSQSIZE)
1102           xpm_avail[i] = 1;
1103     }
1104
1105     closedir(dir);
1106
1107     return 0;
1108 }
1109
1110 void
1111 xpm_print_avail(fp, ext)
1112      FILE *fp;
1113      char *ext;
1114 {
1115     int i;
1116
1117     fprintf(fp, _("Available `%s' sizes:\n"), ext);
1118     for (i=1; i<MAXSQSIZE; ++i) {
1119         if (xpm_avail[i])
1120           printf("%d\n", i);
1121     }
1122 }
1123
1124 /* Return XPM piecesize closest to size */
1125 int
1126 xpm_closest_to(dirname, size, ext)
1127      char *dirname;
1128      int size;
1129      char *ext;
1130 {
1131     int i;
1132     int sm_diff = MAXSQSIZE;
1133     int sm_index = 0;
1134     int diff;
1135
1136     xpm_getavail(dirname, ext);
1137
1138     if (appData.debugMode)
1139       xpm_print_avail(stderr, ext);
1140
1141     for (i=1; i<MAXSQSIZE; ++i) {
1142         if (xpm_avail[i]) {
1143             diff = size - i;
1144             diff = (diff<0) ? -diff : diff;
1145             if (diff < sm_diff) {
1146                 sm_diff = diff;
1147                 sm_index = i;
1148             }
1149         }
1150     }
1151
1152     if (!sm_index) {
1153         fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1154         exit(1);
1155     }
1156
1157     return sm_index;
1158 }
1159 #else   /* !HAVE_DIR_STRUCT */
1160 /* If we are on a system without a DIR struct, we can't
1161    read the directory, so we can't collect a list of
1162    filenames, etc., so we can't do any size-fitting. */
1163 int
1164 xpm_closest_to(dirname, size, ext)
1165      char *dirname;
1166      int size;
1167      char *ext;
1168 {
1169     fprintf(stderr, _("\
1170 Warning: No DIR structure found on this system --\n\
1171          Unable to autosize for XPM/XIM pieces.\n\
1172    Please report this error to frankm@hiwaay.net.\n\
1173    Include system type & operating system in message.\n"));
1174     return size;
1175 }
1176 #endif /* HAVE_DIR_STRUCT */
1177
1178 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1179                              "magenta", "cyan", "white" };
1180 typedef struct {
1181     int attr, bg, fg;
1182 } TextColors;
1183 TextColors textColors[(int)NColorClasses];
1184
1185 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1186 static int
1187 parse_color(str, which)
1188      char *str;
1189      int which;
1190 {
1191     char *p, buf[100], *d;
1192     int i;
1193
1194     if (strlen(str) > 99)       /* watch bounds on buf */
1195       return -1;
1196
1197     p = str;
1198     d = buf;
1199     for (i=0; i<which; ++i) {
1200         p = strchr(p, ',');
1201         if (!p)
1202           return -1;
1203         ++p;
1204     }
1205
1206     /* Could be looking at something like:
1207        black, , 1
1208        .. in which case we want to stop on a comma also */
1209     while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1210       ++p;
1211
1212     if (*p == ',') {
1213         return -1;              /* Use default for empty field */
1214     }
1215
1216     if (which == 2 || isdigit(*p))
1217       return atoi(p);
1218
1219     while (*p && isalpha(*p))
1220       *(d++) = *(p++);
1221
1222     *d = 0;
1223
1224     for (i=0; i<8; ++i) {
1225         if (!StrCaseCmp(buf, cnames[i]))
1226           return which? (i+40) : (i+30);
1227     }
1228     if (!StrCaseCmp(buf, "default")) return -1;
1229
1230     fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1231     return -2;
1232 }
1233
1234 static int
1235 parse_cpair(cc, str)
1236      ColorClass cc;
1237      char *str;
1238 {
1239     if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1240         fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1241                 programName, str);
1242         return -1;
1243     }
1244
1245     /* bg and attr are optional */
1246     textColors[(int)cc].bg = parse_color(str, 1);
1247     if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1248         textColors[(int)cc].attr = 0;
1249     }
1250     return 0;
1251 }
1252
1253
1254 /* Arrange to catch delete-window events */
1255 Atom wm_delete_window;
1256 void
1257 CatchDeleteWindow(Widget w, String procname)
1258 {
1259   char buf[MSG_SIZ];
1260   XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1261   snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1262   XtAugmentTranslations(w, XtParseTranslationTable(buf));
1263 }
1264
1265 void
1266 BoardToTop()
1267 {
1268   Arg args[16];
1269   XtSetArg(args[0], XtNiconic, False);
1270   XtSetValues(shellWidget, args, 1);
1271
1272   XtPopup(shellWidget, XtGrabNone); /* Raise if lowered  */
1273 }
1274
1275 //---------------------------------------------------------------------------------------------------------
1276 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1277 #define XBOARD True
1278 #define JAWS_ARGS
1279 #define CW_USEDEFAULT (1<<31)
1280 #define ICS_TEXT_MENU_SIZE 90
1281 #define DEBUG_FILE "xboard.debug"
1282 #define SetCurrentDirectory chdir
1283 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1284 #define OPTCHAR "-"
1285 #define SEPCHAR " "
1286
1287 // these two must some day move to frontend.h, when they are implemented
1288 Boolean GameListIsUp();
1289
1290 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1291 #include "args.h"
1292
1293 // front-end part of option handling
1294
1295 // [HGM] This platform-dependent table provides the location for storing the color info
1296 extern char *crWhite, * crBlack;
1297
1298 void *
1299 colorVariable[] = {
1300   &appData.whitePieceColor, 
1301   &appData.blackPieceColor, 
1302   &appData.lightSquareColor,
1303   &appData.darkSquareColor, 
1304   &appData.highlightSquareColor,
1305   &appData.premoveHighlightColor,
1306   &appData.lowTimeWarningColor,
1307   NULL,
1308   NULL,
1309   NULL,
1310   NULL,
1311   NULL,
1312   &crWhite,
1313   &crBlack,
1314   NULL
1315 };
1316
1317 // [HGM] font: keep a font for each square size, even non-stndard ones
1318 #define NUM_SIZES 18
1319 #define MAX_SIZE 130
1320 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1321 char *fontTable[NUM_FONTS][MAX_SIZE];
1322
1323 void
1324 ParseFont(char *name, int number)
1325 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1326   int size;
1327   if(sscanf(name, "size%d:", &size)) {
1328     // [HGM] font: font is meant for specific boardSize (likely from settings file);
1329     //       defer processing it until we know if it matches our board size
1330     if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1331         fontTable[number][size] = strdup(strchr(name, ':')+1);
1332         fontValid[number][size] = True;
1333     }
1334     return;
1335   }
1336   switch(number) {
1337     case 0: // CLOCK_FONT
1338         appData.clockFont = strdup(name);
1339       break;
1340     case 1: // MESSAGE_FONT
1341         appData.font = strdup(name);
1342       break;
1343     case 2: // COORD_FONT
1344         appData.coordFont = strdup(name);
1345       break;
1346     default:
1347       return;
1348   }
1349   fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1350 }
1351
1352 void
1353 SetFontDefaults()
1354 { // only 2 fonts currently
1355   appData.clockFont = CLOCK_FONT_NAME;
1356   appData.coordFont = COORD_FONT_NAME;
1357   appData.font  =   DEFAULT_FONT_NAME;
1358 }
1359
1360 void
1361 CreateFonts()
1362 { // no-op, until we identify the code for this already in XBoard and move it here
1363 }
1364
1365 void
1366 ParseColor(int n, char *name)
1367 { // in XBoard, just copy the color-name string
1368   if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1369 }
1370
1371 void
1372 ParseTextAttribs(ColorClass cc, char *s)
1373 {   
1374     (&appData.colorShout)[cc] = strdup(s);
1375 }
1376
1377 void
1378 ParseBoardSize(void *addr, char *name)
1379 {
1380     appData.boardSize = strdup(name);
1381 }
1382
1383 void
1384 LoadAllSounds()
1385 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1386 }
1387
1388 void
1389 SetCommPortDefaults()
1390 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1391 }
1392
1393 // [HGM] args: these three cases taken out to stay in front-end
1394 void
1395 SaveFontArg(FILE *f, ArgDescriptor *ad)
1396 {
1397   char *name, buf[MSG_SIZ];
1398   int i, n = (int)ad->argLoc;
1399   switch(n) {
1400     case 0: // CLOCK_FONT
1401         name = appData.clockFont;
1402       break;
1403     case 1: // MESSAGE_FONT
1404         name = appData.font;
1405       break;
1406     case 2: // COORD_FONT
1407         name = appData.coordFont;
1408       break;
1409     default:
1410       return;
1411   }
1412   for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1413     if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1414         fontTable[n][squareSize] = strdup(name);
1415         fontValid[n][squareSize] = True;
1416         break;
1417   }
1418   for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1419     fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]); 
1420 }
1421
1422 void
1423 ExportSounds()
1424 { // nothing to do, as the sounds are at all times represented by their text-string names already
1425 }
1426
1427 void
1428 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1429 {       // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1430         fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1431 }
1432
1433 void
1434 SaveColor(FILE *f, ArgDescriptor *ad)
1435 {       // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1436         if(colorVariable[(int)ad->argLoc])
1437         fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1438 }
1439
1440 void
1441 SaveBoardSize(FILE *f, char *name, void *addr)
1442 { // wrapper to shield back-end from BoardSize & sizeInfo
1443   fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1444 }
1445
1446 void
1447 ParseCommPortSettings(char *s)
1448 { // no such option in XBoard (yet)
1449 }
1450
1451 extern Widget engineOutputShell;
1452 extern Widget tagsShell, editTagsShell;
1453 void
1454 GetActualPlacement(Widget wg, WindowPlacement *wp)
1455 {
1456   Arg args[16];
1457   Dimension w, h;
1458   Position x, y;
1459   int i;
1460
1461   if(!wg) return;
1462   
1463     i = 0;
1464     XtSetArg(args[i], XtNx, &x); i++;
1465     XtSetArg(args[i], XtNy, &y); i++;
1466     XtSetArg(args[i], XtNwidth, &w); i++;
1467     XtSetArg(args[i], XtNheight, &h); i++;
1468     XtGetValues(wg, args, i);
1469     wp->x = x - 4;
1470     wp->y = y - 23;
1471     wp->height = h;
1472     wp->width = w;
1473 }
1474
1475 void
1476 GetWindowCoords()
1477 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1478   // In XBoard this will have to wait until awareness of window parameters is implemented
1479   GetActualPlacement(shellWidget, &wpMain);
1480   if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1481   if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1482   if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1483   if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1484   if(commentShell) GetActualPlacement(commentShell, &wpComment);
1485   else             GetActualPlacement(editShell,    &wpComment);
1486   if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1487   else      GetActualPlacement(editTagsShell, &wpTags);
1488 }
1489
1490 void
1491 PrintCommPortSettings(FILE *f, char *name)
1492 { // This option does not exist in XBoard
1493 }
1494
1495 int
1496 MySearchPath(char *installDir, char *name, char *fullname)
1497 { // just append installDir and name. Perhaps ExpandPath should be used here?
1498   name = ExpandPathName(name);
1499   if(name && name[0] == '/') strcpy(fullname, name); else {
1500     sprintf(fullname, "%s%c%s", installDir, '/', name);
1501   }
1502   return 1;
1503 }
1504
1505 int
1506 MyGetFullPathName(char *name, char *fullname)
1507 { // should use ExpandPath?
1508   name = ExpandPathName(name);
1509   strcpy(fullname, name);
1510   return 1;
1511 }
1512
1513 void
1514 EnsureOnScreen(int *x, int *y, int minX, int minY)
1515 {
1516   return;
1517 }
1518
1519 int
1520 MainWindowUp()
1521 { // [HGM] args: allows testing if main window is realized from back-end
1522   return xBoardWindow != 0;
1523 }
1524
1525 void
1526 PopUpStartupDialog()
1527 {  // start menu not implemented in XBoard
1528 }
1529 char *
1530 ConvertToLine(int argc, char **argv)
1531 {
1532   static char line[128*1024], buf[1024];
1533   int i;
1534
1535   line[0] = NULLCHAR;
1536   for(i=1; i<argc; i++) {
1537     if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1538         && argv[i][0] != '{' )
1539          sprintf(buf, "{%s} ", argv[i]);
1540     else sprintf(buf, "%s ", argv[i]);
1541     strcat(line, buf);
1542   }
1543     line[strlen(line)-1] = NULLCHAR;
1544   return line;
1545 }
1546
1547 //--------------------------------------------------------------------------------------------
1548
1549 #ifdef IDSIZES
1550   // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1551 #else
1552 #define BoardSize int
1553 void InitDrawingSizes(BoardSize boardSize, int flags)
1554 {   // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1555     Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1556     Arg args[16];
1557     XtGeometryResult gres;
1558     int i;
1559
1560     if(!formWidget) return;
1561
1562     /*
1563      * Enable shell resizing.
1564      */
1565     shellArgs[0].value = (XtArgVal) &w;
1566     shellArgs[1].value = (XtArgVal) &h;
1567     XtGetValues(shellWidget, shellArgs, 2);
1568
1569     shellArgs[4].value = 2*w; shellArgs[2].value = 10;
1570     shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1571     XtSetValues(shellWidget, &shellArgs[2], 4);
1572
1573     XtSetArg(args[0], XtNdefaultDistance, &sep);
1574     XtGetValues(formWidget, args, 1);
1575
1576     boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1577     boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1578     CreateGrid();
1579
1580     XtSetArg(args[0], XtNwidth, boardWidth);
1581     XtSetArg(args[1], XtNheight, boardHeight);
1582     XtSetValues(boardWidget, args, 2);
1583
1584     timerWidth = (boardWidth - sep) / 2;
1585     XtSetArg(args[0], XtNwidth, timerWidth);
1586     XtSetValues(whiteTimerWidget, args, 1);
1587     XtSetValues(blackTimerWidget, args, 1);
1588
1589     XawFormDoLayout(formWidget, False);
1590
1591     if (appData.titleInWindow) {
1592         i = 0;
1593         XtSetArg(args[i], XtNborderWidth, &bor); i++;
1594         XtSetArg(args[i], XtNheight, &h);  i++;
1595         XtGetValues(titleWidget, args, i);
1596         if (smallLayout) {
1597             w = boardWidth - 2*bor;
1598         } else {
1599             XtSetArg(args[0], XtNwidth, &w);
1600             XtGetValues(menuBarWidget, args, 1);
1601             w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1602         }
1603
1604         gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1605         if (gres != XtGeometryYes && appData.debugMode) {
1606             fprintf(stderr,
1607                     _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1608                     programName, gres, w, h, wr, hr);
1609         }
1610     }
1611
1612     XawFormDoLayout(formWidget, True);
1613
1614     /*
1615      * Inhibit shell resizing.
1616      */
1617     shellArgs[0].value = w = (XtArgVal) boardWidth + marginW;
1618     shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1619     shellArgs[4].value = shellArgs[2].value = w;
1620     shellArgs[5].value = shellArgs[3].value = h;
1621     XtSetValues(shellWidget, &shellArgs[0], 6);
1622
1623     // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1624     // (only for xpm)
1625     if(useImages) {
1626       for(i=0; i<4; i++) {
1627         int p;
1628         for(p=0; p<=(int)WhiteKing; p++)
1629            xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1630         if(gameInfo.variant == VariantShogi) {
1631            xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1632            xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1633            xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1634            xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1635            xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1636         }
1637 #ifdef GOTHIC
1638         if(gameInfo.variant == VariantGothic) {
1639            xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1640         }
1641 #endif
1642 #if !HAVE_LIBXPM
1643         // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1644         for(p=0; p<=(int)WhiteKing; p++)
1645            ximMaskPm[p] = ximMaskPm2[p]; // defaults
1646         if(gameInfo.variant == VariantShogi) {
1647            ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1648            ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1649            ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1650            ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1651            ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1652         }
1653 #ifdef GOTHIC
1654         if(gameInfo.variant == VariantGothic) {
1655            ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1656         }
1657 #endif
1658 #endif
1659       }
1660     } else {
1661       for(i=0; i<2; i++) {
1662         int p;
1663         for(p=0; p<=(int)WhiteKing; p++)
1664            pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1665         if(gameInfo.variant == VariantShogi) {
1666            pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1667            pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1668            pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1669            pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1670            pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1671         }
1672 #ifdef GOTHIC
1673         if(gameInfo.variant == VariantGothic) {
1674            pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1675         }
1676 #endif
1677       }
1678     }
1679 #if HAVE_LIBXPM
1680     CreateAnimVars();
1681 #endif
1682 }
1683 #endif
1684
1685 void EscapeExpand(char *p, char *q)
1686 {       // [HGM] initstring: routine to shape up string arguments
1687         while(*p++ = *q++) if(p[-1] == '\\')
1688             switch(*q++) {
1689                 case 'n': p[-1] = '\n'; break;
1690                 case 'r': p[-1] = '\r'; break;
1691                 case 't': p[-1] = '\t'; break;
1692                 case '\\': p[-1] = '\\'; break;
1693                 case 0: *p = 0; return;
1694                 default: p[-1] = q[-1]; break;
1695             }
1696 }
1697
1698 int
1699 main(argc, argv)
1700      int argc;
1701      char **argv;
1702 {
1703     int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1704     XSetWindowAttributes window_attributes;
1705     Arg args[16];
1706     Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1707     XrmValue vFrom, vTo;
1708     XtGeometryResult gres;
1709     char *p;
1710     XrmDatabase xdb;
1711     int forceMono = False;
1712
1713     srandom(time(0)); // [HGM] book: make random truly random
1714
1715     setbuf(stdout, NULL);
1716     setbuf(stderr, NULL);
1717     debugFP = stderr;
1718
1719     if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1720         printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1721         exit(0);
1722     }
1723
1724     programName = strrchr(argv[0], '/');
1725     if (programName == NULL)
1726       programName = argv[0];
1727     else
1728       programName++;
1729
1730 #ifdef ENABLE_NLS
1731     XtSetLanguageProc(NULL, NULL, NULL);
1732     bindtextdomain(PACKAGE, LOCALEDIR);
1733     textdomain(PACKAGE);
1734 #endif
1735
1736     shellWidget =
1737       XtAppInitialize(&appContext, "XBoard", shellOptions,
1738                       XtNumber(shellOptions),
1739                       &argc, argv, xboardResources, NULL, 0);
1740     appData.boardSize = "";
1741     InitAppData(ConvertToLine(argc, argv));
1742     p = getenv("HOME");
1743     if (p == NULL) p = "/tmp";
1744     i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1745     gameCopyFilename = (char*) malloc(i);
1746     gamePasteFilename = (char*) malloc(i);
1747     snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1748     snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1749
1750     XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1751                               clientResources, XtNumber(clientResources),
1752                               NULL, 0);
1753
1754     { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1755         static char buf[MSG_SIZ];
1756         EscapeExpand(buf, appData.initString);
1757         appData.initString = strdup(buf);
1758         EscapeExpand(buf, appData.secondInitString);
1759         appData.secondInitString = strdup(buf);
1760         EscapeExpand(buf, appData.firstComputerString);
1761         appData.firstComputerString = strdup(buf);
1762         EscapeExpand(buf, appData.secondComputerString);
1763         appData.secondComputerString = strdup(buf);
1764     }
1765
1766     if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1767         chessDir = ".";
1768     } else {
1769         if (chdir(chessDir) != 0) {
1770             fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1771             perror(chessDir);
1772             exit(1);
1773         }
1774     }
1775
1776     if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1777         /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1778         if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL)  {
1779            printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1780            exit(errno);
1781         }
1782         setbuf(debugFP, NULL);
1783     }
1784
1785     /* [HGM,HR] make sure board size is acceptable */
1786     if(appData.NrFiles > BOARD_FILES ||
1787        appData.NrRanks > BOARD_RANKS   )
1788          DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1789
1790 #if !HIGHDRAG
1791     /* This feature does not work; animation needs a rewrite */
1792     appData.highlightDragging = FALSE;
1793 #endif
1794     InitBackEnd1();
1795
1796     xDisplay = XtDisplay(shellWidget);
1797     xScreen = DefaultScreen(xDisplay);
1798     wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1799
1800         gameInfo.variant = StringToVariant(appData.variant);
1801         InitPosition(FALSE);
1802
1803 #ifdef IDSIZE
1804     InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1805 #else
1806     if (isdigit(appData.boardSize[0])) {
1807         i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1808                    &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1809                    &fontPxlSize, &smallLayout, &tinyLayout);
1810         if (i == 0) {
1811             fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1812                     programName, appData.boardSize);
1813             exit(2);
1814         }
1815         if (i < 7) {
1816             /* Find some defaults; use the nearest known size */
1817             SizeDefaults *szd, *nearest;
1818             int distance = 99999;
1819             nearest = szd = sizeDefaults;
1820             while (szd->name != NULL) {
1821                 if (abs(szd->squareSize - squareSize) < distance) {
1822                     nearest = szd;
1823                     distance = abs(szd->squareSize - squareSize);
1824                     if (distance == 0) break;
1825                 }
1826                 szd++;
1827             }
1828             if (i < 2) lineGap = nearest->lineGap;
1829             if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1830             if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1831             if (i < 5) fontPxlSize = nearest->fontPxlSize;
1832             if (i < 6) smallLayout = nearest->smallLayout;
1833             if (i < 7) tinyLayout = nearest->tinyLayout;
1834         }
1835     } else {
1836         SizeDefaults *szd = sizeDefaults;
1837         if (*appData.boardSize == NULLCHAR) {
1838             while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1839                    DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1840               szd++;
1841             }
1842             if (szd->name == NULL) szd--;
1843             appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1844         } else {
1845             while (szd->name != NULL &&
1846                    StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1847             if (szd->name == NULL) {
1848                 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1849                         programName, appData.boardSize);
1850                 exit(2);
1851             }
1852         }
1853         squareSize = szd->squareSize;
1854         lineGap = szd->lineGap;
1855         clockFontPxlSize = szd->clockFontPxlSize;
1856         coordFontPxlSize = szd->coordFontPxlSize;
1857         fontPxlSize = szd->fontPxlSize;
1858         smallLayout = szd->smallLayout;
1859         tinyLayout = szd->tinyLayout;
1860         // [HGM] font: use defaults from settings file if available and not overruled
1861     }
1862     if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
1863         appData.clockFont = fontTable[CLOCK_FONT][squareSize];
1864     if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
1865         appData.font = fontTable[MESSAGE_FONT][squareSize];
1866     if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
1867         appData.coordFont = fontTable[COORD_FONT][squareSize];
1868
1869     /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1870     if (strlen(appData.pixmapDirectory) > 0) {
1871         p = ExpandPathName(appData.pixmapDirectory);
1872         if (!p) {
1873             fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1874                    appData.pixmapDirectory);
1875             exit(1);
1876         }
1877         if (appData.debugMode) {
1878           fprintf(stderr, _("\
1879 XBoard square size (hint): %d\n\
1880 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1881         }
1882         squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1883         if (appData.debugMode) {
1884             fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1885         }
1886     }
1887
1888     /* [HR] height treated separately (hacked) */
1889     boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1890     boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1891     if (appData.showJail == 1) {
1892         /* Jail on top and bottom */
1893         XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1894         XtSetArg(boardArgs[2], XtNheight,
1895                  boardHeight + 2*(lineGap + squareSize));
1896     } else if (appData.showJail == 2) {
1897         /* Jail on sides */
1898         XtSetArg(boardArgs[1], XtNwidth,
1899                  boardWidth + 2*(lineGap + squareSize));
1900         XtSetArg(boardArgs[2], XtNheight, boardHeight);
1901     } else {
1902         /* No jail */
1903         XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1904         XtSetArg(boardArgs[2], XtNheight, boardHeight);
1905     }
1906
1907     /*
1908      * Determine what fonts to use.
1909      */
1910     appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1911     clockFontID = XLoadFont(xDisplay, appData.clockFont);
1912     clockFontStruct = XQueryFont(xDisplay, clockFontID);
1913     appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1914     coordFontID = XLoadFont(xDisplay, appData.coordFont);
1915     coordFontStruct = XQueryFont(xDisplay, coordFontID);
1916     appData.font = FindFont(appData.font, fontPxlSize);
1917     countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1918     countFontStruct = XQueryFont(xDisplay, countFontID);
1919 //    appData.font = FindFont(appData.font, fontPxlSize);
1920
1921     xdb = XtDatabase(xDisplay);
1922     XrmPutStringResource(&xdb, "*font", appData.font);
1923
1924     /*
1925      * Detect if there are not enough colors available and adapt.
1926      */
1927     if (DefaultDepth(xDisplay, xScreen) <= 2) {
1928       appData.monoMode = True;
1929     }
1930
1931     if (!appData.monoMode) {
1932         vFrom.addr = (caddr_t) appData.lightSquareColor;
1933         vFrom.size = strlen(appData.lightSquareColor);
1934         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1935         if (vTo.addr == NULL) {
1936           appData.monoMode = True;
1937           forceMono = True;
1938         } else {
1939           lightSquareColor = *(Pixel *) vTo.addr;
1940         }
1941     }
1942     if (!appData.monoMode) {
1943         vFrom.addr = (caddr_t) appData.darkSquareColor;
1944         vFrom.size = strlen(appData.darkSquareColor);
1945         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1946         if (vTo.addr == NULL) {
1947           appData.monoMode = True;
1948           forceMono = True;
1949         } else {
1950           darkSquareColor = *(Pixel *) vTo.addr;
1951         }
1952     }
1953     if (!appData.monoMode) {
1954         vFrom.addr = (caddr_t) appData.whitePieceColor;
1955         vFrom.size = strlen(appData.whitePieceColor);
1956         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1957         if (vTo.addr == NULL) {
1958           appData.monoMode = True;
1959           forceMono = True;
1960         } else {
1961           whitePieceColor = *(Pixel *) vTo.addr;
1962         }
1963     }
1964     if (!appData.monoMode) {
1965         vFrom.addr = (caddr_t) appData.blackPieceColor;
1966         vFrom.size = strlen(appData.blackPieceColor);
1967         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1968         if (vTo.addr == NULL) {
1969           appData.monoMode = True;
1970           forceMono = True;
1971         } else {
1972           blackPieceColor = *(Pixel *) vTo.addr;
1973         }
1974     }
1975
1976     if (!appData.monoMode) {
1977         vFrom.addr = (caddr_t) appData.highlightSquareColor;
1978         vFrom.size = strlen(appData.highlightSquareColor);
1979         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1980         if (vTo.addr == NULL) {
1981           appData.monoMode = True;
1982           forceMono = True;
1983         } else {
1984           highlightSquareColor = *(Pixel *) vTo.addr;
1985         }
1986     }
1987
1988     if (!appData.monoMode) {
1989         vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1990         vFrom.size = strlen(appData.premoveHighlightColor);
1991         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1992         if (vTo.addr == NULL) {
1993           appData.monoMode = True;
1994           forceMono = True;
1995         } else {
1996           premoveHighlightColor = *(Pixel *) vTo.addr;
1997         }
1998     }
1999
2000     if (forceMono) {
2001       fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2002               programName);
2003       
2004       if (appData.bitmapDirectory == NULL ||
2005               appData.bitmapDirectory[0] == NULLCHAR)
2006             appData.bitmapDirectory = DEF_BITMAP_DIR;
2007     }
2008
2009     if (appData.lowTimeWarning && !appData.monoMode) {
2010       vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2011       vFrom.size = strlen(appData.lowTimeWarningColor);
2012       XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2013       if (vTo.addr == NULL) 
2014                 appData.monoMode = True;
2015       else
2016                 lowTimeWarningColor = *(Pixel *) vTo.addr;
2017     }
2018
2019     if (appData.monoMode && appData.debugMode) {
2020         fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2021                 (unsigned long) XWhitePixel(xDisplay, xScreen),
2022                 (unsigned long) XBlackPixel(xDisplay, xScreen));
2023     }
2024
2025     if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2026         parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2027         parse_cpair(ColorChannel1, appData.colorChannel1) < 0  ||
2028         parse_cpair(ColorChannel, appData.colorChannel) < 0  ||
2029         parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2030         parse_cpair(ColorTell, appData.colorTell) < 0 ||
2031         parse_cpair(ColorChallenge, appData.colorChallenge) < 0  ||
2032         parse_cpair(ColorRequest, appData.colorRequest) < 0  ||
2033         parse_cpair(ColorSeek, appData.colorSeek) < 0  ||
2034         parse_cpair(ColorNormal, appData.colorNormal) < 0)
2035       {
2036           if (appData.colorize) {
2037               fprintf(stderr,
2038                       _("%s: can't parse color names; disabling colorization\n"),
2039                       programName);
2040           }
2041           appData.colorize = FALSE;
2042       }
2043     textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2044     textColors[ColorNone].attr = 0;
2045
2046     XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2047
2048     /*
2049      * widget hierarchy
2050      */
2051     if (tinyLayout) {
2052         layoutName = "tinyLayout";
2053     } else if (smallLayout) {
2054         layoutName = "smallLayout";
2055     } else {
2056         layoutName = "normalLayout";
2057     }
2058     /* Outer layoutWidget is there only to provide a name for use in
2059        resources that depend on the layout style */
2060     layoutWidget =
2061       XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2062                             layoutArgs, XtNumber(layoutArgs));
2063     formWidget =
2064       XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2065                             formArgs, XtNumber(formArgs));
2066     XtSetArg(args[0], XtNdefaultDistance, &sep);
2067     XtGetValues(formWidget, args, 1);
2068
2069     j = 0;
2070     widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2071     XtSetArg(args[0], XtNtop,    XtChainTop);
2072     XtSetArg(args[1], XtNbottom, XtChainTop);
2073     XtSetArg(args[2], XtNright,  XtChainLeft);
2074     XtSetValues(menuBarWidget, args, 3);
2075
2076     widgetList[j++] = whiteTimerWidget =
2077       XtCreateWidget("whiteTime", labelWidgetClass,
2078                      formWidget, timerArgs, XtNumber(timerArgs));
2079     XtSetArg(args[0], XtNfont, clockFontStruct);
2080     XtSetArg(args[1], XtNtop,    XtChainTop);
2081     XtSetArg(args[2], XtNbottom, XtChainTop);
2082     XtSetValues(whiteTimerWidget, args, 3);
2083
2084     widgetList[j++] = blackTimerWidget =
2085       XtCreateWidget("blackTime", labelWidgetClass,
2086                      formWidget, timerArgs, XtNumber(timerArgs));
2087     XtSetArg(args[0], XtNfont, clockFontStruct);
2088     XtSetArg(args[1], XtNtop,    XtChainTop);
2089     XtSetArg(args[2], XtNbottom, XtChainTop);
2090     XtSetValues(blackTimerWidget, args, 3);
2091
2092     if (appData.titleInWindow) {
2093         widgetList[j++] = titleWidget =
2094           XtCreateWidget("title", labelWidgetClass, formWidget,
2095                          titleArgs, XtNumber(titleArgs));
2096         XtSetArg(args[0], XtNtop,    XtChainTop);
2097         XtSetArg(args[1], XtNbottom, XtChainTop);
2098         XtSetValues(titleWidget, args, 2);
2099     }
2100
2101     if (appData.showButtonBar) {
2102       widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2103       XtSetArg(args[0], XtNleft,  XtChainRight); // [HGM] glue to right window edge
2104       XtSetArg(args[1], XtNright, XtChainRight); //       for good run-time sizing
2105       XtSetArg(args[2], XtNtop,    XtChainTop);
2106       XtSetArg(args[3], XtNbottom, XtChainTop);
2107       XtSetValues(buttonBarWidget, args, 4);
2108     }
2109
2110     widgetList[j++] = messageWidget =
2111       XtCreateWidget("message", labelWidgetClass, formWidget,
2112                      messageArgs, XtNumber(messageArgs));
2113     XtSetArg(args[0], XtNtop,    XtChainTop);
2114     XtSetArg(args[1], XtNbottom, XtChainTop);
2115     XtSetValues(messageWidget, args, 2);
2116
2117     widgetList[j++] = boardWidget =
2118       XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2119                      XtNumber(boardArgs));
2120
2121     XtManageChildren(widgetList, j);
2122
2123     timerWidth = (boardWidth - sep) / 2;
2124     XtSetArg(args[0], XtNwidth, timerWidth);
2125     XtSetValues(whiteTimerWidget, args, 1);
2126     XtSetValues(blackTimerWidget, args, 1);
2127
2128     XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2129     XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2130     XtGetValues(whiteTimerWidget, args, 2);
2131
2132     if (appData.showButtonBar) {
2133       XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2134       XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2135       XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2136     }
2137
2138     /*
2139      * formWidget uses these constraints but they are stored
2140      * in the children.
2141      */
2142     i = 0;
2143     XtSetArg(args[i], XtNfromHoriz, 0); i++;
2144     XtSetValues(menuBarWidget, args, i);
2145     if (appData.titleInWindow) {
2146         if (smallLayout) {
2147             i = 0;
2148             XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2149             XtSetValues(whiteTimerWidget, args, i);
2150             i = 0;
2151             XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2152             XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2153             XtSetValues(blackTimerWidget, args, i);
2154             i = 0;
2155             XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2156             XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2157             XtSetValues(titleWidget, args, i);
2158             i = 0;
2159             XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2160             XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2161             XtSetValues(messageWidget, args, i);
2162             if (appData.showButtonBar) {
2163               i = 0;
2164               XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2165               XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2166               XtSetValues(buttonBarWidget, args, i);
2167             }
2168         } else {
2169             i = 0;
2170             XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2171             XtSetValues(whiteTimerWidget, args, i);
2172             i = 0;
2173             XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2174             XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2175             XtSetValues(blackTimerWidget, args, i);
2176             i = 0;
2177             XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2178             XtSetValues(titleWidget, args, i);
2179             i = 0;
2180             XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2181             XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2182             XtSetValues(messageWidget, args, i);
2183             if (appData.showButtonBar) {
2184               i = 0;
2185               XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2186               XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2187               XtSetValues(buttonBarWidget, args, i);
2188             }
2189         }
2190     } else {
2191         i = 0;
2192         XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2193         XtSetValues(whiteTimerWidget, args, i);
2194         i = 0;
2195         XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2196         XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2197         XtSetValues(blackTimerWidget, args, i);
2198         i = 0;
2199         XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2200         XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2201         XtSetValues(messageWidget, args, i);
2202         if (appData.showButtonBar) {
2203           i = 0;
2204           XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2205           XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2206           XtSetValues(buttonBarWidget, args, i);
2207         }
2208     }
2209     i = 0;
2210     XtSetArg(args[0], XtNfromVert, messageWidget);
2211     XtSetArg(args[1], XtNtop,    XtChainTop);
2212     XtSetArg(args[2], XtNbottom, XtChainBottom);
2213     XtSetArg(args[3], XtNleft,   XtChainLeft);
2214     XtSetArg(args[4], XtNright,  XtChainRight);
2215     XtSetValues(boardWidget, args, 5);
2216
2217     XtRealizeWidget(shellWidget);
2218
2219     if(wpMain.x > 0) {
2220       XtSetArg(args[0], XtNx, wpMain.x);
2221       XtSetArg(args[1], XtNy, wpMain.y);
2222       XtSetValues(shellWidget, args, 2);
2223     }
2224
2225     /*
2226      * Correct the width of the message and title widgets.
2227      * It is not known why some systems need the extra fudge term.
2228      * The value "2" is probably larger than needed.
2229      */
2230     XawFormDoLayout(formWidget, False);
2231
2232 #define WIDTH_FUDGE 2
2233     i = 0;
2234     XtSetArg(args[i], XtNborderWidth, &bor);  i++;
2235     XtSetArg(args[i], XtNheight, &h);  i++;
2236     XtGetValues(messageWidget, args, i);
2237     if (appData.showButtonBar) {
2238       i = 0;
2239       XtSetArg(args[i], XtNwidth, &w);  i++;
2240       XtGetValues(buttonBarWidget, args, i);
2241       w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2242     } else {
2243       w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2244     }
2245
2246     gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2247     if (gres != XtGeometryYes && appData.debugMode) {
2248       fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2249               programName, gres, w, h, wr, hr);
2250     }
2251
2252     /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2253     /* The size used for the child widget in layout lags one resize behind
2254        its true size, so we resize a second time, 1 pixel smaller.  Yeech! */
2255     w--;
2256     gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2257     if (gres != XtGeometryYes && appData.debugMode) {
2258       fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2259               programName, gres, w, h, wr, hr);
2260     }
2261     /* !! end hack */
2262     XtSetArg(args[0], XtNleft,  XtChainLeft);  // [HGM] glue ends for good run-time sizing
2263     XtSetArg(args[1], XtNright, XtChainRight);
2264     XtSetValues(messageWidget, args, 2);
2265
2266     if (appData.titleInWindow) {
2267         i = 0;
2268         XtSetArg(args[i], XtNborderWidth, &bor); i++;
2269         XtSetArg(args[i], XtNheight, &h);  i++;
2270         XtGetValues(titleWidget, args, i);
2271         if (smallLayout) {
2272             w = boardWidth - 2*bor;
2273         } else {
2274             XtSetArg(args[0], XtNwidth, &w);
2275             XtGetValues(menuBarWidget, args, 1);
2276             w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2277         }
2278
2279         gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2280         if (gres != XtGeometryYes && appData.debugMode) {
2281             fprintf(stderr,
2282                     _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2283                     programName, gres, w, h, wr, hr);
2284         }
2285     }
2286     XawFormDoLayout(formWidget, True);
2287
2288     xBoardWindow = XtWindow(boardWidget);
2289
2290     // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2291     //       not need to go into InitDrawingSizes().
2292 #endif
2293
2294     /*
2295      * Create X checkmark bitmap and initialize option menu checks.
2296      */
2297     ReadBitmap(&xMarkPixmap, "checkmark.bm",
2298                checkmark_bits, checkmark_width, checkmark_height);
2299     XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2300     if (appData.alwaysPromoteToQueen) {
2301         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2302                     args, 1);
2303     }
2304     if (appData.animateDragging) {
2305         XtSetValues(XtNameToWidget(menuBarWidget,
2306                                    "menuOptions.Animate Dragging"),
2307                     args, 1);
2308     }
2309     if (appData.animate) {
2310         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2311                     args, 1);
2312     }
2313     if (appData.autoComment) {
2314         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2315                     args, 1);
2316     }
2317     if (appData.autoCallFlag) {
2318         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2319                     args, 1);
2320     }
2321     if (appData.autoFlipView) {
2322         XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2323                     args, 1);
2324     }
2325     if (appData.autoObserve) {
2326         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2327                     args, 1);
2328     }
2329     if (appData.autoRaiseBoard) {
2330         XtSetValues(XtNameToWidget(menuBarWidget,
2331                                    "menuOptions.Auto Raise Board"), args, 1);
2332     }
2333     if (appData.autoSaveGames) {
2334         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2335                     args, 1);
2336     }
2337     if (appData.saveGameFile[0] != NULLCHAR) {
2338         /* Can't turn this off from menu */
2339         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2340                     args, 1);
2341         XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2342                        False);
2343
2344     }
2345     if (appData.blindfold) {
2346         XtSetValues(XtNameToWidget(menuBarWidget,
2347                                    "menuOptions.Blindfold"), args, 1);
2348     }
2349     if (appData.flashCount > 0) {
2350         XtSetValues(XtNameToWidget(menuBarWidget,
2351                                    "menuOptions.Flash Moves"),
2352                     args, 1);
2353     }
2354     if (appData.getMoveList) {
2355         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2356                     args, 1);
2357     }
2358 #if HIGHDRAG
2359     if (appData.highlightDragging) {
2360         XtSetValues(XtNameToWidget(menuBarWidget,
2361                                    "menuOptions.Highlight Dragging"),
2362                     args, 1);
2363     }
2364 #endif
2365     if (appData.highlightLastMove) {
2366         XtSetValues(XtNameToWidget(menuBarWidget,
2367                                    "menuOptions.Highlight Last Move"),
2368                     args, 1);
2369     }
2370     if (appData.icsAlarm) {
2371         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2372                     args, 1);
2373     }
2374     if (appData.ringBellAfterMoves) {
2375         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2376                     args, 1);
2377     }
2378     if (appData.oldSaveStyle) {
2379         XtSetValues(XtNameToWidget(menuBarWidget,
2380                                    "menuOptions.Old Save Style"), args, 1);
2381     }
2382     if (appData.periodicUpdates) {
2383         XtSetValues(XtNameToWidget(menuBarWidget,
2384                                    "menuOptions.Periodic Updates"), args, 1);
2385     }
2386     if (appData.ponderNextMove) {
2387         XtSetValues(XtNameToWidget(menuBarWidget,
2388                                    "menuOptions.Ponder Next Move"), args, 1);
2389     }
2390     if (appData.popupExitMessage) {
2391         XtSetValues(XtNameToWidget(menuBarWidget,
2392                                    "menuOptions.Popup Exit Message"), args, 1);
2393     }
2394     if (appData.popupMoveErrors) {
2395         XtSetValues(XtNameToWidget(menuBarWidget,
2396                                    "menuOptions.Popup Move Errors"), args, 1);
2397     }
2398     if (appData.premove) {
2399         XtSetValues(XtNameToWidget(menuBarWidget,
2400                                    "menuOptions.Premove"), args, 1);
2401     }
2402     if (appData.quietPlay) {
2403         XtSetValues(XtNameToWidget(menuBarWidget,
2404                                    "menuOptions.Quiet Play"), args, 1);
2405     }
2406     if (appData.showCoords) {
2407         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2408                     args, 1);
2409     }
2410     if (appData.hideThinkingFromHuman) {
2411         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2412                     args, 1);
2413     }
2414     if (appData.testLegality) {
2415         XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2416                     args, 1);
2417     }
2418     if (saveSettingsOnExit) {
2419         XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2420                     args, 1);
2421     }
2422
2423     /*
2424      * Create an icon.
2425      */
2426     ReadBitmap(&wIconPixmap, "icon_white.bm",
2427                icon_white_bits, icon_white_width, icon_white_height);
2428     ReadBitmap(&bIconPixmap, "icon_black.bm",
2429                icon_black_bits, icon_black_width, icon_black_height);
2430     iconPixmap = wIconPixmap;
2431     i = 0;
2432     XtSetArg(args[i], XtNiconPixmap, iconPixmap);  i++;
2433     XtSetValues(shellWidget, args, i);
2434
2435     /*
2436      * Create a cursor for the board widget.
2437      */
2438     window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2439     XChangeWindowAttributes(xDisplay, xBoardWindow,
2440                             CWCursor, &window_attributes);
2441
2442     /*
2443      * Inhibit shell resizing.
2444      */
2445     shellArgs[0].value = (XtArgVal) &w;
2446     shellArgs[1].value = (XtArgVal) &h;
2447     XtGetValues(shellWidget, shellArgs, 2);
2448     shellArgs[4].value = shellArgs[2].value = w;
2449     shellArgs[5].value = shellArgs[3].value = h;
2450     XtSetValues(shellWidget, &shellArgs[2], 4);
2451     marginW =  w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2452     marginH =  h - boardHeight;
2453
2454     CatchDeleteWindow(shellWidget, "QuitProc");
2455
2456     CreateGCs();
2457     CreateGrid();
2458 #if HAVE_LIBXPM
2459     if (appData.bitmapDirectory[0] != NULLCHAR) {
2460       CreatePieces();
2461     } else {
2462       CreateXPMPieces();
2463     }
2464 #else
2465     CreateXIMPieces();
2466     /* Create regular pieces */
2467     if (!useImages) CreatePieces();
2468 #endif
2469
2470     CreatePieceMenus();
2471
2472     if (appData.animate || appData.animateDragging)
2473       CreateAnimVars();
2474
2475     XtAugmentTranslations(formWidget,
2476                           XtParseTranslationTable(globalTranslations));
2477     XtAugmentTranslations(boardWidget,
2478                           XtParseTranslationTable(boardTranslations));
2479     XtAugmentTranslations(whiteTimerWidget,
2480                           XtParseTranslationTable(whiteTranslations));
2481     XtAugmentTranslations(blackTimerWidget,
2482                           XtParseTranslationTable(blackTranslations));
2483
2484     /* Why is the following needed on some versions of X instead
2485      * of a translation? */
2486     XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2487                       (XtEventHandler) EventProc, NULL);
2488     /* end why */
2489
2490     /* [AS] Restore layout */
2491     if( wpMoveHistory.visible ) {
2492       HistoryPopUp();
2493     }
2494
2495     if( wpEvalGraph.visible ) 
2496       {
2497         EvalGraphPopUp();
2498       };
2499     
2500     if( wpEngineOutput.visible ) {
2501       EngineOutputPopUp();
2502     }
2503
2504     InitBackEnd2();
2505
2506     if (errorExitStatus == -1) {
2507         if (appData.icsActive) {
2508             /* We now wait until we see "login:" from the ICS before
2509                sending the logon script (problems with timestamp otherwise) */
2510             /*ICSInitScript();*/
2511             if (appData.icsInputBox) ICSInputBoxPopUp();
2512         }
2513
2514     #ifdef SIGWINCH
2515     signal(SIGWINCH, TermSizeSigHandler);
2516     #endif
2517         signal(SIGINT, IntSigHandler);
2518         signal(SIGTERM, IntSigHandler);
2519         if (*appData.cmailGameName != NULLCHAR) {
2520             signal(SIGUSR1, CmailSigHandler);
2521         }
2522     }
2523     gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2524     InitPosition(TRUE);
2525
2526     XtAppMainLoop(appContext);
2527     if (appData.debugMode) fclose(debugFP); // [DM] debug
2528     return 0;
2529 }
2530
2531 void
2532 ShutDownFrontEnd()
2533 {
2534     if (appData.icsActive && oldICSInteractionTitle != NULL) {
2535         DisplayIcsInteractionTitle(oldICSInteractionTitle);
2536     }
2537     if (saveSettingsOnExit) SaveSettings(settingsFileName);
2538     unlink(gameCopyFilename);
2539     unlink(gamePasteFilename);
2540 }
2541
2542 RETSIGTYPE TermSizeSigHandler(int sig)
2543 {
2544     update_ics_width();
2545 }
2546
2547 RETSIGTYPE
2548 IntSigHandler(sig)
2549      int sig;
2550 {
2551     ExitEvent(sig);
2552 }
2553
2554 RETSIGTYPE
2555 CmailSigHandler(sig)
2556      int sig;
2557 {
2558     int dummy = 0;
2559     int error;
2560
2561     signal(SIGUSR1, SIG_IGN);   /* suspend handler     */
2562
2563     /* Activate call-back function CmailSigHandlerCallBack()             */
2564     OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2565
2566     signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2567 }
2568
2569 void
2570 CmailSigHandlerCallBack(isr, closure, message, count, error)
2571      InputSourceRef isr;
2572      VOIDSTAR closure;
2573      char *message;
2574      int count;
2575      int error;
2576 {
2577     BoardToTop();
2578     ReloadCmailMsgEvent(TRUE);  /* Reload cmail msg  */
2579 }
2580 /**** end signal code ****/
2581
2582
2583 void
2584 ICSInitScript()
2585 {
2586     FILE *f;
2587     char buf[MSG_SIZ];
2588     char *p;
2589
2590     f = fopen(appData.icsLogon, "r");
2591     if (f == NULL) {
2592         p = getenv("HOME");
2593         if (p != NULL) {
2594             strcpy(buf, p);
2595             strcat(buf, "/");
2596             strcat(buf, appData.icsLogon);
2597             f = fopen(buf, "r");
2598         }
2599     }
2600     if (f != NULL)
2601       ProcessICSInitScript(f);
2602 }
2603
2604 void
2605 ResetFrontEnd()
2606 {
2607     CommentPopDown();
2608     EditCommentPopDown();
2609     TagsPopDown();
2610     return;
2611 }
2612
2613 typedef struct {
2614     char *name;
2615     Boolean value;
2616 } Enables;
2617
2618 void
2619 GreyRevert(grey)
2620      Boolean grey;
2621 {
2622     Widget w;
2623     if (!menuBarWidget) return;
2624     w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2625     if (w == NULL) {
2626       DisplayError("menuStep.Revert", 0);
2627     } else {
2628       XtSetSensitive(w, !grey);
2629     }
2630     w = XtNameToWidget(menuBarWidget, "menuStep.Annotate");
2631     if (w == NULL) {
2632       DisplayError("menuStep.Annotate", 0);
2633     } else {
2634       XtSetSensitive(w, !grey);
2635     }
2636 }
2637
2638 void
2639 SetMenuEnables(enab)
2640      Enables *enab;
2641 {
2642   Widget w;
2643   if (!menuBarWidget) return;
2644   while (enab->name != NULL) {
2645     w = XtNameToWidget(menuBarWidget, enab->name);
2646     if (w == NULL) {
2647       DisplayError(enab->name, 0);
2648     } else {
2649       XtSetSensitive(w, enab->value);
2650     }
2651     enab++;
2652   }
2653 }
2654
2655 Enables icsEnables[] = {
2656     { "menuFile.Mail Move", False },
2657     { "menuFile.Reload CMail Message", False },
2658     { "menuMode.Machine Black", False },
2659     { "menuMode.Machine White", False },
2660     { "menuMode.Analysis Mode", False },
2661     { "menuMode.Analyze File", False },
2662     { "menuMode.Two Machines", False },
2663 #ifndef ZIPPY
2664     { "menuHelp.Hint", False },
2665     { "menuHelp.Book", False },
2666     { "menuStep.Move Now", False },
2667     { "menuOptions.Periodic Updates", False },
2668     { "menuOptions.Hide Thinking", False },
2669     { "menuOptions.Ponder Next Move", False },
2670 #endif
2671     { "menuStep.Annotate", False },
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.Annotate", False },
2688     { "menuStep.Move Now", False },
2689     { "menuStep.Retract Move", False },
2690     { "menuOptions.Auto Comment", False },
2691     { "menuOptions.Auto Flag", False },
2692     { "menuOptions.Auto Flip View", False },
2693     { "menuOptions.Auto Observe", False },
2694     { "menuOptions.Auto Raise Board", False },
2695     { "menuOptions.Get Move List", False },
2696     { "menuOptions.ICS Alarm", False },
2697     { "menuOptions.Move Sound", False },
2698     { "menuOptions.Quiet Play", False },
2699     { "menuOptions.Hide Thinking", False },
2700     { "menuOptions.Periodic Updates", False },
2701     { "menuOptions.Ponder Next Move", False },
2702     { "menuHelp.Hint", False },
2703     { "menuHelp.Book", False },
2704     { NULL, False }
2705 };
2706
2707 Enables gnuEnables[] = {
2708     { "menuMode.ICS Client", False },
2709     { "menuMode.ICS Input Box", False },
2710     { "menuAction.Accept", False },
2711     { "menuAction.Decline", False },
2712     { "menuAction.Rematch", False },
2713     { "menuAction.Adjourn", False },
2714     { "menuAction.Stop Examining", False },
2715     { "menuAction.Stop Observing", False },
2716     { "menuAction.Upload to Examine", False },
2717     { "menuStep.Revert", False },
2718     { "menuStep.Annotate", False },
2719     { "menuOptions.Auto Comment", False },
2720     { "menuOptions.Auto Observe", False },
2721     { "menuOptions.Auto Raise Board", False },
2722     { "menuOptions.Get Move List", False },
2723     { "menuOptions.Premove", False },
2724     { "menuOptions.Quiet Play", False },
2725
2726     /* The next two options rely on SetCmailMode being called *after*    */
2727     /* SetGNUMode so that when GNU is being used to give hints these     */
2728     /* menu options are still available                                  */
2729
2730     { "menuFile.Mail Move", False },
2731     { "menuFile.Reload CMail Message", False },
2732     { NULL, False }
2733 };
2734
2735 Enables cmailEnables[] = {
2736     { "Action", True },
2737     { "menuAction.Call Flag", False },
2738     { "menuAction.Draw", True },
2739     { "menuAction.Adjourn", False },
2740     { "menuAction.Abort", False },
2741     { "menuAction.Stop Observing", False },
2742     { "menuAction.Stop Examining", False },
2743     { "menuFile.Mail Move", True },
2744     { "menuFile.Reload CMail Message", True },
2745     { NULL, False }
2746 };
2747
2748 Enables trainingOnEnables[] = {
2749   { "menuMode.Edit Comment", False },
2750   { "menuMode.Pause", False },
2751   { "menuStep.Forward", False },
2752   { "menuStep.Backward", False },
2753   { "menuStep.Forward to End", False },
2754   { "menuStep.Back to Start", False },
2755   { "menuStep.Move Now", False },
2756   { "menuStep.Truncate Game", False },
2757   { NULL, False }
2758 };
2759
2760 Enables trainingOffEnables[] = {
2761   { "menuMode.Edit Comment", True },
2762   { "menuMode.Pause", True },
2763   { "menuStep.Forward", True },
2764   { "menuStep.Backward", True },
2765   { "menuStep.Forward to End", True },
2766   { "menuStep.Back to Start", True },
2767   { "menuStep.Move Now", True },
2768   { "menuStep.Truncate Game", True },
2769   { NULL, False }
2770 };
2771
2772 Enables machineThinkingEnables[] = {
2773   { "menuFile.Load Game", False },
2774   { "menuFile.Load Next Game", False },
2775   { "menuFile.Load Previous Game", False },
2776   { "menuFile.Reload Same Game", False },
2777   { "menuFile.Paste Game", False },
2778   { "menuFile.Load Position", False },
2779   { "menuFile.Load Next Position", False },
2780   { "menuFile.Load Previous Position", False },
2781   { "menuFile.Reload Same Position", False },
2782   { "menuFile.Paste Position", False },
2783   { "menuMode.Machine White", False },
2784   { "menuMode.Machine Black", False },
2785   { "menuMode.Two Machines", False },
2786   { "menuStep.Retract Move", False },
2787   { NULL, False }
2788 };
2789
2790 Enables userThinkingEnables[] = {
2791   { "menuFile.Load Game", True },
2792   { "menuFile.Load Next Game", True },
2793   { "menuFile.Load Previous Game", True },
2794   { "menuFile.Reload Same Game", True },
2795   { "menuFile.Paste Game", True },
2796   { "menuFile.Load Position", True },
2797   { "menuFile.Load Next Position", True },
2798   { "menuFile.Load Previous Position", True },
2799   { "menuFile.Reload Same Position", True },
2800   { "menuFile.Paste Position", True },
2801   { "menuMode.Machine White", True },
2802   { "menuMode.Machine Black", True },
2803   { "menuMode.Two Machines", True },
2804   { "menuStep.Retract Move", True },
2805   { NULL, False }
2806 };
2807
2808 void SetICSMode()
2809 {
2810   SetMenuEnables(icsEnables);
2811
2812 #ifdef ZIPPY
2813   if (appData.zippyPlay && !appData.noChessProgram)   /* [DM] icsEngineAnalyze */
2814      XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2815 #endif
2816 }
2817
2818 void
2819 SetNCPMode()
2820 {
2821   SetMenuEnables(ncpEnables);
2822 }
2823
2824 void
2825 SetGNUMode()
2826 {
2827   SetMenuEnables(gnuEnables);
2828 }
2829
2830 void
2831 SetCmailMode()
2832 {
2833   SetMenuEnables(cmailEnables);
2834 }
2835
2836 void
2837 SetTrainingModeOn()
2838 {
2839   SetMenuEnables(trainingOnEnables);
2840   if (appData.showButtonBar) {
2841     XtSetSensitive(buttonBarWidget, False);
2842   }
2843   CommentPopDown();
2844 }
2845
2846 void
2847 SetTrainingModeOff()
2848 {
2849   SetMenuEnables(trainingOffEnables);
2850   if (appData.showButtonBar) {
2851     XtSetSensitive(buttonBarWidget, True);
2852   }
2853 }
2854
2855 void
2856 SetUserThinkingEnables()
2857 {
2858   if (appData.noChessProgram) return;
2859   SetMenuEnables(userThinkingEnables);
2860 }
2861
2862 void
2863 SetMachineThinkingEnables()
2864 {
2865   if (appData.noChessProgram) return;
2866   SetMenuEnables(machineThinkingEnables);
2867   switch (gameMode) {
2868   case MachinePlaysBlack:
2869   case MachinePlaysWhite:
2870   case TwoMachinesPlay:
2871     XtSetSensitive(XtNameToWidget(menuBarWidget,
2872                                   ModeToWidgetName(gameMode)), True);
2873     break;
2874   default:
2875     break;
2876   }
2877 }
2878
2879 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2880 #define HISTORY_SIZE 64\r
2881 static char *history[HISTORY_SIZE];\r
2882 int histIn = 0, histP = 0;\r
2883 \r
2884 void\r
2885 SaveInHistory(char *cmd)\r
2886 {\r
2887   if (history[histIn] != NULL) {\r
2888     free(history[histIn]);\r
2889     history[histIn] = NULL;\r
2890   }\r
2891   if (*cmd == NULLCHAR) return;\r
2892   history[histIn] = StrSave(cmd);\r
2893   histIn = (histIn + 1) % HISTORY_SIZE;\r
2894   if (history[histIn] != NULL) {\r
2895     free(history[histIn]);\r
2896     history[histIn] = NULL;\r
2897   }\r
2898   histP = histIn;\r
2899 }\r
2900 \r
2901 char *\r
2902 PrevInHistory(char *cmd)\r
2903 {\r
2904   int newhp;\r
2905   if (histP == histIn) {\r
2906     if (history[histIn] != NULL) free(history[histIn]);\r
2907     history[histIn] = StrSave(cmd);\r
2908   }\r
2909   newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;\r
2910   if (newhp == histIn || history[newhp] == NULL) return NULL;\r
2911   histP = newhp;\r
2912   return history[histP];\r
2913 }\r
2914 \r
2915 char *\r
2916 NextInHistory()\r
2917 {\r
2918   if (histP == histIn) return NULL;\r
2919   histP = (histP + 1) % HISTORY_SIZE;\r
2920   return history[histP];   \r
2921 }
2922 // end of borrowed code\r
2923 \r
2924 #define Abs(n) ((n)<0 ? -(n) : (n))
2925
2926 /*
2927  * Find a font that matches "pattern" that is as close as
2928  * possible to the targetPxlSize.  Prefer fonts that are k
2929  * pixels smaller to fonts that are k pixels larger.  The
2930  * pattern must be in the X Consortium standard format,
2931  * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2932  * The return value should be freed with XtFree when no
2933  * longer needed.
2934  */
2935 char *FindFont(pattern, targetPxlSize)
2936      char *pattern;
2937      int targetPxlSize;
2938 {
2939     char **fonts, *p, *best, *scalable, *scalableTail;
2940     int i, j, nfonts, minerr, err, pxlSize;
2941
2942 #ifdef ENABLE_NLS
2943     char **missing_list;
2944     int missing_count;
2945     char *def_string, *base_fnt_lst, strInt[3];
2946     XFontSet fntSet;
2947     XFontStruct **fnt_list;
2948
2949     base_fnt_lst = calloc(1, strlen(pattern) + 3);
2950     sprintf(strInt, "%d", targetPxlSize);
2951     p = strstr(pattern, "--");
2952     strncpy(base_fnt_lst, pattern, p - pattern + 2);
2953     strcat(base_fnt_lst, strInt);
2954     strcat(base_fnt_lst, strchr(p + 2, '-'));
2955
2956     if ((fntSet = XCreateFontSet(xDisplay,
2957                                  base_fnt_lst,
2958                                  &missing_list,
2959                                  &missing_count,
2960                                  &def_string)) == NULL) {
2961
2962        fprintf(stderr, _("Unable to create font set.\n"));
2963        exit (2);
2964     }
2965
2966     nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2967 #else
2968     fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2969     if (nfonts < 1) {
2970         fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2971                 programName, pattern);
2972         exit(2);
2973     }
2974 #endif
2975
2976     best = fonts[0];
2977     scalable = NULL;
2978     minerr = 999999;
2979     for (i=0; i<nfonts; i++) {
2980         j = 0;
2981         p = fonts[i];
2982         if (*p != '-') continue;
2983         while (j < 7) {
2984             if (*p == NULLCHAR) break;
2985             if (*p++ == '-') j++;
2986         }
2987         if (j < 7) continue;
2988         pxlSize = atoi(p);
2989         if (pxlSize == 0) {
2990             scalable = fonts[i];
2991             scalableTail = p;
2992         } else {
2993             err = pxlSize - targetPxlSize;
2994             if (Abs(err) < Abs(minerr) ||
2995                 (minerr > 0 && err < 0 && -err == minerr)) {
2996                 best = fonts[i];
2997                 minerr = err;
2998             }
2999         }
3000     }
3001     if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3002         /* If the error is too big and there is a scalable font,
3003            use the scalable font. */
3004         int headlen = scalableTail - scalable;
3005         p = (char *) XtMalloc(strlen(scalable) + 10);
3006         while (isdigit(*scalableTail)) scalableTail++;
3007         sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3008     } else {
3009         p = (char *) XtMalloc(strlen(best) + 1);
3010         strcpy(p, best);
3011     }
3012     if (appData.debugMode) {
3013         fprintf(debugFP, _("resolved %s at pixel size %d\n  to %s\n"),
3014                 pattern, targetPxlSize, p);
3015     }
3016 #ifdef ENABLE_NLS
3017     if (missing_count > 0)
3018        XFreeStringList(missing_list);
3019     XFreeFontSet(xDisplay, fntSet);
3020 #else
3021      XFreeFontNames(fonts);
3022 #endif
3023     return p;
3024 }
3025
3026 void CreateGCs()
3027 {
3028     XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3029       | GCBackground | GCFunction | GCPlaneMask;
3030     XGCValues gc_values;
3031     GC copyInvertedGC;
3032
3033     gc_values.plane_mask = AllPlanes;
3034     gc_values.line_width = lineGap;
3035     gc_values.line_style = LineSolid;
3036     gc_values.function = GXcopy;
3037
3038     gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3039     gc_values.background = XBlackPixel(xDisplay, xScreen);
3040     lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3041
3042     gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3043     gc_values.background = XWhitePixel(xDisplay, xScreen);
3044     coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3045     XSetFont(xDisplay, coordGC, coordFontID);
3046
3047     // [HGM] make font for holdings counts (white on black0
3048     gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3049     gc_values.background = XBlackPixel(xDisplay, xScreen);
3050     countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3051     XSetFont(xDisplay, countGC, countFontID);
3052
3053     if (appData.monoMode) {
3054         gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3055         gc_values.background = XWhitePixel(xDisplay, xScreen);
3056         highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3057
3058         gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3059         gc_values.background = XBlackPixel(xDisplay, xScreen);
3060         lightSquareGC = wbPieceGC
3061           = XtGetGC(shellWidget, value_mask, &gc_values);
3062
3063         gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3064         gc_values.background = XWhitePixel(xDisplay, xScreen);
3065         darkSquareGC = bwPieceGC
3066           = XtGetGC(shellWidget, value_mask, &gc_values);
3067
3068         if (DefaultDepth(xDisplay, xScreen) == 1) {
3069             /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3070             gc_values.function = GXcopyInverted;
3071             copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3072             gc_values.function = GXcopy;
3073             if (XBlackPixel(xDisplay, xScreen) == 1) {
3074                 bwPieceGC = darkSquareGC;
3075                 wbPieceGC = copyInvertedGC;
3076             } else {
3077                 bwPieceGC = copyInvertedGC;
3078                 wbPieceGC = lightSquareGC;
3079             }
3080         }
3081     } else {
3082         gc_values.foreground = highlightSquareColor;
3083         gc_values.background = highlightSquareColor;
3084         highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3085
3086         gc_values.foreground = premoveHighlightColor;
3087         gc_values.background = premoveHighlightColor;
3088         prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3089
3090         gc_values.foreground = lightSquareColor;
3091         gc_values.background = darkSquareColor;
3092         lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3093
3094         gc_values.foreground = darkSquareColor;
3095         gc_values.background = lightSquareColor;
3096         darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3097
3098         gc_values.foreground = jailSquareColor;
3099         gc_values.background = jailSquareColor;
3100         jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3101
3102         gc_values.foreground = whitePieceColor;
3103         gc_values.background = darkSquareColor;
3104         wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3105
3106         gc_values.foreground = whitePieceColor;
3107         gc_values.background = lightSquareColor;
3108         wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3109
3110         gc_values.foreground = whitePieceColor;
3111         gc_values.background = jailSquareColor;
3112         wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3113
3114         gc_values.foreground = blackPieceColor;
3115         gc_values.background = darkSquareColor;
3116         bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3117
3118         gc_values.foreground = blackPieceColor;
3119         gc_values.background = lightSquareColor;
3120         blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3121
3122         gc_values.foreground = blackPieceColor;
3123         gc_values.background = jailSquareColor;
3124         bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3125     }
3126 }
3127
3128 void loadXIM(xim, xmask, filename, dest, mask)
3129      XImage *xim;
3130      XImage *xmask;
3131      char *filename;
3132      Pixmap *dest;
3133      Pixmap *mask;
3134 {
3135     int x, y, w, h, p;
3136     FILE *fp;
3137     Pixmap temp;
3138     XGCValues   values;
3139     GC maskGC;
3140
3141     fp = fopen(filename, "rb");
3142     if (!fp) {
3143         fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3144         exit(1);
3145     }
3146
3147     w = fgetc(fp);
3148     h = fgetc(fp);
3149
3150     for (y=0; y<h; ++y) {
3151         for (x=0; x<h; ++x) {
3152             p = fgetc(fp);
3153
3154             switch (p) {
3155               case 0:
3156                 XPutPixel(xim, x, y, blackPieceColor);
3157                 if (xmask)
3158                   XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3159                 break;
3160               case 1:
3161                 XPutPixel(xim, x, y, darkSquareColor);
3162                 if (xmask)
3163                   XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3164                 break;
3165               case 2:
3166                 XPutPixel(xim, x, y, whitePieceColor);
3167                 if (xmask)
3168                   XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3169                 break;
3170               case 3:
3171                 XPutPixel(xim, x, y, lightSquareColor);
3172                 if (xmask)
3173                   XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3174                 break;
3175             }
3176         }
3177     }
3178
3179     /* create Pixmap of piece */
3180     *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3181                           w, h, xim->depth);
3182     XPutImage(xDisplay, *dest, lightSquareGC, xim,
3183               0, 0, 0, 0, w, h);
3184
3185     /* create Pixmap of clipmask
3186        Note: We assume the white/black pieces have the same
3187              outline, so we make only 6 masks. This is okay
3188              since the XPM clipmask routines do the same. */
3189     if (xmask) {
3190       temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3191                             w, h, xim->depth);
3192       XPutImage(xDisplay, temp, lightSquareGC, xmask,
3193               0, 0, 0, 0, w, h);
3194
3195       /* now create the 1-bit version */
3196       *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3197                           w, h, 1);
3198
3199       values.foreground = 1;
3200       values.background = 0;
3201
3202       /* Don't use XtGetGC, not read only */
3203       maskGC = XCreateGC(xDisplay, *mask,
3204                     GCForeground | GCBackground, &values);
3205       XCopyPlane(xDisplay, temp, *mask, maskGC,
3206                   0, 0, squareSize, squareSize, 0, 0, 1);
3207       XFreePixmap(xDisplay, temp);
3208     }
3209 }
3210
3211
3212 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3213
3214 void CreateXIMPieces()
3215 {
3216     int piece, kind;
3217     char buf[MSG_SIZ];
3218     u_int ss;
3219     static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3220     XImage *ximtemp;
3221
3222     ss = squareSize;
3223
3224     /* The XSynchronize calls were copied from CreatePieces.
3225        Not sure if needed, but can't hurt */
3226     XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3227                                      buffering bug */
3228
3229     /* temp needed by loadXIM() */
3230     ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3231                  0, 0, ss, ss, AllPlanes, XYPixmap);
3232
3233     if (strlen(appData.pixmapDirectory) == 0) {
3234       useImages = 0;
3235     } else {
3236         useImages = 1;
3237         if (appData.monoMode) {
3238           DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3239                             0, 2);
3240           ExitEvent(2);
3241         }
3242         fprintf(stderr, _("\nLoading XIMs...\n"));
3243         /* Load pieces */
3244         for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3245             fprintf(stderr, "%d", piece+1);
3246             for (kind=0; kind<4; kind++) {
3247                 fprintf(stderr, ".");
3248                 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3249                         ExpandPathName(appData.pixmapDirectory),
3250                         piece <= (int) WhiteKing ? "" : "w",
3251                         pieceBitmapNames[piece],
3252                         ximkind[kind], ss);
3253                 ximPieceBitmap[kind][piece] =
3254                   XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3255                             0, 0, ss, ss, AllPlanes, XYPixmap);
3256                 if (appData.debugMode)
3257                   fprintf(stderr, _("(File:%s:) "), buf);
3258                 loadXIM(ximPieceBitmap[kind][piece],
3259                         ximtemp, buf,
3260                         &(xpmPieceBitmap2[kind][piece]),
3261                         &(ximMaskPm2[piece]));
3262                 if(piece <= (int)WhiteKing)
3263                     xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3264             }
3265             fprintf(stderr," ");
3266         }
3267         /* Load light and dark squares */
3268         /* If the LSQ and DSQ pieces don't exist, we will
3269            draw them with solid squares. */
3270         snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3271         if (access(buf, 0) != 0) {
3272             useImageSqs = 0;
3273         } else {
3274             useImageSqs = 1;
3275             fprintf(stderr, _("light square "));
3276             ximLightSquare=
3277               XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3278                         0, 0, ss, ss, AllPlanes, XYPixmap);
3279             if (appData.debugMode)
3280               fprintf(stderr, _("(File:%s:) "), buf);
3281
3282             loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3283             fprintf(stderr, _("dark square "));
3284             snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3285                     ExpandPathName(appData.pixmapDirectory), ss);
3286             if (appData.debugMode)
3287               fprintf(stderr, _("(File:%s:) "), buf);
3288             ximDarkSquare=
3289               XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3290                         0, 0, ss, ss, AllPlanes, XYPixmap);
3291             loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3292             xpmJailSquare = xpmLightSquare;
3293         }
3294         fprintf(stderr, _("Done.\n"));
3295     }
3296     XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3297 }
3298
3299 #if HAVE_LIBXPM
3300 void CreateXPMPieces()
3301 {
3302     int piece, kind, r;
3303     char buf[MSG_SIZ];
3304     u_int ss = squareSize;
3305     XpmAttributes attr;
3306     static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3307     XpmColorSymbol symbols[4];
3308
3309     /* The XSynchronize calls were copied from CreatePieces.
3310        Not sure if needed, but can't hurt */
3311     XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3312
3313     /* Setup translations so piece colors match square colors */
3314     symbols[0].name = "light_piece";
3315     symbols[0].value = appData.whitePieceColor;
3316     symbols[1].name = "dark_piece";
3317     symbols[1].value = appData.blackPieceColor;
3318     symbols[2].name = "light_square";
3319     symbols[2].value = appData.lightSquareColor;
3320     symbols[3].name = "dark_square";
3321     symbols[3].value = appData.darkSquareColor;
3322
3323     attr.valuemask = XpmColorSymbols;
3324     attr.colorsymbols = symbols;
3325     attr.numsymbols = 4;
3326
3327     if (appData.monoMode) {
3328       DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3329                         0, 2);
3330       ExitEvent(2);
3331     }
3332     if (strlen(appData.pixmapDirectory) == 0) {
3333         XpmPieces* pieces = builtInXpms;
3334         useImages = 1;
3335         /* Load pieces */
3336         while (pieces->size != squareSize && pieces->size) pieces++;
3337         if (!pieces->size) {
3338           fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3339           exit(1);
3340         }
3341         for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3342             for (kind=0; kind<4; kind++) {
3343
3344                 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3345                                                pieces->xpm[piece][kind],
3346                                                &(xpmPieceBitmap2[kind][piece]),
3347                                                NULL, &attr)) != 0) {
3348                   fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3349                           r, buf);
3350                   exit(1);
3351                 }
3352                 if(piece <= (int) WhiteKing)
3353                     xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3354             }
3355         }
3356         useImageSqs = 0;
3357         xpmJailSquare = xpmLightSquare;
3358     } else {
3359         useImages = 1;
3360
3361         fprintf(stderr, _("\nLoading XPMs...\n"));
3362
3363         /* Load pieces */
3364         for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3365             fprintf(stderr, "%d ", piece+1);
3366             for (kind=0; kind<4; kind++) {
3367               snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3368                         ExpandPathName(appData.pixmapDirectory),
3369                         piece > (int) WhiteKing ? "w" : "",
3370                         pieceBitmapNames[piece],
3371                         xpmkind[kind], ss);
3372                 if (appData.debugMode) {
3373                     fprintf(stderr, _("(File:%s:) "), buf);
3374                 }
3375                 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3376                                            &(xpmPieceBitmap2[kind][piece]),
3377                                            NULL, &attr)) != 0) {
3378                     if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3379                       // [HGM] missing: read of unorthodox piece failed; substitute King.
3380                       snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3381                                 ExpandPathName(appData.pixmapDirectory),
3382                                 xpmkind[kind], ss);
3383                         if (appData.debugMode) {
3384                             fprintf(stderr, _("(Replace by File:%s:) "), buf);
3385                         }
3386                         r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3387                                                 &(xpmPieceBitmap2[kind][piece]),
3388                                                 NULL, &attr);
3389                     }
3390                     if (r != 0) {
3391                         fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3392                                 r, buf);
3393                         exit(1);
3394                     }
3395                 }
3396                 if(piece <= (int) WhiteKing) 
3397                     xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3398             }
3399         }
3400         /* Load light and dark squares */
3401         /* If the LSQ and DSQ pieces don't exist, we will
3402            draw them with solid squares. */
3403         fprintf(stderr, _("light square "));
3404         snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3405         if (access(buf, 0) != 0) {
3406             useImageSqs = 0;
3407         } else {
3408             useImageSqs = 1;
3409             if (appData.debugMode)
3410               fprintf(stderr, _("(File:%s:) "), buf);
3411
3412             if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3413                                        &xpmLightSquare, NULL, &attr)) != 0) {
3414                 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3415                 exit(1);
3416             }
3417             fprintf(stderr, _("dark square "));
3418             snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3419                     ExpandPathName(appData.pixmapDirectory), ss);
3420             if (appData.debugMode) {
3421                 fprintf(stderr, _("(File:%s:) "), buf);
3422             }
3423             if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3424                                        &xpmDarkSquare, NULL, &attr)) != 0) {
3425                 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3426                 exit(1);
3427             }
3428         }
3429         xpmJailSquare = xpmLightSquare;
3430         fprintf(stderr, _("Done.\n"));
3431     }
3432     XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3433                                       buffering bug */
3434 }
3435 #endif /* HAVE_LIBXPM */
3436
3437 #if HAVE_LIBXPM
3438 /* No built-in bitmaps */
3439 void CreatePieces()
3440 {
3441     int piece, kind;
3442     char buf[MSG_SIZ];
3443     u_int ss = squareSize;
3444
3445     XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3446                                      buffering bug */
3447
3448     for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3449         for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3450             sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3451                     pieceBitmapNames[piece],
3452                     ss, kind == SOLID ? 's' : 'o');
3453             ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3454             if(piece <= (int)WhiteKing)
3455                 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3456         }
3457     }
3458
3459     XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3460                                       buffering bug */
3461 }
3462 #else
3463 /* With built-in bitmaps */
3464 void CreatePieces()
3465 {
3466     BuiltInBits* bib = builtInBits;
3467     int piece, kind;
3468     char buf[MSG_SIZ];
3469     u_int ss = squareSize;
3470
3471     XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3472                                      buffering bug */
3473
3474     while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3475
3476     for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3477         for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3478             sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3479                     pieceBitmapNames[piece],
3480                     ss, kind == SOLID ? 's' : 'o');
3481             ReadBitmap(&pieceBitmap2[kind][piece], buf,
3482                        bib->bits[kind][piece], ss, ss);
3483             if(piece <= (int)WhiteKing)
3484                 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3485         }
3486     }
3487
3488     XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3489                                       buffering bug */
3490 }
3491 #endif
3492
3493 void ReadBitmap(pm, name, bits, wreq, hreq)
3494      Pixmap *pm;
3495      String name;
3496      unsigned char bits[];
3497      u_int wreq, hreq;
3498 {
3499     int x_hot, y_hot;
3500     u_int w, h;
3501     int errcode;
3502     char msg[MSG_SIZ], fullname[MSG_SIZ];
3503
3504     if (*appData.bitmapDirectory != NULLCHAR) {
3505         strcpy(fullname, appData.bitmapDirectory);
3506         strcat(fullname, "/");
3507         strcat(fullname, name);
3508         errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3509                                   &w, &h, pm, &x_hot, &y_hot);
3510     fprintf(stderr, "load %s\n", name);
3511         if (errcode != BitmapSuccess) {
3512             switch (errcode) {
3513               case BitmapOpenFailed:
3514                 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3515                 break;
3516               case BitmapFileInvalid:
3517                 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3518                 break;
3519               case BitmapNoMemory:
3520                 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3521                         fullname);
3522                 break;
3523               default:
3524                 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3525                         errcode, fullname);
3526                 break;
3527             }
3528             fprintf(stderr, _("%s: %s...using built-in\n"),
3529                     programName, msg);
3530         } else if (w != wreq || h != hreq) {
3531             fprintf(stderr,
3532                     _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3533                     programName, fullname, w, h, wreq, hreq);
3534         } else {
3535             return;
3536         }
3537     }
3538     if (bits != NULL) {
3539         *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3540                                     wreq, hreq);
3541     }
3542 }
3543
3544 void CreateGrid()
3545 {
3546     int i, j;
3547
3548     if (lineGap == 0) return;
3549
3550     /* [HR] Split this into 2 loops for non-square boards. */
3551
3552     for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3553         gridSegments[i].x1 = 0;
3554         gridSegments[i].x2 =
3555           lineGap + BOARD_WIDTH * (squareSize + lineGap);
3556         gridSegments[i].y1 = gridSegments[i].y2
3557           = lineGap / 2 + (i * (squareSize + lineGap));
3558     }
3559
3560     for (j = 0; j < BOARD_WIDTH + 1; j++) {
3561         gridSegments[j + i].y1 = 0;
3562         gridSegments[j + i].y2 =
3563           lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3564         gridSegments[j + i].x1 = gridSegments[j + i].x2
3565           = lineGap / 2 + (j * (squareSize + lineGap));
3566     }
3567 }
3568
3569 static void MenuBarSelect(w, addr, index)
3570      Widget w;
3571      caddr_t addr;
3572      caddr_t index;
3573 {
3574     XtActionProc proc = (XtActionProc) addr;
3575
3576     (proc)(NULL, NULL, NULL, NULL);
3577 }
3578
3579 void CreateMenuBarPopup(parent, name, mb)
3580      Widget parent;
3581      String name;
3582      Menu *mb;
3583 {
3584     int j;
3585     Widget menu, entry;
3586     MenuItem *mi;
3587     Arg args[16];
3588
3589     menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3590                               parent, NULL, 0);
3591     j = 0;
3592     XtSetArg(args[j], XtNleftMargin, 20);   j++;
3593     XtSetArg(args[j], XtNrightMargin, 20);  j++;
3594     mi = mb->mi;
3595     while (mi->string != NULL) {
3596         if (strcmp(mi->string, "----") == 0) {
3597             entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3598                                           menu, args, j);
3599         } else {
3600           XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3601             entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3602                                           menu, args, j+1);
3603             XtAddCallback(entry, XtNcallback,
3604                           (XtCallbackProc) MenuBarSelect,
3605                           (caddr_t) mi->proc);
3606         }
3607         mi++;
3608     }
3609 }
3610
3611 Widget CreateMenuBar(mb)
3612      Menu *mb;
3613 {
3614     int j;
3615     Widget anchor, menuBar;
3616     Arg args[16];
3617     char menuName[MSG_SIZ];
3618
3619     j = 0;
3620     XtSetArg(args[j], XtNorientation, XtorientHorizontal);  j++;
3621     XtSetArg(args[j], XtNvSpace, 0);                        j++;
3622     XtSetArg(args[j], XtNborderWidth, 0);                   j++;
3623     menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3624                              formWidget, args, j);
3625
3626     while (mb->name != NULL) {
3627         strcpy(menuName, "menu");
3628         strcat(menuName, mb->name);
3629         j = 0;
3630         XtSetArg(args[j], XtNmenuName, XtNewString(menuName));  j++;
3631         if (tinyLayout) {
3632             char shortName[2];