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