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