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