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