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