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