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