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