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