4d10b370129e04d1dc5f8dbbbb1cfc1429085554
[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 SelectMove P((Widget w, XEvent * event, String * params, Cardinal * nParams));
477 void GameListOptionsPopDown 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 Game   Ctrl+G"), "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     {N_(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     { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1041     { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1042     { "GenericPopDown", (XtActionProc) GenericPopDown },
1043     { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1044     { "SelectMove", (XtActionProc) SelectMove },
1045 };
1046
1047 char globalTranslations[] =
1048   ":<Key>F9: ResignProc() \n \
1049    :Ctrl<Key>n: ResetProc() \n \
1050    :Meta<Key>V: NewVariantProc() \n \
1051    :Ctrl<Key>o: LoadGameProc() \n \
1052    :Meta<Key>Next: LoadNextGameProc() \n \
1053    :Meta<Key>Prior: LoadPrevGameProc() \n \
1054    :Ctrl<Key>Down: LoadSelectedProc(3) \n \
1055    :Ctrl<Key>Up: LoadSelectedProc(-3) \n \
1056    :Ctrl<Key>s: SaveGameProc() \n \
1057    :Ctrl<Key>c: CopyGameProc() \n \
1058    :Ctrl<Key>v: PasteGameProc() \n \
1059    :Ctrl<Key>O: LoadPositionProc() \n \
1060    :Shift<Key>Next: LoadNextPositionProc() \n \
1061    :Shift<Key>Prior: LoadPrevPositionProc() \n \
1062    :Ctrl<Key>S: SavePositionProc() \n \
1063    :Ctrl<Key>C: CopyPositionProc() \n \
1064    :Ctrl<Key>V: PastePositionProc() \n \
1065    :Ctrl<Key>q: QuitProc() \n \
1066    :Ctrl<Key>w: MachineWhiteProc() \n \
1067    :Ctrl<Key>b: MachineBlackProc() \n \
1068    :Ctrl<Key>t: TwoMachinesProc() \n \
1069    :Ctrl<Key>a: AnalysisModeProc() \n \
1070    :Ctrl<Key>g: AnalyzeFileProc() \n \
1071    :Ctrl<Key>e: EditGameProc() \n \
1072    :Ctrl<Key>E: EditPositionProc() \n \
1073    :Meta<Key>O: EngineOutputProc() \n \
1074    :Meta<Key>E: EvalGraphProc() \n \
1075    :Meta<Key>G: ShowGameListProc() \n \
1076    :Meta<Key>H: ShowMoveListProc() \n \
1077    :<Key>Pause: PauseProc() \n \
1078    :<Key>F3: AcceptProc() \n \
1079    :<Key>F4: DeclineProc() \n \
1080    :<Key>F12: RematchProc() \n \
1081    :<Key>F5: CallFlagProc() \n \
1082    :<Key>F6: DrawProc() \n \
1083    :<Key>F7: AdjournProc() \n \
1084    :<Key>F8: AbortProc() \n \
1085    :<Key>F10: StopObservingProc() \n \
1086    :<Key>F11: StopExaminingProc() \n \
1087    :Meta Ctrl<Key>F12: DebugProc() \n \
1088    :Meta<Key>End: ToEndProc() \n \
1089    :Meta<Key>Right: ForwardProc() \n \
1090    :Meta<Key>Home: ToStartProc() \n \
1091    :Meta<Key>Left: BackwardProc() \n \
1092    :<Key>Left: BackwardProc() \n \
1093    :<Key>Right: ForwardProc() \n \
1094    :<Key>Home: RevertProc() \n \
1095    :<Key>End: TruncateGameProc() \n \
1096    :Ctrl<Key>m: MoveNowProc() \n \
1097    :Ctrl<Key>x: RetractMoveProc() \n \
1098    :Meta<Key>J: EngineMenuProc() \n \
1099    :Meta<Key>U: UciMenuProc() \n \
1100    :Meta<Key>T: TimeControlProc() \n \
1101    :Ctrl<Key>P: PonderNextMoveProc() \n "
1102 #ifndef OPTIONSDIALOG
1103     "\
1104    :Ctrl<Key>Q: AlwaysQueenProc() \n \
1105    :Ctrl<Key>F: AutoflagProc() \n \
1106    :Ctrl<Key>A: AnimateMovingProc() \n \
1107    :Ctrl<Key>L: TestLegalityProc() \n \
1108    :Ctrl<Key>H: HideThinkingProc() \n "
1109 #endif
1110    "\
1111    :<Key>-: Iconify() \n \
1112    :<Key>F1: ManProc() \n \
1113    :<Key>F2: FlipViewProc() \n \
1114    <KeyDown>.: BackwardProc() \n \
1115    <KeyUp>.: ForwardProc() \n \
1116    Shift<Key>1: AskQuestionProc(\"Direct command\",\
1117                                 \"Send to chess program:\",,1) \n \
1118    Shift<Key>2: AskQuestionProc(\"Direct command\",\
1119                                 \"Send to second chess program:\",,2) \n";
1120
1121 char boardTranslations[] =
1122    "<Btn1Down>: HandleUserMove(0) \n \
1123    Shift<Btn1Up>: HandleUserMove(1) \n \
1124    <Btn1Up>: HandleUserMove(0) \n \
1125    <Btn1Motion>: AnimateUserMove() \n \
1126    <Btn3Motion>: HandlePV() \n \
1127    <Btn3Up>: PieceMenuPopup(menuB) \n \
1128    Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1129                  PieceMenuPopup(menuB) \n \
1130    Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1131                  PieceMenuPopup(menuW) \n \
1132    Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1133                  PieceMenuPopup(menuW) \n \
1134    Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1135                  PieceMenuPopup(menuB) \n";
1136
1137 char whiteTranslations[] =
1138    "Shift<BtnDown>: WhiteClock(1)\n \
1139    <BtnDown>: WhiteClock(0)\n";
1140 char blackTranslations[] =
1141    "Shift<BtnDown>: BlackClock(1)\n \
1142    <BtnDown>: BlackClock(0)\n";
1143
1144 char ICSInputTranslations[] =
1145     "<Key>Up: UpKeyProc() \n "
1146     "<Key>Down: DownKeyProc() \n "
1147     "<Key>Return: EnterKeyProc() \n";
1148
1149 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1150 //             as the widget is destroyed before the up-click can call extend-end
1151 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1152
1153 String xboardResources[] = {
1154     "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1155     "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1156     "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1157     NULL
1158   };
1159
1160
1161 /* Max possible square size */
1162 #define MAXSQSIZE 256
1163
1164 static int xpm_avail[MAXSQSIZE];
1165
1166 #ifdef HAVE_DIR_STRUCT
1167
1168 /* Extract piece size from filename */
1169 static int
1170 xpm_getsize(name, len, ext)
1171      char *name;
1172      int len;
1173      char *ext;
1174 {
1175     char *p, *d;
1176     char buf[10];
1177
1178     if (len < 4)
1179       return 0;
1180
1181     if ((p=strchr(name, '.')) == NULL ||
1182         StrCaseCmp(p+1, ext) != 0)
1183       return 0;
1184
1185     p = name + 3;
1186     d = buf;
1187
1188     while (*p && isdigit(*p))
1189       *(d++) = *(p++);
1190
1191     *d = 0;
1192     return atoi(buf);
1193 }
1194
1195 /* Setup xpm_avail */
1196 static int
1197 xpm_getavail(dirname, ext)
1198      char *dirname;
1199      char *ext;
1200 {
1201     DIR *dir;
1202     struct dirent *ent;
1203     int  i;
1204
1205     for (i=0; i<MAXSQSIZE; ++i)
1206       xpm_avail[i] = 0;
1207
1208     if (appData.debugMode)
1209       fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1210
1211     dir = opendir(dirname);
1212     if (!dir)
1213       {
1214           fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1215                   programName, dirname);
1216           exit(1);
1217       }
1218
1219     while ((ent=readdir(dir)) != NULL) {
1220         i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1221         if (i > 0 && i < MAXSQSIZE)
1222           xpm_avail[i] = 1;
1223     }
1224
1225     closedir(dir);
1226
1227     return 0;
1228 }
1229
1230 void
1231 xpm_print_avail(fp, ext)
1232      FILE *fp;
1233      char *ext;
1234 {
1235     int i;
1236
1237     fprintf(fp, _("Available `%s' sizes:\n"), ext);
1238     for (i=1; i<MAXSQSIZE; ++i) {
1239         if (xpm_avail[i])
1240           printf("%d\n", i);
1241     }
1242 }
1243
1244 /* Return XPM piecesize closest to size */
1245 int
1246 xpm_closest_to(dirname, size, ext)
1247      char *dirname;
1248      int size;
1249      char *ext;
1250 {
1251     int i;
1252     int sm_diff = MAXSQSIZE;
1253     int sm_index = 0;
1254     int diff;
1255
1256     xpm_getavail(dirname, ext);
1257
1258     if (appData.debugMode)
1259       xpm_print_avail(stderr, ext);
1260
1261     for (i=1; i<MAXSQSIZE; ++i) {
1262         if (xpm_avail[i]) {
1263             diff = size - i;
1264             diff = (diff<0) ? -diff : diff;
1265             if (diff < sm_diff) {
1266                 sm_diff = diff;
1267                 sm_index = i;
1268             }
1269         }
1270     }
1271
1272     if (!sm_index) {
1273         fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1274         exit(1);
1275     }
1276
1277     return sm_index;
1278 }
1279 #else   /* !HAVE_DIR_STRUCT */
1280 /* If we are on a system without a DIR struct, we can't
1281    read the directory, so we can't collect a list of
1282    filenames, etc., so we can't do any size-fitting. */
1283 int
1284 xpm_closest_to(dirname, size, ext)
1285      char *dirname;
1286      int size;
1287      char *ext;
1288 {
1289     fprintf(stderr, _("\
1290 Warning: No DIR structure found on this system --\n\
1291          Unable to autosize for XPM/XIM pieces.\n\
1292    Please report this error to %s.\n\
1293    Include system type & operating system in message.\n"), PACKAGE_BUGREPORT););
1294     return size;
1295 }
1296 #endif /* HAVE_DIR_STRUCT */
1297
1298 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1299                              "magenta", "cyan", "white" };
1300 typedef struct {
1301     int attr, bg, fg;
1302 } TextColors;
1303 TextColors textColors[(int)NColorClasses];
1304
1305 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1306 static int
1307 parse_color(str, which)
1308      char *str;
1309      int which;
1310 {
1311     char *p, buf[100], *d;
1312     int i;
1313
1314     if (strlen(str) > 99)       /* watch bounds on buf */
1315       return -1;
1316
1317     p = str;
1318     d = buf;
1319     for (i=0; i<which; ++i) {
1320         p = strchr(p, ',');
1321         if (!p)
1322           return -1;
1323         ++p;
1324     }
1325
1326     /* Could be looking at something like:
1327        black, , 1
1328        .. in which case we want to stop on a comma also */
1329     while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1330       ++p;
1331
1332     if (*p == ',') {
1333         return -1;              /* Use default for empty field */
1334     }
1335
1336     if (which == 2 || isdigit(*p))
1337       return atoi(p);
1338
1339     while (*p && isalpha(*p))
1340       *(d++) = *(p++);
1341
1342     *d = 0;
1343
1344     for (i=0; i<8; ++i) {
1345         if (!StrCaseCmp(buf, cnames[i]))
1346           return which? (i+40) : (i+30);
1347     }
1348     if (!StrCaseCmp(buf, "default")) return -1;
1349
1350     fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1351     return -2;
1352 }
1353
1354 static int
1355 parse_cpair(cc, str)
1356      ColorClass cc;
1357      char *str;
1358 {
1359     if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1360         fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1361                 programName, str);
1362         return -1;
1363     }
1364
1365     /* bg and attr are optional */
1366     textColors[(int)cc].bg = parse_color(str, 1);
1367     if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1368         textColors[(int)cc].attr = 0;
1369     }
1370     return 0;
1371 }
1372
1373
1374 /* Arrange to catch delete-window events */
1375 Atom wm_delete_window;
1376 void
1377 CatchDeleteWindow(Widget w, String procname)
1378 {
1379   char buf[MSG_SIZ];
1380   XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1381   snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1382   XtAugmentTranslations(w, XtParseTranslationTable(buf));
1383 }
1384
1385 void
1386 BoardToTop()
1387 {
1388   Arg args[16];
1389   XtSetArg(args[0], XtNiconic, False);
1390   XtSetValues(shellWidget, args, 1);
1391
1392   XtPopup(shellWidget, XtGrabNone); /* Raise if lowered  */
1393 }
1394
1395 //---------------------------------------------------------------------------------------------------------
1396 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1397 #define XBOARD True
1398 #define JAWS_ARGS
1399 #define CW_USEDEFAULT (1<<31)
1400 #define ICS_TEXT_MENU_SIZE 90
1401 #define DEBUG_FILE "xboard.debug"
1402 #define SetCurrentDirectory chdir
1403 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1404 #define OPTCHAR "-"
1405 #define SEPCHAR " "
1406
1407 // these two must some day move to frontend.h, when they are implemented
1408 Boolean GameListIsUp();
1409
1410 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1411 #include "args.h"
1412
1413 // front-end part of option handling
1414
1415 // [HGM] This platform-dependent table provides the location for storing the color info
1416 extern char *crWhite, * crBlack;
1417
1418 void *
1419 colorVariable[] = {
1420   &appData.whitePieceColor,
1421   &appData.blackPieceColor,
1422   &appData.lightSquareColor,
1423   &appData.darkSquareColor,
1424   &appData.highlightSquareColor,
1425   &appData.premoveHighlightColor,
1426   &appData.lowTimeWarningColor,
1427   NULL,
1428   NULL,
1429   NULL,
1430   NULL,
1431   NULL,
1432   &crWhite,
1433   &crBlack,
1434   NULL
1435 };
1436
1437 // [HGM] font: keep a font for each square size, even non-stndard ones
1438 #define NUM_SIZES 18
1439 #define MAX_SIZE 130
1440 Boolean fontIsSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1441 char *fontTable[NUM_FONTS][MAX_SIZE];
1442
1443 void
1444 ParseFont(char *name, int number)
1445 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1446   int size;
1447   if(sscanf(name, "size%d:", &size)) {
1448     // [HGM] font: font is meant for specific boardSize (likely from settings file);
1449     //       defer processing it until we know if it matches our board size
1450     if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1451         fontTable[number][size] = strdup(strchr(name, ':')+1);
1452         fontValid[number][size] = True;
1453     }
1454     return;
1455   }
1456   switch(number) {
1457     case 0: // CLOCK_FONT
1458         appData.clockFont = strdup(name);
1459       break;
1460     case 1: // MESSAGE_FONT
1461         appData.font = strdup(name);
1462       break;
1463     case 2: // COORD_FONT
1464         appData.coordFont = strdup(name);
1465       break;
1466     default:
1467       return;
1468   }
1469   fontIsSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1470 }
1471
1472 void
1473 SetFontDefaults()
1474 { // only 2 fonts currently
1475   appData.clockFont = CLOCK_FONT_NAME;
1476   appData.coordFont = COORD_FONT_NAME;
1477   appData.font  =   DEFAULT_FONT_NAME;
1478 }
1479
1480 void
1481 CreateFonts()
1482 { // no-op, until we identify the code for this already in XBoard and move it here
1483 }
1484
1485 void
1486 ParseColor(int n, char *name)
1487 { // in XBoard, just copy the color-name string
1488   if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1489 }
1490
1491 void
1492 ParseTextAttribs(ColorClass cc, char *s)
1493 {
1494     (&appData.colorShout)[cc] = strdup(s);
1495 }
1496
1497 void
1498 ParseBoardSize(void *addr, char *name)
1499 {
1500     appData.boardSize = strdup(name);
1501 }
1502
1503 void
1504 LoadAllSounds()
1505 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1506 }
1507
1508 void
1509 SetCommPortDefaults()
1510 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1511 }
1512
1513 // [HGM] args: these three cases taken out to stay in front-end
1514 void
1515 SaveFontArg(FILE *f, ArgDescriptor *ad)
1516 {
1517   char *name;
1518   int i, n = (int)(intptr_t)ad->argLoc;
1519   switch(n) {
1520     case 0: // CLOCK_FONT
1521         name = appData.clockFont;
1522       break;
1523     case 1: // MESSAGE_FONT
1524         name = appData.font;
1525       break;
1526     case 2: // COORD_FONT
1527         name = appData.coordFont;
1528       break;
1529     default:
1530       return;
1531   }
1532   for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1533     if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1534         fontTable[n][squareSize] = strdup(name);
1535         fontValid[n][squareSize] = True;
1536         break;
1537   }
1538   for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1539     fprintf(f, OPTCHAR "%s" SEPCHAR "\"size%d:%s\"\n", ad->argName, i, fontTable[n][i]);
1540 }
1541
1542 void
1543 ExportSounds()
1544 { // nothing to do, as the sounds are at all times represented by their text-string names already
1545 }
1546
1547 void
1548 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1549 {       // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1550         fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
1551 }
1552
1553 void
1554 SaveColor(FILE *f, ArgDescriptor *ad)
1555 {       // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1556         if(colorVariable[(int)(intptr_t)ad->argLoc])
1557         fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
1558 }
1559
1560 void
1561 SaveBoardSize(FILE *f, char *name, void *addr)
1562 { // wrapper to shield back-end from BoardSize & sizeInfo
1563   fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1564 }
1565
1566 void
1567 ParseCommPortSettings(char *s)
1568 { // no such option in XBoard (yet)
1569 }
1570
1571 extern Widget engineOutputShell;
1572
1573 void
1574 GetActualPlacement(Widget wg, WindowPlacement *wp)
1575 {
1576   Arg args[16];
1577   Dimension w, h;
1578   Position x, y;
1579   int i;
1580
1581   if(!wg) return;
1582
1583     i = 0;
1584     XtSetArg(args[i], XtNx, &x); i++;
1585     XtSetArg(args[i], XtNy, &y); i++;
1586     XtSetArg(args[i], XtNwidth, &w); i++;
1587     XtSetArg(args[i], XtNheight, &h); i++;
1588     XtGetValues(wg, args, i);
1589     wp->x = x - 4;
1590     wp->y = y - 23;
1591     wp->height = h;
1592     wp->width = w;
1593 }
1594
1595 void
1596 GetWindowCoords()
1597 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1598   // In XBoard this will have to wait until awareness of window parameters is implemented
1599   GetActualPlacement(shellWidget, &wpMain);
1600   if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput);
1601   if(MoveHistoryIsUp()) GetActualPlacement(shells[7], &wpMoveHistory);
1602   if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1603   if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1604   if(shellUp[1]) GetActualPlacement(shells[1], &wpComment);
1605   if(shellUp[2]) GetActualPlacement(shells[2], &wpTags);
1606 }
1607
1608 void
1609 PrintCommPortSettings(FILE *f, char *name)
1610 { // This option does not exist in XBoard
1611 }
1612
1613 int
1614 MySearchPath(char *installDir, char *name, char *fullname)
1615 { // just append installDir and name. Perhaps ExpandPath should be used here?
1616   name = ExpandPathName(name);
1617   if(name && name[0] == '/')
1618     safeStrCpy(fullname, name, MSG_SIZ );
1619   else {
1620     sprintf(fullname, "%s%c%s", installDir, '/', name);
1621   }
1622   return 1;
1623 }
1624
1625 int
1626 MyGetFullPathName(char *name, char *fullname)
1627 { // should use ExpandPath?
1628   name = ExpandPathName(name);
1629   safeStrCpy(fullname, name, MSG_SIZ );
1630   return 1;
1631 }
1632
1633 void
1634 EnsureOnScreen(int *x, int *y, int minX, int minY)
1635 {
1636   return;
1637 }
1638
1639 int
1640 MainWindowUp()
1641 { // [HGM] args: allows testing if main window is realized from back-end
1642   return xBoardWindow != 0;
1643 }
1644
1645 void
1646 PopUpStartupDialog()
1647 {  // start menu not implemented in XBoard
1648 }
1649
1650 char *
1651 ConvertToLine(int argc, char **argv)
1652 {
1653   static char line[128*1024], buf[1024];
1654   int i;
1655
1656   line[0] = NULLCHAR;
1657   for(i=1; i<argc; i++)
1658     {
1659       if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') || argv[i][0] == NULLCHAR)
1660           && argv[i][0] != '{' )
1661         snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1662       else
1663         snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1664       strncat(line, buf, 128*1024 - strlen(line) - 1 );
1665     }
1666
1667   line[strlen(line)-1] = NULLCHAR;
1668   return line;
1669 }
1670
1671 //--------------------------------------------------------------------------------------------
1672
1673 extern Boolean twoBoards, partnerUp;
1674
1675 #ifdef IDSIZES
1676   // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1677 #else
1678 #define BoardSize int
1679 void InitDrawingSizes(BoardSize boardSize, int flags)
1680 {   // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1681     Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1682     Arg args[16];
1683     XtGeometryResult gres;
1684     int i;
1685     static Dimension oldWidth, oldHeight;
1686     static VariantClass oldVariant;
1687     static int oldDual = -1;
1688
1689     if(!formWidget) return;
1690
1691     if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1692     boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1693     boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1694
1695   if(boardWidth != oldWidth || boardHeight != oldHeight || oldDual != twoBoards) { // do resizing stuff only if size actually changed
1696     /*
1697      * Enable shell resizing.
1698      */
1699     shellArgs[0].value = (XtArgVal) &w;
1700     shellArgs[1].value = (XtArgVal) &h;
1701     XtGetValues(shellWidget, shellArgs, 2);
1702
1703     shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1704     shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1705     XtSetValues(shellWidget, &shellArgs[2], 4);
1706
1707     XtSetArg(args[0], XtNdefaultDistance, &sep);
1708     XtGetValues(formWidget, args, 1);
1709
1710     oldWidth = boardWidth; oldHeight = boardHeight; oldDual = twoBoards;
1711     CreateGrid();
1712     hOffset = boardWidth + 10;
1713     for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1714         secondSegments[i] = gridSegments[i];
1715         secondSegments[i].x1 += hOffset;
1716         secondSegments[i].x2 += hOffset;
1717     }
1718
1719     XtSetArg(args[0], XtNwidth, boardWidth);
1720     XtSetArg(args[1], XtNheight, boardHeight);
1721     XtSetValues(boardWidget, args, 2);
1722
1723     timerWidth = (boardWidth - sep) / 2;
1724     XtSetArg(args[0], XtNwidth, timerWidth);
1725     XtSetValues(whiteTimerWidget, args, 1);
1726     XtSetValues(blackTimerWidget, args, 1);
1727
1728     XawFormDoLayout(formWidget, False);
1729
1730     if (appData.titleInWindow) {
1731         i = 0;
1732         XtSetArg(args[i], XtNborderWidth, &bor); i++;
1733         XtSetArg(args[i], XtNheight, &h);  i++;
1734         XtGetValues(titleWidget, args, i);
1735         if (smallLayout) {
1736             w = boardWidth - 2*bor;
1737         } else {
1738             XtSetArg(args[0], XtNwidth, &w);
1739             XtGetValues(menuBarWidget, args, 1);
1740             w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1741         }
1742
1743         gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1744         if (gres != XtGeometryYes && appData.debugMode) {
1745             fprintf(stderr,
1746                     _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1747                     programName, gres, w, h, wr, hr);
1748         }
1749     }
1750
1751     XawFormDoLayout(formWidget, True);
1752
1753     /*
1754      * Inhibit shell resizing.
1755      */
1756     shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1757     shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1758     shellArgs[4].value = shellArgs[2].value = w;
1759     shellArgs[5].value = shellArgs[3].value = h;
1760     XtSetValues(shellWidget, &shellArgs[0], 6);
1761   }
1762
1763     // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1764     // (only for xpm)
1765
1766     if(gameInfo.variant == oldVariant) return; // and only if variant changed
1767
1768     if(useImages) {
1769       for(i=0; i<4; i++) {
1770         int p;
1771         for(p=0; p<=(int)WhiteKing; p++)
1772            xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1773         if(gameInfo.variant == VariantShogi) {
1774            xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1775            xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1776            xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1777            xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1778            xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1779         }
1780 #ifdef GOTHIC
1781         if(gameInfo.variant == VariantGothic) {
1782            xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1783         }
1784 #endif
1785         if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1786            xpmPieceBitmap[i][(int)WhiteAngel]    = xpmPieceBitmap2[i][(int)WhiteFalcon];
1787            xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1788         }
1789 #if !HAVE_LIBXPM
1790         // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1791         for(p=0; p<=(int)WhiteKing; p++)
1792            ximMaskPm[p] = ximMaskPm2[p]; // defaults
1793         if(gameInfo.variant == VariantShogi) {
1794            ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1795            ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1796            ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1797            ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1798            ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1799         }
1800 #ifdef GOTHIC
1801         if(gameInfo.variant == VariantGothic) {
1802            ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1803         }
1804 #endif
1805         if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1806            ximMaskPm[(int)WhiteAngel]    = ximMaskPm2[(int)WhiteFalcon];
1807            ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1808         }
1809 #endif
1810       }
1811     } else {
1812       for(i=0; i<2; i++) {
1813         int p;
1814         for(p=0; p<=(int)WhiteKing; p++)
1815            pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1816         if(gameInfo.variant == VariantShogi) {
1817            pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1818            pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1819            pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1820            pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1821            pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1822         }
1823 #ifdef GOTHIC
1824         if(gameInfo.variant == VariantGothic) {
1825            pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1826         }
1827 #endif
1828         if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1829            pieceBitmap[i][(int)WhiteAngel]    = pieceBitmap2[i][(int)WhiteFalcon];
1830            pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1831         }
1832       }
1833     }
1834 #if HAVE_LIBXPM
1835     CreateAnimVars();
1836 #endif
1837 }
1838 #endif
1839
1840 void ParseIcsTextColors()
1841 {   // [HGM] tken out of main(), so it can be called from ICS-Options dialog
1842     if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1843         parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1844         parse_cpair(ColorChannel1, appData.colorChannel1) < 0  ||
1845         parse_cpair(ColorChannel, appData.colorChannel) < 0  ||
1846         parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1847         parse_cpair(ColorTell, appData.colorTell) < 0 ||
1848         parse_cpair(ColorChallenge, appData.colorChallenge) < 0  ||
1849         parse_cpair(ColorRequest, appData.colorRequest) < 0  ||
1850         parse_cpair(ColorSeek, appData.colorSeek) < 0  ||
1851         parse_cpair(ColorNormal, appData.colorNormal) < 0)
1852       {
1853           if (appData.colorize) {
1854               fprintf(stderr,
1855                       _("%s: can't parse color names; disabling colorization\n"),
1856                       programName);
1857           }
1858           appData.colorize = FALSE;
1859       }
1860 }
1861
1862 int MakeColors()
1863 {   // [HGM] taken out of main(), so it can be called from BoardOptions dialog
1864     XrmValue vFrom, vTo;
1865     int forceMono = False;
1866
1867     if (!appData.monoMode) {
1868         vFrom.addr = (caddr_t) appData.lightSquareColor;
1869         vFrom.size = strlen(appData.lightSquareColor);
1870         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1871         if (vTo.addr == NULL) {
1872           appData.monoMode = True;
1873           forceMono = True;
1874         } else {
1875           lightSquareColor = *(Pixel *) vTo.addr;
1876         }
1877     }
1878     if (!appData.monoMode) {
1879         vFrom.addr = (caddr_t) appData.darkSquareColor;
1880         vFrom.size = strlen(appData.darkSquareColor);
1881         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1882         if (vTo.addr == NULL) {
1883           appData.monoMode = True;
1884           forceMono = True;
1885         } else {
1886           darkSquareColor = *(Pixel *) vTo.addr;
1887         }
1888     }
1889     if (!appData.monoMode) {
1890         vFrom.addr = (caddr_t) appData.whitePieceColor;
1891         vFrom.size = strlen(appData.whitePieceColor);
1892         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1893         if (vTo.addr == NULL) {
1894           appData.monoMode = True;
1895           forceMono = True;
1896         } else {
1897           whitePieceColor = *(Pixel *) vTo.addr;
1898         }
1899     }
1900     if (!appData.monoMode) {
1901         vFrom.addr = (caddr_t) appData.blackPieceColor;
1902         vFrom.size = strlen(appData.blackPieceColor);
1903         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1904         if (vTo.addr == NULL) {
1905           appData.monoMode = True;
1906           forceMono = True;
1907         } else {
1908           blackPieceColor = *(Pixel *) vTo.addr;
1909         }
1910     }
1911
1912     if (!appData.monoMode) {
1913         vFrom.addr = (caddr_t) appData.highlightSquareColor;
1914         vFrom.size = strlen(appData.highlightSquareColor);
1915         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1916         if (vTo.addr == NULL) {
1917           appData.monoMode = True;
1918           forceMono = True;
1919         } else {
1920           highlightSquareColor = *(Pixel *) vTo.addr;
1921         }
1922     }
1923
1924     if (!appData.monoMode) {
1925         vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1926         vFrom.size = strlen(appData.premoveHighlightColor);
1927         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1928         if (vTo.addr == NULL) {
1929           appData.monoMode = True;
1930           forceMono = True;
1931         } else {
1932           premoveHighlightColor = *(Pixel *) vTo.addr;
1933         }
1934     }
1935     return forceMono;
1936 }
1937
1938 void
1939 CreateAnyPieces()
1940 {   // [HGM] taken out of main
1941 #if HAVE_LIBXPM
1942     if (appData.monoMode && // [HGM] no sense to go on to certain doom
1943        (appData.bitmapDirectory == NULL || appData.bitmapDirectory[0] == NULLCHAR))
1944             appData.bitmapDirectory = DEF_BITMAP_DIR;
1945
1946     if (appData.bitmapDirectory[0] != NULLCHAR) {
1947       CreatePieces();
1948     } else {
1949       CreateXPMPieces();
1950       CreateXPMBoard(appData.liteBackTextureFile, 1);
1951       CreateXPMBoard(appData.darkBackTextureFile, 0);
1952     }
1953 #else
1954     CreateXIMPieces();
1955     /* Create regular pieces */
1956     if (!useImages) CreatePieces();
1957 #endif
1958 }
1959
1960 int
1961 main(argc, argv)
1962      int argc;
1963      char **argv;
1964 {
1965     int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1966     XSetWindowAttributes window_attributes;
1967     Arg args[16];
1968     Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1969     XrmValue vFrom, vTo;
1970     XtGeometryResult gres;
1971     char *p;
1972     XrmDatabase xdb;
1973     int forceMono = False;
1974
1975     srandom(time(0)); // [HGM] book: make random truly random
1976
1977     setbuf(stdout, NULL);
1978     setbuf(stderr, NULL);
1979     debugFP = stderr;
1980
1981     if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1982         printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1983         exit(0);
1984     }
1985
1986     programName = strrchr(argv[0], '/');
1987     if (programName == NULL)
1988       programName = argv[0];
1989     else
1990       programName++;
1991
1992 #ifdef ENABLE_NLS
1993     XtSetLanguageProc(NULL, NULL, NULL);
1994     bindtextdomain(PACKAGE, LOCALEDIR);
1995     textdomain(PACKAGE);
1996 #endif
1997
1998     shellWidget =
1999       XtAppInitialize(&appContext, "XBoard", shellOptions,
2000                       XtNumber(shellOptions),
2001                       &argc, argv, xboardResources, NULL, 0);
2002     appData.boardSize = "";
2003     InitAppData(ConvertToLine(argc, argv));
2004     p = getenv("HOME");
2005     if (p == NULL) p = "/tmp";
2006     i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
2007     gameCopyFilename = (char*) malloc(i);
2008     gamePasteFilename = (char*) malloc(i);
2009     snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
2010     snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
2011
2012     XtGetApplicationResources(shellWidget, (XtPointer) &appData,
2013                               clientResources, XtNumber(clientResources),
2014                               NULL, 0);
2015
2016     { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
2017         static char buf[MSG_SIZ];
2018         EscapeExpand(buf, appData.firstInitString);
2019         appData.firstInitString = strdup(buf);
2020         EscapeExpand(buf, appData.secondInitString);
2021         appData.secondInitString = strdup(buf);
2022         EscapeExpand(buf, appData.firstComputerString);
2023         appData.firstComputerString = strdup(buf);
2024         EscapeExpand(buf, appData.secondComputerString);
2025         appData.secondComputerString = strdup(buf);
2026     }
2027
2028     if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
2029         chessDir = ".";
2030     } else {
2031         if (chdir(chessDir) != 0) {
2032             fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
2033             perror(chessDir);
2034             exit(1);
2035         }
2036     }
2037
2038     if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
2039         /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
2040         if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL)  {
2041            printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
2042            exit(errno);
2043         }
2044         setbuf(debugFP, NULL);
2045     }
2046
2047 #if ENABLE_NLS
2048     if (appData.debugMode) {
2049       fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
2050     }
2051 #endif
2052
2053     /* [HGM,HR] make sure board size is acceptable */
2054     if(appData.NrFiles > BOARD_FILES ||
2055        appData.NrRanks > BOARD_RANKS   )
2056          DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
2057
2058 #if !HIGHDRAG
2059     /* This feature does not work; animation needs a rewrite */
2060     appData.highlightDragging = FALSE;
2061 #endif
2062     InitBackEnd1();
2063
2064     xDisplay = XtDisplay(shellWidget);
2065     xScreen = DefaultScreen(xDisplay);
2066     wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
2067
2068         gameInfo.variant = StringToVariant(appData.variant);
2069         InitPosition(FALSE);
2070
2071 #ifdef IDSIZE
2072     InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
2073 #else
2074     if (isdigit(appData.boardSize[0])) {
2075         i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
2076                    &lineGap, &clockFontPxlSize, &coordFontPxlSize,
2077                    &fontPxlSize, &smallLayout, &tinyLayout);
2078         if (i == 0) {
2079             fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
2080                     programName, appData.boardSize);
2081             exit(2);
2082         }
2083         if (i < 7) {
2084             /* Find some defaults; use the nearest known size */
2085             SizeDefaults *szd, *nearest;
2086             int distance = 99999;
2087             nearest = szd = sizeDefaults;
2088             while (szd->name != NULL) {
2089                 if (abs(szd->squareSize - squareSize) < distance) {
2090                     nearest = szd;
2091                     distance = abs(szd->squareSize - squareSize);
2092                     if (distance == 0) break;
2093                 }
2094                 szd++;
2095             }
2096             if (i < 2) lineGap = nearest->lineGap;
2097             if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
2098             if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
2099             if (i < 5) fontPxlSize = nearest->fontPxlSize;
2100             if (i < 6) smallLayout = nearest->smallLayout;
2101             if (i < 7) tinyLayout = nearest->tinyLayout;
2102         }
2103     } else {
2104         SizeDefaults *szd = sizeDefaults;
2105         if (*appData.boardSize == NULLCHAR) {
2106             while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
2107                    DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
2108               szd++;
2109             }
2110             if (szd->name == NULL) szd--;
2111             appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
2112         } else {
2113             while (szd->name != NULL &&
2114                    StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
2115             if (szd->name == NULL) {
2116                 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
2117                         programName, appData.boardSize);
2118                 exit(2);
2119             }
2120         }
2121         squareSize = szd->squareSize;
2122         lineGap = szd->lineGap;
2123         clockFontPxlSize = szd->clockFontPxlSize;
2124         coordFontPxlSize = szd->coordFontPxlSize;
2125         fontPxlSize = szd->fontPxlSize;
2126         smallLayout = szd->smallLayout;
2127         tinyLayout = szd->tinyLayout;
2128         // [HGM] font: use defaults from settings file if available and not overruled
2129     }
2130     if(!fontIsSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
2131         appData.clockFont = fontTable[CLOCK_FONT][squareSize];
2132     if(!fontIsSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
2133         appData.font = fontTable[MESSAGE_FONT][squareSize];
2134     if(!fontIsSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
2135         appData.coordFont = fontTable[COORD_FONT][squareSize];
2136
2137     /* Now, using squareSize as a hint, find a good XPM/XIM set size */
2138     if (strlen(appData.pixmapDirectory) > 0) {
2139         p = ExpandPathName(appData.pixmapDirectory);
2140         if (!p) {
2141             fprintf(stderr, _("Error expanding path name \"%s\"\n"),
2142                    appData.pixmapDirectory);
2143             exit(1);
2144         }
2145         if (appData.debugMode) {
2146           fprintf(stderr, _("\
2147 XBoard square size (hint): %d\n\
2148 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
2149         }
2150         squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
2151         if (appData.debugMode) {
2152             fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
2153         }
2154     }
2155     defaultLineGap = lineGap;
2156     if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
2157
2158     /* [HR] height treated separately (hacked) */
2159     boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
2160     boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
2161     if (appData.showJail == 1) {
2162         /* Jail on top and bottom */
2163         XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2164         XtSetArg(boardArgs[2], XtNheight,
2165                  boardHeight + 2*(lineGap + squareSize));
2166     } else if (appData.showJail == 2) {
2167         /* Jail on sides */
2168         XtSetArg(boardArgs[1], XtNwidth,
2169                  boardWidth + 2*(lineGap + squareSize));
2170         XtSetArg(boardArgs[2], XtNheight, boardHeight);
2171     } else {
2172         /* No jail */
2173         XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2174         XtSetArg(boardArgs[2], XtNheight, boardHeight);
2175     }
2176
2177     /*
2178      * Determine what fonts to use.
2179      */
2180 #if ENABLE_NLS
2181     appData.font = InsertPxlSize(appData.font, fontPxlSize);
2182     appData.clockFont = InsertPxlSize(appData.clockFont, clockFontPxlSize);
2183     appData.coordFont = InsertPxlSize(appData.coordFont, coordFontPxlSize);
2184     fontSet = CreateFontSet(appData.font);
2185     clockFontSet = CreateFontSet(appData.clockFont);
2186     {
2187       /* For the coordFont, use the 0th font of the fontset. */
2188       XFontSet coordFontSet = CreateFontSet(appData.coordFont);
2189       XFontStruct **font_struct_list;
2190       char **font_name_list;
2191       XFontsOfFontSet(coordFontSet, &font_struct_list, &font_name_list);
2192       coordFontID = XLoadFont(xDisplay, font_name_list[0]);
2193       coordFontStruct = XQueryFont(xDisplay, coordFontID);
2194     }
2195 #else
2196     appData.font = FindFont(appData.font, fontPxlSize);
2197     appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2198     appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2199     clockFontID = XLoadFont(xDisplay, appData.clockFont);
2200     clockFontStruct = XQueryFont(xDisplay, clockFontID);
2201     coordFontID = XLoadFont(xDisplay, appData.coordFont);
2202     coordFontStruct = XQueryFont(xDisplay, coordFontID);
2203 #endif
2204     countFontID = coordFontID;  // [HGM] holdings
2205     countFontStruct = coordFontStruct;
2206
2207     xdb = XtDatabase(xDisplay);
2208 #if ENABLE_NLS
2209     XrmPutLineResource(&xdb, "*international: True");
2210     vTo.size = sizeof(XFontSet);
2211     vTo.addr = (XtPointer) &fontSet;
2212     XrmPutResource(&xdb, "*fontSet", XtRFontSet, &vTo);
2213 #else
2214     XrmPutStringResource(&xdb, "*font", appData.font);
2215 #endif
2216
2217     /*
2218      * Detect if there are not enough colors available and adapt.
2219      */
2220     if (DefaultDepth(xDisplay, xScreen) <= 2) {
2221       appData.monoMode = True;
2222     }
2223
2224     forceMono = MakeColors();
2225
2226     if (forceMono) {
2227       fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2228               programName);
2229         appData.monoMode = True;
2230     }
2231
2232     if (appData.lowTimeWarning && !appData.monoMode) {
2233       vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2234       vFrom.size = strlen(appData.lowTimeWarningColor);
2235       XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2236       if (vTo.addr == NULL)
2237                 appData.monoMode = True;
2238       else
2239                 lowTimeWarningColor = *(Pixel *) vTo.addr;
2240     }
2241
2242     if (appData.monoMode && appData.debugMode) {
2243         fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2244                 (unsigned long) XWhitePixel(xDisplay, xScreen),
2245                 (unsigned long) XBlackPixel(xDisplay, xScreen));
2246     }
2247
2248     ParseIcsTextColors();
2249     textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2250     textColors[ColorNone].attr = 0;
2251
2252     XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2253
2254     /*
2255      * widget hierarchy
2256      */
2257     if (tinyLayout) {
2258         layoutName = "tinyLayout";
2259     } else if (smallLayout) {
2260         layoutName = "smallLayout";
2261     } else {
2262         layoutName = "normalLayout";
2263     }
2264     /* Outer layoutWidget is there only to provide a name for use in
2265        resources that depend on the layout style */
2266     layoutWidget =
2267       XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2268                             layoutArgs, XtNumber(layoutArgs));
2269     formWidget =
2270       XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2271                             formArgs, XtNumber(formArgs));
2272     XtSetArg(args[0], XtNdefaultDistance, &sep);
2273     XtGetValues(formWidget, args, 1);
2274
2275     j = 0;
2276     widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2277     XtSetArg(args[0], XtNtop,    XtChainTop);
2278     XtSetArg(args[1], XtNbottom, XtChainTop);
2279     XtSetArg(args[2], XtNright,  XtChainLeft);
2280     XtSetValues(menuBarWidget, args, 3);
2281
2282     widgetList[j++] = whiteTimerWidget =
2283       XtCreateWidget("whiteTime", labelWidgetClass,
2284                      formWidget, timerArgs, XtNumber(timerArgs));
2285 #if ENABLE_NLS
2286     XtSetArg(args[0], XtNfontSet, clockFontSet);
2287 #else
2288     XtSetArg(args[0], XtNfont, clockFontStruct);
2289 #endif
2290     XtSetArg(args[1], XtNtop,    XtChainTop);
2291     XtSetArg(args[2], XtNbottom, XtChainTop);
2292     XtSetValues(whiteTimerWidget, args, 3);
2293
2294     widgetList[j++] = blackTimerWidget =
2295       XtCreateWidget("blackTime", labelWidgetClass,
2296                      formWidget, timerArgs, XtNumber(timerArgs));
2297 #if ENABLE_NLS
2298     XtSetArg(args[0], XtNfontSet, clockFontSet);
2299 #else
2300     XtSetArg(args[0], XtNfont, clockFontStruct);
2301 #endif
2302     XtSetArg(args[1], XtNtop,    XtChainTop);
2303     XtSetArg(args[2], XtNbottom, XtChainTop);
2304     XtSetValues(blackTimerWidget, args, 3);
2305
2306     if (appData.titleInWindow) {
2307         widgetList[j++] = titleWidget =
2308           XtCreateWidget("title", labelWidgetClass, formWidget,
2309                          titleArgs, XtNumber(titleArgs));
2310         XtSetArg(args[0], XtNtop,    XtChainTop);
2311         XtSetArg(args[1], XtNbottom, XtChainTop);
2312         XtSetValues(titleWidget, args, 2);
2313     }
2314
2315     if (appData.showButtonBar) {
2316       widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2317       XtSetArg(args[0], XtNleft,  XtChainRight); // [HGM] glue to right window edge
2318       XtSetArg(args[1], XtNright, XtChainRight); //       for good run-time sizing
2319       XtSetArg(args[2], XtNtop,    XtChainTop);
2320       XtSetArg(args[3], XtNbottom, XtChainTop);
2321       XtSetValues(buttonBarWidget, args, 4);
2322     }
2323
2324     widgetList[j++] = messageWidget =
2325       XtCreateWidget("message", labelWidgetClass, formWidget,
2326                      messageArgs, XtNumber(messageArgs));
2327     XtSetArg(args[0], XtNtop,    XtChainTop);
2328     XtSetArg(args[1], XtNbottom, XtChainTop);
2329     XtSetValues(messageWidget, args, 2);
2330
2331     widgetList[j++] = boardWidget =
2332       XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2333                      XtNumber(boardArgs));
2334
2335     XtManageChildren(widgetList, j);
2336
2337     timerWidth = (boardWidth - sep) / 2;
2338     XtSetArg(args[0], XtNwidth, timerWidth);
2339     XtSetValues(whiteTimerWidget, args, 1);
2340     XtSetValues(blackTimerWidget, args, 1);
2341
2342     XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2343     XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2344     XtGetValues(whiteTimerWidget, args, 2);
2345
2346     if (appData.showButtonBar) {
2347       XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2348       XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2349       XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2350     }
2351
2352     /*
2353      * formWidget uses these constraints but they are stored
2354      * in the children.
2355      */
2356     i = 0;
2357     XtSetArg(args[i], XtNfromHoriz, 0); i++;
2358     XtSetValues(menuBarWidget, args, i);
2359     if (appData.titleInWindow) {
2360         if (smallLayout) {
2361             i = 0;
2362             XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2363             XtSetValues(whiteTimerWidget, args, i);
2364             i = 0;
2365             XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2366             XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2367             XtSetValues(blackTimerWidget, args, i);
2368             i = 0;
2369             XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2370             XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2371             XtSetValues(titleWidget, args, i);
2372             i = 0;
2373             XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2374             XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2375             XtSetValues(messageWidget, args, i);
2376             if (appData.showButtonBar) {
2377               i = 0;
2378               XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2379               XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2380               XtSetValues(buttonBarWidget, args, i);
2381             }
2382         } else {
2383             i = 0;
2384             XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2385             XtSetValues(whiteTimerWidget, args, i);
2386             i = 0;
2387             XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2388             XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2389             XtSetValues(blackTimerWidget, args, i);
2390             i = 0;
2391             XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2392             XtSetValues(titleWidget, args, i);
2393             i = 0;
2394             XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2395             XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2396             XtSetValues(messageWidget, args, i);
2397             if (appData.showButtonBar) {
2398               i = 0;
2399               XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2400               XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2401               XtSetValues(buttonBarWidget, args, i);
2402             }
2403         }
2404     } else {
2405         i = 0;
2406         XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2407         XtSetValues(whiteTimerWidget, args, i);
2408         i = 0;
2409         XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2410         XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2411         XtSetValues(blackTimerWidget, args, i);
2412         i = 0;
2413         XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2414         XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2415         XtSetValues(messageWidget, args, i);
2416         if (appData.showButtonBar) {
2417           i = 0;
2418           XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2419           XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2420           XtSetValues(buttonBarWidget, args, i);
2421         }
2422     }
2423     i = 0;
2424     XtSetArg(args[0], XtNfromVert, messageWidget);
2425     XtSetArg(args[1], XtNtop,    XtChainTop);
2426     XtSetArg(args[2], XtNbottom, XtChainBottom);
2427     XtSetArg(args[3], XtNleft,   XtChainLeft);
2428     XtSetArg(args[4], XtNright,  XtChainRight);
2429     XtSetValues(boardWidget, args, 5);
2430
2431     XtRealizeWidget(shellWidget);
2432
2433     if(wpMain.x > 0) {
2434       XtSetArg(args[0], XtNx, wpMain.x);
2435       XtSetArg(args[1], XtNy, wpMain.y);
2436       XtSetValues(shellWidget, args, 2);
2437     }
2438
2439     /*
2440      * Correct the width of the message and title widgets.
2441      * It is not known why some systems need the extra fudge term.
2442      * The value "2" is probably larger than needed.
2443      */
2444     XawFormDoLayout(formWidget, False);
2445
2446 #define WIDTH_FUDGE 2
2447     i = 0;
2448     XtSetArg(args[i], XtNborderWidth, &bor);  i++;
2449     XtSetArg(args[i], XtNheight, &h);  i++;
2450     XtGetValues(messageWidget, args, i);
2451     if (appData.showButtonBar) {
2452       i = 0;
2453       XtSetArg(args[i], XtNwidth, &w);  i++;
2454       XtGetValues(buttonBarWidget, args, i);
2455       w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2456     } else {
2457       w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2458     }
2459
2460     gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2461     if (gres != XtGeometryYes && appData.debugMode) {
2462       fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2463               programName, gres, w, h, wr, hr);
2464     }
2465
2466     /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2467     /* The size used for the child widget in layout lags one resize behind
2468        its true size, so we resize a second time, 1 pixel smaller.  Yeech! */
2469     w--;
2470     gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2471     if (gres != XtGeometryYes && appData.debugMode) {
2472       fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2473               programName, gres, w, h, wr, hr);
2474     }
2475     /* !! end hack */
2476     XtSetArg(args[0], XtNleft,  XtChainLeft);  // [HGM] glue ends for good run-time sizing
2477     XtSetArg(args[1], XtNright, XtChainRight);
2478     XtSetValues(messageWidget, args, 2);
2479
2480     if (appData.titleInWindow) {
2481         i = 0;
2482         XtSetArg(args[i], XtNborderWidth, &bor); i++;
2483         XtSetArg(args[i], XtNheight, &h);  i++;
2484         XtGetValues(titleWidget, args, i);
2485         if (smallLayout) {
2486             w = boardWidth - 2*bor;
2487         } else {
2488             XtSetArg(args[0], XtNwidth, &w);
2489             XtGetValues(menuBarWidget, args, 1);
2490             w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2491         }
2492
2493         gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2494         if (gres != XtGeometryYes && appData.debugMode) {
2495             fprintf(stderr,
2496                     _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2497                     programName, gres, w, h, wr, hr);
2498         }
2499     }
2500     XawFormDoLayout(formWidget, True);
2501
2502     xBoardWindow = XtWindow(boardWidget);
2503
2504     // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2505     //       not need to go into InitDrawingSizes().
2506 #endif
2507
2508     /*
2509      * Create X checkmark bitmap and initialize option menu checks.
2510      */
2511     ReadBitmap(&xMarkPixmap, "checkmark.bm",
2512                checkmark_bits, checkmark_width, checkmark_height);
2513     XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2514 #ifndef OPTIONSDIALOG
2515     if (appData.alwaysPromoteToQueen) {
2516         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2517                     args, 1);
2518     }
2519     if (appData.animateDragging) {
2520         XtSetValues(XtNameToWidget(menuBarWidget,
2521                                    "menuOptions.Animate Dragging"),
2522                     args, 1);
2523     }
2524     if (appData.animate) {
2525         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2526                     args, 1);
2527     }
2528     if (appData.autoCallFlag) {
2529         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2530                     args, 1);
2531     }
2532     if (appData.autoFlipView) {
2533         XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2534                     args, 1);
2535     }
2536     if (appData.blindfold) {
2537         XtSetValues(XtNameToWidget(menuBarWidget,
2538                                    "menuOptions.Blindfold"), args, 1);
2539     }
2540     if (appData.flashCount > 0) {
2541         XtSetValues(XtNameToWidget(menuBarWidget,
2542                                    "menuOptions.Flash Moves"),
2543                     args, 1);
2544     }
2545 #if HIGHDRAG
2546     if (appData.highlightDragging) {
2547         XtSetValues(XtNameToWidget(menuBarWidget,
2548                                    "menuOptions.Highlight Dragging"),
2549                     args, 1);
2550     }
2551 #endif
2552     if (appData.highlightLastMove) {
2553         XtSetValues(XtNameToWidget(menuBarWidget,
2554                                    "menuOptions.Highlight Last Move"),
2555                     args, 1);
2556     }
2557     if (appData.highlightMoveWithArrow) {
2558         XtSetValues(XtNameToWidget(menuBarWidget,
2559                                    "menuOptions.Arrow"),
2560                     args, 1);
2561     }
2562 //    if (appData.icsAlarm) {
2563 //      XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2564 //                  args, 1);
2565 //    }
2566     if (appData.ringBellAfterMoves) {
2567         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2568                     args, 1);
2569     }
2570     if (appData.oneClick) {
2571         XtSetValues(XtNameToWidget(menuBarWidget,
2572                                    "menuOptions.OneClick"), args, 1);
2573     }
2574     if (appData.periodicUpdates) {
2575         XtSetValues(XtNameToWidget(menuBarWidget,
2576                                    "menuOptions.Periodic Updates"), args, 1);
2577     }
2578     if (appData.ponderNextMove) {
2579         XtSetValues(XtNameToWidget(menuBarWidget,
2580                                    "menuOptions.Ponder Next Move"), args, 1);
2581     }
2582     if (appData.popupExitMessage) {
2583         XtSetValues(XtNameToWidget(menuBarWidget,
2584                                    "menuOptions.Popup Exit Message"), args, 1);
2585     }
2586     if (appData.popupMoveErrors) {
2587         XtSetValues(XtNameToWidget(menuBarWidget,
2588                                    "menuOptions.Popup Move Errors"), args, 1);
2589     }
2590 //    if (appData.premove) {
2591 //      XtSetValues(XtNameToWidget(menuBarWidget,
2592 //                                 "menuOptions.Premove"), args, 1);
2593 //    }
2594     if (appData.showCoords) {
2595         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2596                     args, 1);
2597     }
2598     if (appData.hideThinkingFromHuman) {
2599         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2600                     args, 1);
2601     }
2602     if (appData.testLegality) {
2603         XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2604                     args, 1);
2605     }
2606 #endif
2607     if (saveSettingsOnExit) {
2608         XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2609                     args, 1);
2610     }
2611
2612     /*
2613      * Create an icon.
2614      */
2615     ReadBitmap(&wIconPixmap, "icon_white.bm",
2616                icon_white_bits, icon_white_width, icon_white_height);
2617     ReadBitmap(&bIconPixmap, "icon_black.bm",
2618                icon_black_bits, icon_black_width, icon_black_height);
2619     iconPixmap = wIconPixmap;
2620     i = 0;
2621     XtSetArg(args[i], XtNiconPixmap, iconPixmap);  i++;
2622     XtSetValues(shellWidget, args, i);
2623
2624     /*
2625      * Create a cursor for the board widget.
2626      */
2627     window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2628     XChangeWindowAttributes(xDisplay, xBoardWindow,
2629                             CWCursor, &window_attributes);
2630
2631     /*
2632      * Inhibit shell resizing.
2633      */
2634     shellArgs[0].value = (XtArgVal) &w;
2635     shellArgs[1].value = (XtArgVal) &h;
2636     XtGetValues(shellWidget, shellArgs, 2);
2637     shellArgs[4].value = shellArgs[2].value = w;
2638     shellArgs[5].value = shellArgs[3].value = h;
2639     XtSetValues(shellWidget, &shellArgs[2], 4);
2640     marginW =  w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2641     marginH =  h - boardHeight;
2642
2643     CatchDeleteWindow(shellWidget, "QuitProc");
2644
2645     CreateGCs(False);
2646     CreateGrid();
2647     CreateAnyPieces();
2648
2649     CreatePieceMenus();
2650
2651     if (appData.animate || appData.animateDragging)
2652       CreateAnimVars();
2653
2654     XtAugmentTranslations(formWidget,
2655                           XtParseTranslationTable(globalTranslations));
2656     XtAugmentTranslations(boardWidget,
2657                           XtParseTranslationTable(boardTranslations));
2658     XtAugmentTranslations(whiteTimerWidget,
2659                           XtParseTranslationTable(whiteTranslations));
2660     XtAugmentTranslations(blackTimerWidget,
2661                           XtParseTranslationTable(blackTranslations));
2662
2663     /* Why is the following needed on some versions of X instead
2664      * of a translation? */
2665     XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2666                       (XtEventHandler) EventProc, NULL);
2667     /* end why */
2668     XtAddEventHandler(formWidget, KeyPressMask, False,
2669                       (XtEventHandler) MoveTypeInProc, NULL);
2670
2671     /* [AS] Restore layout */
2672     if( wpMoveHistory.visible ) {
2673       HistoryPopUp();
2674     }
2675
2676     if( wpEvalGraph.visible )
2677       {
2678         EvalGraphPopUp();
2679       };
2680
2681     if( wpEngineOutput.visible ) {
2682       EngineOutputPopUp();
2683     }
2684
2685     InitBackEnd2();
2686
2687     if (errorExitStatus == -1) {
2688         if (appData.icsActive) {
2689             /* We now wait until we see "login:" from the ICS before
2690                sending the logon script (problems with timestamp otherwise) */
2691             /*ICSInitScript();*/
2692             if (appData.icsInputBox) ICSInputBoxPopUp();
2693         }
2694
2695     #ifdef SIGWINCH
2696     signal(SIGWINCH, TermSizeSigHandler);
2697     #endif
2698         signal(SIGINT, IntSigHandler);
2699         signal(SIGTERM, IntSigHandler);
2700         if (*appData.cmailGameName != NULLCHAR) {
2701             signal(SIGUSR1, CmailSigHandler);
2702         }
2703     }
2704     gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2705     InitPosition(TRUE);
2706 //    XtSetKeyboardFocus(shellWidget, formWidget);
2707     XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
2708
2709     XtAppMainLoop(appContext);
2710     if (appData.debugMode) fclose(debugFP); // [DM] debug
2711     return 0;
2712 }
2713
2714 static Boolean noEcho;
2715
2716 void
2717 ShutDownFrontEnd()
2718 {
2719     if (appData.icsActive && oldICSInteractionTitle != NULL) {
2720         DisplayIcsInteractionTitle(oldICSInteractionTitle);
2721     }
2722     if (saveSettingsOnExit) SaveSettings(settingsFileName);
2723     unlink(gameCopyFilename);
2724     unlink(gamePasteFilename);
2725     if(noEcho) EchoOn();
2726 }
2727
2728 RETSIGTYPE TermSizeSigHandler(int sig)
2729 {
2730     update_ics_width();
2731 }
2732
2733 RETSIGTYPE
2734 IntSigHandler(sig)
2735      int sig;
2736 {
2737     ExitEvent(sig);
2738 }
2739
2740 RETSIGTYPE
2741 CmailSigHandler(sig)
2742      int sig;
2743 {
2744     int dummy = 0;
2745     int error;
2746
2747     signal(SIGUSR1, SIG_IGN);   /* suspend handler     */
2748
2749     /* Activate call-back function CmailSigHandlerCallBack()             */
2750     OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2751
2752     signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2753 }
2754
2755 void
2756 CmailSigHandlerCallBack(isr, closure, message, count, error)
2757      InputSourceRef isr;
2758      VOIDSTAR closure;
2759      char *message;
2760      int count;
2761      int error;
2762 {
2763     BoardToTop();
2764     ReloadCmailMsgEvent(TRUE);  /* Reload cmail msg  */
2765 }
2766 /**** end signal code ****/
2767
2768
2769 void
2770 ICSInitScript()
2771 {
2772   /* try to open the icsLogon script, either in the location given
2773    * or in the users HOME directory
2774    */
2775
2776   FILE *f;
2777   char buf[MSG_SIZ];
2778   char *homedir;
2779
2780   f = fopen(appData.icsLogon, "r");
2781   if (f == NULL)
2782     {
2783       homedir = getenv("HOME");
2784       if (homedir != NULL)
2785         {
2786           safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2787           strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2788           strncat(buf, appData.icsLogon,  MSG_SIZ - strlen(buf) - 1);
2789           f = fopen(buf, "r");
2790         }
2791     }
2792
2793   if (f != NULL)
2794     ProcessICSInitScript(f);
2795   else
2796     printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2797
2798   return;
2799 }
2800
2801 void
2802 ResetFrontEnd()
2803 {
2804     CommentPopDown();
2805     TagsPopDown();
2806     return;
2807 }
2808
2809 typedef struct {
2810     char *name;
2811     Boolean value;
2812 } Enables;
2813
2814 void
2815 GreyRevert(grey)
2816      Boolean grey;
2817 {
2818     Widget w;
2819     if (!menuBarWidget) return;
2820     w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2821     if (w == NULL) {
2822       DisplayError("menuEdit.Revert", 0);
2823     } else {
2824       XtSetSensitive(w, !grey);
2825     }
2826     w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2827     if (w == NULL) {
2828       DisplayError("menuEdit.Annotate", 0);
2829     } else {
2830       XtSetSensitive(w, !grey);
2831     }
2832 }
2833
2834 void
2835 SetMenuEnables(enab)
2836      Enables *enab;
2837 {
2838   Widget w;
2839   if (!menuBarWidget) return;
2840   while (enab->name != NULL) {
2841     w = XtNameToWidget(menuBarWidget, enab->name);
2842     if (w == NULL) {
2843       DisplayError(enab->name, 0);
2844     } else {
2845       XtSetSensitive(w, enab->value);
2846     }
2847     enab++;
2848   }
2849 }
2850
2851 Enables icsEnables[] = {
2852     { "menuFile.Mail Move", False },
2853     { "menuFile.Reload CMail Message", False },
2854     { "menuMode.Machine Black", False },
2855     { "menuMode.Machine White", False },
2856     { "menuMode.Analysis Mode", False },
2857     { "menuMode.Analyze File", False },
2858     { "menuMode.Two Machines", False },
2859     { "menuMode.Machine Match", False },
2860 #ifndef ZIPPY
2861     { "menuEngine.Hint", False },
2862     { "menuEngine.Book", False },
2863     { "menuEngine.Move Now", False },
2864 #ifndef OPTIONSDIALOG
2865     { "menuOptions.Periodic Updates", False },
2866     { "menuOptions.Hide Thinking", False },
2867     { "menuOptions.Ponder Next Move", False },
2868 #endif
2869 #endif
2870     { "menuEngine.Engine #1 Settings", False },
2871     { "menuEngine.Engine #2 Settings", False },
2872     { "menuEngine.Load Engine", False },
2873     { "menuEdit.Annotate", False },
2874     { "menuOptions.Match", False },
2875     { NULL, False }
2876 };
2877
2878 Enables ncpEnables[] = {
2879     { "menuFile.Mail Move", False },
2880     { "menuFile.Reload CMail Message", False },
2881     { "menuMode.Machine White", False },
2882     { "menuMode.Machine Black", False },
2883     { "menuMode.Analysis Mode", False },
2884     { "menuMode.Analyze File", False },
2885     { "menuMode.Two Machines", False },
2886     { "menuMode.Machine Match", False },
2887     { "menuMode.ICS Client", False },
2888     { "menuView.ICStex", False },
2889     { "menuView.ICS Input Box", False },
2890     { "Action", False },
2891     { "menuEdit.Revert", False },
2892     { "menuEdit.Annotate", False },
2893     { "menuEngine.Engine #1 Settings", False },
2894     { "menuEngine.Engine #2 Settings", False },
2895     { "menuEngine.Move Now", False },
2896     { "menuEngine.Retract Move", False },
2897     { "menuOptions.ICS", False },
2898 #ifndef OPTIONSDIALOG
2899     { "menuOptions.Auto Flag", False },
2900     { "menuOptions.Auto Flip View", False },
2901 //    { "menuOptions.ICS Alarm", False },
2902     { "menuOptions.Move Sound", False },
2903     { "menuOptions.Hide Thinking", False },
2904     { "menuOptions.Periodic Updates", False },
2905     { "menuOptions.Ponder Next Move", False },
2906 #endif
2907     { "menuEngine.Hint", False },
2908     { "menuEngine.Book", False },
2909     { NULL, False }
2910 };
2911
2912 Enables gnuEnables[] = {
2913     { "menuMode.ICS Client", False },
2914     { "menuView.ICStex", False },
2915     { "menuView.ICS Input Box", False },
2916     { "menuAction.Accept", False },
2917     { "menuAction.Decline", False },
2918     { "menuAction.Rematch", False },
2919     { "menuAction.Adjourn", False },
2920     { "menuAction.Stop Examining", False },
2921     { "menuAction.Stop Observing", False },
2922     { "menuAction.Upload to Examine", False },
2923     { "menuEdit.Revert", False },
2924     { "menuEdit.Annotate", False },
2925     { "menuOptions.ICS", False },
2926
2927     /* The next two options rely on SetCmailMode being called *after*    */
2928     /* SetGNUMode so that when GNU is being used to give hints these     */
2929     /* menu options are still available                                  */
2930
2931     { "menuFile.Mail Move", False },
2932     { "menuFile.Reload CMail Message", False },
2933     // [HGM] The following have been added to make a switch from ncp to GNU mode possible
2934     { "menuMode.Machine White", True },
2935     { "menuMode.Machine Black", True },
2936     { "menuMode.Analysis Mode", True },
2937     { "menuMode.Analyze File", True },
2938     { "menuMode.Two Machines", True },
2939     { "menuMode.Machine Match", True },
2940     { "menuEngine.Engine #1 Settings", True },
2941     { "menuEngine.Engine #2 Settings", True },
2942     { "menuEngine.Hint", True },
2943     { "menuEngine.Book", True },
2944     { "menuEngine.Move Now", True },
2945     { "menuEngine.Retract Move", True },
2946     { "Action", True },
2947     { NULL, False }
2948 };
2949
2950 Enables cmailEnables[] = {
2951     { "Action", True },
2952     { "menuAction.Call Flag", False },
2953     { "menuAction.Draw", True },
2954     { "menuAction.Adjourn", False },
2955     { "menuAction.Abort", False },
2956     { "menuAction.Stop Observing", False },
2957     { "menuAction.Stop Examining", False },
2958     { "menuFile.Mail Move", True },
2959     { "menuFile.Reload CMail Message", True },
2960     { NULL, False }
2961 };
2962
2963 Enables trainingOnEnables[] = {
2964   { "menuMode.Edit Comment", False },
2965   { "menuMode.Pause", False },
2966   { "menuEdit.Forward", False },
2967   { "menuEdit.Backward", False },
2968   { "menuEdit.Forward to End", False },
2969   { "menuEdit.Back to Start", False },
2970   { "menuEngine.Move Now", False },
2971   { "menuEdit.Truncate Game", False },
2972   { NULL, False }
2973 };
2974
2975 Enables trainingOffEnables[] = {
2976   { "menuMode.Edit Comment", True },
2977   { "menuMode.Pause", True },
2978   { "menuEdit.Forward", True },
2979   { "menuEdit.Backward", True },
2980   { "menuEdit.Forward to End", True },
2981   { "menuEdit.Back to Start", True },
2982   { "menuEngine.Move Now", True },
2983   { "menuEdit.Truncate Game", True },
2984   { NULL, False }
2985 };
2986
2987 Enables machineThinkingEnables[] = {
2988   { "menuFile.Load Game", False },
2989 //  { "menuFile.Load Next Game", False },
2990 //  { "menuFile.Load Previous Game", False },
2991 //  { "menuFile.Reload Same Game", False },
2992   { "menuEdit.Paste Game", False },
2993   { "menuFile.Load Position", False },
2994 //  { "menuFile.Load Next Position", False },
2995 //  { "menuFile.Load Previous Position", False },
2996 //  { "menuFile.Reload Same Position", False },
2997   { "menuEdit.Paste Position", False },
2998   { "menuMode.Machine White", False },
2999   { "menuMode.Machine Black", False },
3000   { "menuMode.Two Machines", False },
3001 //  { "menuMode.Machine Match", False },
3002   { "menuEngine.Retract Move", False },
3003   { NULL, False }
3004 };
3005
3006 Enables userThinkingEnables[] = {
3007   { "menuFile.Load Game", True },
3008 //  { "menuFile.Load Next Game", True },
3009 //  { "menuFile.Load Previous Game", True },
3010 //  { "menuFile.Reload Same Game", True },
3011   { "menuEdit.Paste Game", True },
3012   { "menuFile.Load Position", True },
3013 //  { "menuFile.Load Next Position", True },
3014 //  { "menuFile.Load Previous Position", True },
3015 //  { "menuFile.Reload Same Position", True },
3016   { "menuEdit.Paste Position", True },
3017   { "menuMode.Machine White", True },
3018   { "menuMode.Machine Black", True },
3019   { "menuMode.Two Machines", True },
3020 //  { "menuMode.Machine Match", True },
3021   { "menuEngine.Retract Move", True },
3022   { NULL, False }
3023 };
3024
3025 void SetICSMode()
3026 {
3027   SetMenuEnables(icsEnables);
3028
3029 #if ZIPPY
3030   if (appData.zippyPlay && !appData.noChessProgram) { /* [DM] icsEngineAnalyze */
3031      XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
3032      XtSetSensitive(XtNameToWidget(menuBarWidget, "menuEngine.Engine #1 Settings"), True);
3033   }
3034 #endif
3035 }
3036
3037 void
3038 SetNCPMode()
3039 {
3040   SetMenuEnables(ncpEnables);
3041 }
3042
3043 void
3044 SetGNUMode()
3045 {
3046   SetMenuEnables(gnuEnables);
3047 }
3048
3049 void
3050 SetCmailMode()
3051 {
3052   SetMenuEnables(cmailEnables);
3053 }
3054
3055 void
3056 SetTrainingModeOn()
3057 {
3058   SetMenuEnables(trainingOnEnables);
3059   if (appData.showButtonBar) {
3060     XtSetSensitive(buttonBarWidget, False);
3061   }
3062   CommentPopDown();
3063 }
3064
3065 void
3066 SetTrainingModeOff()
3067 {
3068   SetMenuEnables(trainingOffEnables);
3069   if (appData.showButtonBar) {
3070     XtSetSensitive(buttonBarWidget, True);
3071   }
3072 }
3073
3074 void
3075 SetUserThinkingEnables()
3076 {
3077   if (appData.noChessProgram) return;
3078   SetMenuEnables(userThinkingEnables);
3079 }
3080
3081 void
3082 SetMachineThinkingEnables()
3083 {
3084   if (appData.noChessProgram) return;
3085   SetMenuEnables(machineThinkingEnables);
3086   switch (gameMode) {
3087   case MachinePlaysBlack:
3088   case MachinePlaysWhite:
3089   case TwoMachinesPlay:
3090     XtSetSensitive(XtNameToWidget(menuBarWidget,
3091                                   ModeToWidgetName(gameMode)), True);
3092     break;
3093   default:
3094     break;
3095   }
3096 }
3097
3098 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
3099 #define HISTORY_SIZE 64
3100 static char *history[HISTORY_SIZE];
3101 int histIn = 0, histP = 0;
3102
3103 void
3104 SaveInHistory(char *cmd)
3105 {
3106   if (history[histIn] != NULL) {
3107     free(history[histIn]);
3108     history[histIn] = NULL;
3109   }
3110   if (*cmd == NULLCHAR) return;
3111   history[histIn] = StrSave(cmd);
3112   histIn = (histIn + 1) % HISTORY_SIZE;
3113   if (history[histIn] != NULL) {
3114     free(history[histIn]);
3115     history[histIn] = NULL;
3116   }
3117   histP = histIn;
3118 }
3119
3120 char *
3121 PrevInHistory(char *cmd)
3122 {
3123   int newhp;
3124   if (histP == histIn) {
3125     if (history[histIn] != NULL) free(history[histIn]);
3126     history[histIn] = StrSave(cmd);
3127   }
3128   newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
3129   if (newhp == histIn || history[newhp] == NULL) return NULL;
3130   histP = newhp;
3131   return history[histP];
3132 }
3133
3134 char *
3135 NextInHistory()
3136 {
3137   if (histP == histIn) return NULL;
3138   histP = (histP + 1) % HISTORY_SIZE;
3139   return history[histP];   
3140 }
3141 // end of borrowed code
3142
3143 #define Abs(n) ((n)<0 ? -(n) : (n))
3144
3145 #ifdef ENABLE_NLS
3146 char *
3147 InsertPxlSize(pattern, targetPxlSize)
3148      char *pattern;
3149      int targetPxlSize;
3150 {
3151     char *base_fnt_lst, strInt[12], *p, *q;
3152     int alternatives, i, len, strIntLen;
3153
3154     /*
3155      * Replace the "*" (if present) in the pixel-size slot of each
3156      * alternative with the targetPxlSize.
3157      */
3158     p = pattern;
3159     alternatives = 1;
3160     while ((p = strchr(p, ',')) != NULL) {
3161       alternatives++;
3162       p++;
3163     }
3164     snprintf(strInt, sizeof(strInt), "%d", targetPxlSize);
3165     strIntLen = strlen(strInt);
3166     base_fnt_lst = calloc(1, strlen(pattern) + strIntLen * alternatives + 1);
3167
3168     p = pattern;
3169     q = base_fnt_lst;
3170     while (alternatives--) {
3171       char *comma = strchr(p, ',');
3172       for (i=0; i<14; i++) {
3173         char *hyphen = strchr(p, '-');
3174         if (!hyphen) break;
3175         if (comma && hyphen > comma) break;
3176         len = hyphen + 1 - p;
3177         if (i == 7 && *p == '*' && len == 2) {
3178           p += len;
3179           memcpy(q, strInt, strIntLen);
3180           q += strIntLen;
3181           *q++ = '-';
3182         } else {
3183           memcpy(q, p, len);
3184           p += len;
3185           q += len;
3186         }
3187       }
3188       if (!comma) break;
3189       len = comma + 1 - p;
3190       memcpy(q, p, len);
3191       p += len;
3192       q += len;
3193     }
3194     strcpy(q, p);
3195
3196     return base_fnt_lst;
3197 }
3198
3199 XFontSet
3200 CreateFontSet(base_fnt_lst)
3201      char *base_fnt_lst;
3202 {
3203     XFontSet fntSet;
3204     char **missing_list;
3205     int missing_count;
3206     char *def_string;
3207
3208     fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
3209                             &missing_list, &missing_count, &def_string);
3210     if (appData.debugMode) {
3211       int i, count;
3212       XFontStruct **font_struct_list;
3213       char **font_name_list;
3214       fprintf(debugFP, "Requested font set for list %s\n", base_fnt_lst);
3215       if (fntSet) {
3216         fprintf(debugFP, " got list %s, locale %s\n",
3217                 XBaseFontNameListOfFontSet(fntSet),
3218                 XLocaleOfFontSet(fntSet));
3219         count = XFontsOfFontSet(fntSet, &font_struct_list, &font_name_list);
3220         for (i = 0; i < count; i++) {
3221           fprintf(debugFP, " got charset %s\n", font_name_list[i]);
3222         }
3223       }
3224       for (i = 0; i < missing_count; i++) {
3225         fprintf(debugFP, " missing charset %s\n", missing_list[i]);
3226       }
3227     }
3228     if (fntSet == NULL) {
3229       fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
3230       exit(2);
3231     }
3232     return fntSet;
3233 }
3234 #else // not ENABLE_NLS
3235 /*
3236  * Find a font that matches "pattern" that is as close as
3237  * possible to the targetPxlSize.  Prefer fonts that are k
3238  * pixels smaller to fonts that are k pixels larger.  The
3239  * pattern must be in the X Consortium standard format,
3240  * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3241  * The return value should be freed with XtFree when no
3242  * longer needed.
3243  */
3244 char *
3245 FindFont(pattern, targetPxlSize)
3246      char *pattern;
3247      int targetPxlSize;
3248 {
3249     char **fonts, *p, *best, *scalable, *scalableTail;
3250     int i, j, nfonts, minerr, err, pxlSize;
3251
3252     fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3253     if (nfonts < 1) {
3254         fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3255                 programName, pattern);
3256         exit(2);
3257     }
3258
3259     best = fonts[0];
3260     scalable = NULL;
3261     minerr = 999999;
3262     for (i=0; i<nfonts; i++) {
3263         j = 0;
3264         p = fonts[i];
3265         if (*p != '-') continue;
3266         while (j < 7) {
3267             if (*p == NULLCHAR) break;
3268             if (*p++ == '-') j++;
3269         }
3270         if (j < 7) continue;
3271         pxlSize = atoi(p);
3272         if (pxlSize == 0) {
3273             scalable = fonts[i];
3274             scalableTail = p;
3275         } else {
3276             err = pxlSize - targetPxlSize;
3277             if (Abs(err) < Abs(minerr) ||
3278                 (minerr > 0 && err < 0 && -err == minerr)) {
3279                 best = fonts[i];
3280                 minerr = err;
3281             }
3282         }
3283     }
3284     if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3285         /* If the error is too big and there is a scalable font,
3286            use the scalable font. */
3287         int headlen = scalableTail - scalable;
3288         p = (char *) XtMalloc(strlen(scalable) + 10);
3289         while (isdigit(*scalableTail)) scalableTail++;
3290         sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3291     } else {
3292         p = (char *) XtMalloc(strlen(best) + 2);
3293         safeStrCpy(p, best, strlen(best)+1 );
3294     }
3295     if (appData.debugMode) {
3296         fprintf(debugFP, _("resolved %s at pixel size %d\n  to %s\n"),
3297                 pattern, targetPxlSize, p);
3298     }
3299     XFreeFontNames(fonts);
3300     return p;
3301 }
3302 #endif
3303
3304 void DeleteGCs()
3305 {   // [HGM] deletes GCs that are to be remade, to prevent resource leak;
3306     // must be called before all non-first callse to CreateGCs()
3307     XtReleaseGC(shellWidget, highlineGC);
3308     XtReleaseGC(shellWidget, lightSquareGC);
3309     XtReleaseGC(shellWidget, darkSquareGC);
3310     XtReleaseGC(shellWidget, lineGC);
3311     if (appData.monoMode) {
3312         if (DefaultDepth(xDisplay, xScreen) == 1) {
3313             XtReleaseGC(shellWidget, wbPieceGC);
3314         } else {
3315             XtReleaseGC(shellWidget, bwPieceGC);
3316         }
3317     } else {
3318         XtReleaseGC(shellWidget, prelineGC);
3319         XtReleaseGC(shellWidget, jailSquareGC);
3320         XtReleaseGC(shellWidget, wdPieceGC);
3321         XtReleaseGC(shellWidget, wlPieceGC);
3322         XtReleaseGC(shellWidget, wjPieceGC);
3323         XtReleaseGC(shellWidget, bdPieceGC);
3324         XtReleaseGC(shellWidget, blPieceGC);
3325         XtReleaseGC(shellWidget, bjPieceGC);
3326     }
3327 }
3328
3329 void CreateGCs(int redo)
3330 {
3331     XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3332       | GCBackground | GCFunction | GCPlaneMask;
3333     XGCValues gc_values;
3334     GC copyInvertedGC;
3335
3336     gc_values.plane_mask = AllPlanes;
3337     gc_values.line_width = lineGap;
3338     gc_values.line_style = LineSolid;
3339     gc_values.function = GXcopy;
3340
3341   if(redo) {
3342     DeleteGCs(); // called a second time; clean up old GCs first
3343   } else { // [HGM] grid and font GCs created on first call only
3344     gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3345     gc_values.background = XWhitePixel(xDisplay, xScreen);
3346     coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3347     XSetFont(xDisplay, coordGC, coordFontID);
3348
3349     // [HGM] make font for holdings counts (white on black)
3350     gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3351     gc_values.background = XBlackPixel(xDisplay, xScreen);
3352     countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3353     XSetFont(xDisplay, countGC, countFontID);
3354   }
3355     gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3356     gc_values.background = XBlackPixel(xDisplay, xScreen);
3357     lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3358
3359     if (appData.monoMode) {
3360         gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3361         gc_values.background = XWhitePixel(xDisplay, xScreen);
3362         highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3363
3364         gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3365         gc_values.background = XBlackPixel(xDisplay, xScreen);
3366         lightSquareGC = wbPieceGC
3367           = XtGetGC(shellWidget, value_mask, &gc_values);
3368
3369         gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3370         gc_values.background = XWhitePixel(xDisplay, xScreen);
3371         darkSquareGC = bwPieceGC
3372           = XtGetGC(shellWidget, value_mask, &gc_values);
3373
3374         if (DefaultDepth(xDisplay, xScreen) == 1) {
3375             /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3376             gc_values.function = GXcopyInverted;
3377             copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3378             gc_values.function = GXcopy;
3379             if (XBlackPixel(xDisplay, xScreen) == 1) {
3380                 bwPieceGC = darkSquareGC;
3381                 wbPieceGC = copyInvertedGC;
3382             } else {
3383                 bwPieceGC = copyInvertedGC;
3384                 wbPieceGC = lightSquareGC;
3385             }
3386         }
3387     } else {
3388         gc_values.foreground = highlightSquareColor;
3389         gc_values.background = highlightSquareColor;
3390         highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3391
3392         gc_values.foreground = premoveHighlightColor;
3393         gc_values.background = premoveHighlightColor;
3394         prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3395
3396         gc_values.foreground = lightSquareColor;
3397         gc_values.background = darkSquareColor;
3398         lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3399
3400         gc_values.foreground = darkSquareColor;
3401         gc_values.background = lightSquareColor;
3402         darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3403
3404         gc_values.foreground = jailSquareColor;
3405         gc_values.background = jailSquareColor;
3406         jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3407
3408         gc_values.foreground = whitePieceColor;
3409         gc_values.background = darkSquareColor;
3410         wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3411
3412         gc_values.foreground = whitePieceColor;
3413         gc_values.background = lightSquareColor;
3414         wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3415
3416         gc_values.foreground = whitePieceColor;
3417         gc_values.background = jailSquareColor;
3418         wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3419
3420         gc_values.foreground = blackPieceColor;
3421         gc_values.background = darkSquareColor;
3422         bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3423
3424         gc_values.foreground = blackPieceColor;
3425         gc_values.background = lightSquareColor;
3426         blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3427
3428         gc_values.foreground = blackPieceColor;
3429         gc_values.background = jailSquareColor;
3430         bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3431     }
3432 }
3433
3434 void loadXIM(xim, xmask, filename, dest, mask)
3435      XImage *xim;
3436      XImage *xmask;
3437      char *filename;
3438      Pixmap *dest;
3439      Pixmap *mask;
3440 {
3441     int x, y, w, h, p;
3442     FILE *fp;
3443     Pixmap temp;
3444     XGCValues   values;
3445     GC maskGC;
3446
3447     fp = fopen(filename, "rb");
3448     if (!fp) {
3449         fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3450         exit(1);
3451     }
3452
3453     w = fgetc(fp);
3454     h = fgetc(fp);
3455
3456     for (y=0; y<h; ++y) {
3457         for (x=0; x<h; ++x) {
3458             p = fgetc(fp);
3459
3460             switch (p) {
3461               case 0:
3462                 XPutPixel(xim, x, y, blackPieceColor);
3463                 if (xmask)
3464                   XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3465                 break;
3466               case 1:
3467                 XPutPixel(xim, x, y, darkSquareColor);
3468                 if (xmask)
3469                   XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3470                 break;
3471               case 2:
3472                 XPutPixel(xim, x, y, whitePieceColor);
3473                 if (xmask)
3474                   XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3475                 break;
3476               case 3:
3477                 XPutPixel(xim, x, y, lightSquareColor);
3478                 if (xmask)
3479                   XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3480                 break;
3481             }
3482         }
3483     }
3484
3485     fclose(fp);
3486
3487     /* create Pixmap of piece */
3488     *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3489                           w, h, xim->depth);
3490     XPutImage(xDisplay, *dest, lightSquareGC, xim,
3491               0, 0, 0, 0, w, h);
3492
3493     /* create Pixmap of clipmask
3494        Note: We assume the white/black pieces have the same
3495              outline, so we make only 6 masks. This is okay
3496              since the XPM clipmask routines do the same. */
3497     if (xmask) {
3498       temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3499                             w, h, xim->depth);
3500       XPutImage(xDisplay, temp, lightSquareGC, xmask,
3501               0, 0, 0, 0, w, h);
3502
3503       /* now create the 1-bit version */
3504       *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3505                           w, h, 1);
3506
3507       values.foreground = 1;
3508       values.background = 0;
3509
3510       /* Don't use XtGetGC, not read only */
3511       maskGC = XCreateGC(xDisplay, *mask,
3512                     GCForeground | GCBackground, &values);
3513       XCopyPlane(xDisplay, temp, *mask, maskGC,
3514                   0, 0, squareSize, squareSize, 0, 0, 1);
3515       XFreePixmap(xDisplay, temp);
3516     }
3517 }
3518
3519
3520 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3521
3522 void CreateXIMPieces()
3523 {
3524     int piece, kind;
3525     char buf[MSG_SIZ];
3526     u_int ss;
3527     static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3528     XImage *ximtemp;
3529
3530     ss = squareSize;
3531
3532     /* The XSynchronize calls were copied from CreatePieces.
3533        Not sure if needed, but can't hurt */
3534     XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3535                                      buffering bug */
3536
3537     /* temp needed by loadXIM() */
3538     ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3539                  0, 0, ss, ss, AllPlanes, XYPixmap);
3540
3541     if (strlen(appData.pixmapDirectory) == 0) {
3542       useImages = 0;
3543     } else {
3544         useImages = 1;
3545         if (appData.monoMode) {
3546           DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3547                             0, 2);
3548           ExitEvent(2);
3549         }
3550         fprintf(stderr, _("\nLoading XIMs...\n"));
3551         /* Load pieces */
3552         for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3553             fprintf(stderr, "%d", piece+1);
3554             for (kind=0; kind<4; kind++) {
3555                 fprintf(stderr, ".");
3556                 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3557                         ExpandPathName(appData.pixmapDirectory),
3558                         piece <= (int) WhiteKing ? "" : "w",
3559                         pieceBitmapNames[piece],
3560                         ximkind[kind], ss);
3561                 ximPieceBitmap[kind][piece] =
3562                   XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3563                             0, 0, ss, ss, AllPlanes, XYPixmap);
3564                 if (appData.debugMode)
3565                   fprintf(stderr, _("(File:%s:) "), buf);
3566                 loadXIM(ximPieceBitmap[kind][piece],
3567                         ximtemp, buf,
3568                         &(xpmPieceBitmap2[kind][piece]),
3569                         &(ximMaskPm2[piece]));
3570                 if(piece <= (int)WhiteKing)
3571                     xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3572             }
3573             fprintf(stderr," ");
3574         }
3575         /* Load light and dark squares */
3576         /* If the LSQ and DSQ pieces don't exist, we will
3577            draw them with solid squares. */
3578         snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3579         if (access(buf, 0) != 0) {
3580             useImageSqs = 0;
3581         } else {
3582             useImageSqs = 1;
3583             fprintf(stderr, _("light square "));
3584             ximLightSquare=
3585               XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3586                         0, 0, ss, ss, AllPlanes, XYPixmap);
3587             if (appData.debugMode)
3588               fprintf(stderr, _("(File:%s:) "), buf);
3589
3590             loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3591             fprintf(stderr, _("dark square "));
3592             snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3593                     ExpandPathName(appData.pixmapDirectory), ss);
3594             if (appData.debugMode)
3595               fprintf(stderr, _("(File:%s:) "), buf);
3596             ximDarkSquare=
3597               XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3598                         0, 0, ss, ss, AllPlanes, XYPixmap);
3599             loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3600             xpmJailSquare = xpmLightSquare;
3601         }
3602         fprintf(stderr, _("Done.\n"));
3603     }
3604     XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3605 }
3606
3607 static VariantClass oldVariant = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
3608
3609 #if HAVE_LIBXPM
3610 void CreateXPMBoard(char *s, int kind)
3611 {
3612     XpmAttributes attr;
3613     attr.valuemask = 0;
3614     if(!appData.useBitmaps || s == NULL || *s == 0 || *s == '*') { useTexture &= ~(kind+1); return; }
3615     if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3616         useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3617     }
3618 }
3619
3620 void FreeXPMPieces()
3621 {   // [HGM] to prevent resoucre leak on calling CreaeXPMPieces() a second time,
3622     // thisroutine has to be called t free the old piece pixmaps
3623     int piece, kind;
3624     for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++)
3625         for (kind=0; kind<4; kind++) XFreePixmap(xDisplay, xpmPieceBitmap2[kind][piece]);
3626     if(useImageSqs) {
3627         XFreePixmap(xDisplay, xpmLightSquare);
3628         XFreePixmap(xDisplay, xpmDarkSquare);
3629     }
3630 }
3631
3632 void CreateXPMPieces()
3633 {
3634     int piece, kind, r;
3635     char buf[MSG_SIZ];
3636     u_int ss = squareSize;
3637     XpmAttributes attr;
3638     static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3639     XpmColorSymbol symbols[4];
3640     static int redo = False;
3641
3642     if(redo) FreeXPMPieces(); else redo = 1;
3643
3644     /* The XSynchronize calls were copied from CreatePieces.
3645        Not sure if needed, but can't hurt */
3646     XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3647
3648     /* Setup translations so piece colors match square colors */
3649     symbols[0].name = "light_piece";
3650     symbols[0].value = appData.whitePieceColor;
3651     symbols[1].name = "dark_piece";
3652     symbols[1].value = appData.blackPieceColor;
3653     symbols[2].name = "light_square";
3654     symbols[2].value = appData.lightSquareColor;