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