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