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