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