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