Fix arrow highlighting in 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;
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) return; // 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 #if HAVE_LIBXPM
1837     CreateAnimVars();
1838 #endif
1839 }
1840 #endif
1841
1842 void ParseIcsTextColors()
1843 {   // [HGM] tken out of main(), so it can be called from ICS-Options dialog
1844     if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1845         parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1846         parse_cpair(ColorChannel1, appData.colorChannel1) < 0  ||
1847         parse_cpair(ColorChannel, appData.colorChannel) < 0  ||
1848         parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1849         parse_cpair(ColorTell, appData.colorTell) < 0 ||
1850         parse_cpair(ColorChallenge, appData.colorChallenge) < 0  ||
1851         parse_cpair(ColorRequest, appData.colorRequest) < 0  ||
1852         parse_cpair(ColorSeek, appData.colorSeek) < 0  ||
1853         parse_cpair(ColorNormal, appData.colorNormal) < 0)
1854       {
1855           if (appData.colorize) {
1856               fprintf(stderr,
1857                       _("%s: can't parse color names; disabling colorization\n"),
1858                       programName);
1859           }
1860           appData.colorize = FALSE;
1861       }
1862 }
1863
1864 int MakeColors()
1865 {   // [HGM] taken out of main(), so it can be called from BoardOptions dialog
1866     XrmValue vFrom, vTo;
1867     int forceMono = False;
1868
1869     if (!appData.monoMode) {
1870         vFrom.addr = (caddr_t) appData.lightSquareColor;
1871         vFrom.size = strlen(appData.lightSquareColor);
1872         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1873         if (vTo.addr == NULL) {
1874           appData.monoMode = True;
1875           forceMono = True;
1876         } else {
1877           lightSquareColor = *(Pixel *) vTo.addr;
1878         }
1879     }
1880     if (!appData.monoMode) {
1881         vFrom.addr = (caddr_t) appData.darkSquareColor;
1882         vFrom.size = strlen(appData.darkSquareColor);
1883         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1884         if (vTo.addr == NULL) {
1885           appData.monoMode = True;
1886           forceMono = True;
1887         } else {
1888           darkSquareColor = *(Pixel *) vTo.addr;
1889         }
1890     }
1891     if (!appData.monoMode) {
1892         vFrom.addr = (caddr_t) appData.whitePieceColor;
1893         vFrom.size = strlen(appData.whitePieceColor);
1894         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1895         if (vTo.addr == NULL) {
1896           appData.monoMode = True;
1897           forceMono = True;
1898         } else {
1899           whitePieceColor = *(Pixel *) vTo.addr;
1900         }
1901     }
1902     if (!appData.monoMode) {
1903         vFrom.addr = (caddr_t) appData.blackPieceColor;
1904         vFrom.size = strlen(appData.blackPieceColor);
1905         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1906         if (vTo.addr == NULL) {
1907           appData.monoMode = True;
1908           forceMono = True;
1909         } else {
1910           blackPieceColor = *(Pixel *) vTo.addr;
1911         }
1912     }
1913
1914     if (!appData.monoMode) {
1915         vFrom.addr = (caddr_t) appData.highlightSquareColor;
1916         vFrom.size = strlen(appData.highlightSquareColor);
1917         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1918         if (vTo.addr == NULL) {
1919           appData.monoMode = True;
1920           forceMono = True;
1921         } else {
1922           highlightSquareColor = *(Pixel *) vTo.addr;
1923         }
1924     }
1925
1926     if (!appData.monoMode) {
1927         vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1928         vFrom.size = strlen(appData.premoveHighlightColor);
1929         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1930         if (vTo.addr == NULL) {
1931           appData.monoMode = True;
1932           forceMono = True;
1933         } else {
1934           premoveHighlightColor = *(Pixel *) vTo.addr;
1935         }
1936     }
1937     return forceMono;
1938 }
1939
1940 void
1941 CreateAnyPieces()
1942 {   // [HGM] taken out of main
1943 #if HAVE_LIBXPM
1944     if (appData.monoMode && // [HGM] no sense to go on to certain doom
1945        (appData.bitmapDirectory == NULL || appData.bitmapDirectory[0] == NULLCHAR))
1946             appData.bitmapDirectory = strdup(DEF_BITMAP_DIR);
1947
1948     if (appData.bitmapDirectory[0] != NULLCHAR) {
1949       CreatePieces();
1950     } else {
1951       CreateXPMPieces();
1952       CreateXPMBoard(appData.liteBackTextureFile, 1);
1953       CreateXPMBoard(appData.darkBackTextureFile, 0);
1954     }
1955 #else
1956     CreateXIMPieces();
1957     /* Create regular pieces */
1958     if (!useImages) CreatePieces();
1959 #endif
1960 }
1961
1962 int
1963 main(argc, argv)
1964      int argc;
1965      char **argv;
1966 {
1967     int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1968     XSetWindowAttributes window_attributes;
1969     Arg args[16];
1970     Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1971     XrmValue vFrom, vTo;
1972     XtGeometryResult gres;
1973     char *p;
1974     XrmDatabase xdb;
1975     int forceMono = False;
1976
1977     srandom(time(0)); // [HGM] book: make random truly random
1978
1979     setbuf(stdout, NULL);
1980     setbuf(stderr, NULL);
1981     debugFP = stderr;
1982
1983     if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1984         printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1985         exit(0);
1986     }
1987
1988     programName = strrchr(argv[0], '/');
1989     if (programName == NULL)
1990       programName = argv[0];
1991     else
1992       programName++;
1993
1994 #ifdef ENABLE_NLS
1995     XtSetLanguageProc(NULL, NULL, NULL);
1996     bindtextdomain(PACKAGE, LOCALEDIR);
1997     textdomain(PACKAGE);
1998 #endif
1999
2000     shellWidget =
2001       XtAppInitialize(&appContext, "XBoard", shellOptions,
2002                       XtNumber(shellOptions),
2003                       &argc, argv, xboardResources, NULL, 0);
2004     appData.boardSize = "";
2005     InitAppData(ConvertToLine(argc, argv));
2006     p = getenv("HOME");
2007     if (p == NULL) p = "/tmp";
2008     i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
2009     gameCopyFilename = (char*) malloc(i);
2010     gamePasteFilename = (char*) malloc(i);
2011     snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
2012     snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
2013
2014     XtGetApplicationResources(shellWidget, (XtPointer) &appData,
2015                               clientResources, XtNumber(clientResources),
2016                               NULL, 0);
2017
2018     { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
2019         static char buf[MSG_SIZ];
2020         EscapeExpand(buf, appData.firstInitString);
2021         appData.firstInitString = strdup(buf);
2022         EscapeExpand(buf, appData.secondInitString);
2023         appData.secondInitString = strdup(buf);
2024         EscapeExpand(buf, appData.firstComputerString);
2025         appData.firstComputerString = strdup(buf);
2026         EscapeExpand(buf, appData.secondComputerString);
2027         appData.secondComputerString = strdup(buf);
2028     }
2029
2030     if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
2031         chessDir = ".";
2032     } else {
2033         if (chdir(chessDir) != 0) {
2034             fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
2035             perror(chessDir);
2036             exit(1);
2037         }
2038     }
2039
2040     if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
2041         /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
2042         if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL)  {
2043            printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
2044            exit(errno);
2045         }
2046         setbuf(debugFP, NULL);
2047     }
2048
2049 #if ENABLE_NLS
2050     if (appData.debugMode) {
2051       fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
2052     }
2053 #endif
2054
2055     /* [HGM,HR] make sure board size is acceptable */
2056     if(appData.NrFiles > BOARD_FILES ||
2057        appData.NrRanks > BOARD_RANKS   )
2058          DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
2059
2060 #if !HIGHDRAG
2061     /* This feature does not work; animation needs a rewrite */
2062     appData.highlightDragging = FALSE;
2063 #endif
2064     InitBackEnd1();
2065
2066     xDisplay = XtDisplay(shellWidget);
2067     xScreen = DefaultScreen(xDisplay);
2068     wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
2069
2070         gameInfo.variant = StringToVariant(appData.variant);
2071         InitPosition(FALSE);
2072
2073 #ifdef IDSIZE
2074     InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
2075 #else
2076     if (isdigit(appData.boardSize[0])) {
2077         i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
2078                    &lineGap, &clockFontPxlSize, &coordFontPxlSize,
2079                    &fontPxlSize, &smallLayout, &tinyLayout);
2080         if (i == 0) {
2081             fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
2082                     programName, appData.boardSize);
2083             exit(2);
2084         }
2085         if (i < 7) {
2086             /* Find some defaults; use the nearest known size */
2087             SizeDefaults *szd, *nearest;
2088             int distance = 99999;
2089             nearest = szd = sizeDefaults;
2090             while (szd->name != NULL) {
2091                 if (abs(szd->squareSize - squareSize) < distance) {
2092                     nearest = szd;
2093                     distance = abs(szd->squareSize - squareSize);
2094                     if (distance == 0) break;
2095                 }
2096                 szd++;
2097             }
2098             if (i < 2) lineGap = nearest->lineGap;
2099             if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
2100             if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
2101             if (i < 5) fontPxlSize = nearest->fontPxlSize;
2102             if (i < 6) smallLayout = nearest->smallLayout;
2103             if (i < 7) tinyLayout = nearest->tinyLayout;
2104         }
2105     } else {
2106         SizeDefaults *szd = sizeDefaults;
2107         if (*appData.boardSize == NULLCHAR) {
2108             while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
2109                    DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
2110               szd++;
2111             }
2112             if (szd->name == NULL) szd--;
2113             appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
2114         } else {
2115             while (szd->name != NULL &&
2116                    StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
2117             if (szd->name == NULL) {
2118                 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
2119                         programName, appData.boardSize);
2120                 exit(2);
2121             }
2122         }
2123         squareSize = szd->squareSize;
2124         lineGap = szd->lineGap;
2125         clockFontPxlSize = szd->clockFontPxlSize;
2126         coordFontPxlSize = szd->coordFontPxlSize;
2127         fontPxlSize = szd->fontPxlSize;
2128         smallLayout = szd->smallLayout;
2129         tinyLayout = szd->tinyLayout;
2130         // [HGM] font: use defaults from settings file if available and not overruled
2131     }
2132     if(!fontIsSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
2133         appData.clockFont = fontTable[CLOCK_FONT][squareSize];
2134     if(!fontIsSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
2135         appData.font = fontTable[MESSAGE_FONT][squareSize];
2136     if(!fontIsSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
2137         appData.coordFont = fontTable[COORD_FONT][squareSize];
2138
2139     /* Now, using squareSize as a hint, find a good XPM/XIM set size */
2140     if (strlen(appData.pixmapDirectory) > 0) {
2141         p = ExpandPathName(appData.pixmapDirectory);
2142         if (!p) {
2143             fprintf(stderr, _("Error expanding path name \"%s\"\n"),
2144                    appData.pixmapDirectory);
2145             exit(1);
2146         }
2147         if (appData.debugMode) {
2148           fprintf(stderr, _("\
2149 XBoard square size (hint): %d\n\
2150 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
2151         }
2152         squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
2153         if (appData.debugMode) {
2154             fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
2155         }
2156     }
2157     defaultLineGap = lineGap;
2158     if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
2159
2160     /* [HR] height treated separately (hacked) */
2161     boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
2162     boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
2163     if (appData.showJail == 1) {
2164         /* Jail on top and bottom */
2165         XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2166         XtSetArg(boardArgs[2], XtNheight,
2167                  boardHeight + 2*(lineGap + squareSize));
2168     } else if (appData.showJail == 2) {
2169         /* Jail on sides */
2170         XtSetArg(boardArgs[1], XtNwidth,
2171                  boardWidth + 2*(lineGap + squareSize));
2172         XtSetArg(boardArgs[2], XtNheight, boardHeight);
2173     } else {
2174         /* No jail */
2175         XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2176         XtSetArg(boardArgs[2], XtNheight, boardHeight);
2177     }
2178
2179     /*
2180      * Determine what fonts to use.
2181      */
2182 #if ENABLE_NLS
2183     appData.font = InsertPxlSize(appData.font, fontPxlSize);
2184     appData.clockFont = InsertPxlSize(appData.clockFont, clockFontPxlSize);
2185     appData.coordFont = InsertPxlSize(appData.coordFont, coordFontPxlSize);
2186     fontSet = CreateFontSet(appData.font);
2187     clockFontSet = CreateFontSet(appData.clockFont);
2188     {
2189       /* For the coordFont, use the 0th font of the fontset. */
2190       XFontSet coordFontSet = CreateFontSet(appData.coordFont);
2191       XFontStruct **font_struct_list;
2192       char **font_name_list;
2193       XFontsOfFontSet(coordFontSet, &font_struct_list, &font_name_list);
2194       coordFontID = XLoadFont(xDisplay, font_name_list[0]);
2195       coordFontStruct = XQueryFont(xDisplay, coordFontID);
2196     }
2197 #else
2198     appData.font = FindFont(appData.font, fontPxlSize);
2199     appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2200     appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2201     clockFontID = XLoadFont(xDisplay, appData.clockFont);
2202     clockFontStruct = XQueryFont(xDisplay, clockFontID);
2203     coordFontID = XLoadFont(xDisplay, appData.coordFont);
2204     coordFontStruct = XQueryFont(xDisplay, coordFontID);
2205 #endif
2206     countFontID = coordFontID;  // [HGM] holdings
2207     countFontStruct = coordFontStruct;
2208
2209     xdb = XtDatabase(xDisplay);
2210 #if ENABLE_NLS
2211     XrmPutLineResource(&xdb, "*international: True");
2212     vTo.size = sizeof(XFontSet);
2213     vTo.addr = (XtPointer) &fontSet;
2214     XrmPutResource(&xdb, "*fontSet", XtRFontSet, &vTo);
2215 #else
2216     XrmPutStringResource(&xdb, "*font", appData.font);
2217 #endif
2218
2219     /*
2220      * Detect if there are not enough colors available and adapt.
2221      */
2222     if (DefaultDepth(xDisplay, xScreen) <= 2) {
2223       appData.monoMode = True;
2224     }
2225
2226     forceMono = MakeColors();
2227
2228     if (forceMono) {
2229       fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2230               programName);
2231         appData.monoMode = True;
2232     }
2233
2234     if (appData.lowTimeWarning && !appData.monoMode) {
2235       vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2236       vFrom.size = strlen(appData.lowTimeWarningColor);
2237       XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2238       if (vTo.addr == NULL)
2239                 appData.monoMode = True;
2240       else
2241                 lowTimeWarningColor = *(Pixel *) vTo.addr;
2242     }
2243
2244     if (appData.monoMode && appData.debugMode) {
2245         fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2246                 (unsigned long) XWhitePixel(xDisplay, xScreen),
2247                 (unsigned long) XBlackPixel(xDisplay, xScreen));
2248     }
2249
2250     ParseIcsTextColors();
2251     textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2252     textColors[ColorNone].attr = 0;
2253
2254     XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2255
2256     /*
2257      * widget hierarchy
2258      */
2259     if (tinyLayout) {
2260         layoutName = "tinyLayout";
2261     } else if (smallLayout) {
2262         layoutName = "smallLayout";
2263     } else {
2264         layoutName = "normalLayout";
2265     }
2266     /* Outer layoutWidget is there only to provide a name for use in
2267        resources that depend on the layout style */
2268     layoutWidget =
2269       XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2270                             layoutArgs, XtNumber(layoutArgs));
2271     formWidget =
2272       XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2273                             formArgs, XtNumber(formArgs));
2274     XtSetArg(args[0], XtNdefaultDistance, &sep);
2275     XtGetValues(formWidget, args, 1);
2276
2277     j = 0;
2278     widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2279     XtSetArg(args[0], XtNtop,    XtChainTop);
2280     XtSetArg(args[1], XtNbottom, XtChainTop);
2281     XtSetArg(args[2], XtNright,  XtChainLeft);
2282     XtSetValues(menuBarWidget, args, 3);
2283
2284     widgetList[j++] = whiteTimerWidget =
2285       XtCreateWidget("whiteTime", labelWidgetClass,
2286                      formWidget, timerArgs, XtNumber(timerArgs));
2287 #if ENABLE_NLS
2288     XtSetArg(args[0], XtNfontSet, clockFontSet);
2289 #else
2290     XtSetArg(args[0], XtNfont, clockFontStruct);
2291 #endif
2292     XtSetArg(args[1], XtNtop,    XtChainTop);
2293     XtSetArg(args[2], XtNbottom, XtChainTop);
2294     XtSetValues(whiteTimerWidget, args, 3);
2295
2296     widgetList[j++] = blackTimerWidget =
2297       XtCreateWidget("blackTime", labelWidgetClass,
2298                      formWidget, timerArgs, XtNumber(timerArgs));
2299 #if ENABLE_NLS
2300     XtSetArg(args[0], XtNfontSet, clockFontSet);
2301 #else
2302     XtSetArg(args[0], XtNfont, clockFontStruct);
2303 #endif
2304     XtSetArg(args[1], XtNtop,    XtChainTop);
2305     XtSetArg(args[2], XtNbottom, XtChainTop);
2306     XtSetValues(blackTimerWidget, args, 3);
2307
2308     if (appData.titleInWindow) {
2309         widgetList[j++] = titleWidget =
2310           XtCreateWidget("title", labelWidgetClass, formWidget,
2311                          titleArgs, XtNumber(titleArgs));
2312         XtSetArg(args[0], XtNtop,    XtChainTop);
2313         XtSetArg(args[1], XtNbottom, XtChainTop);
2314         XtSetValues(titleWidget, args, 2);
2315     }
2316
2317     if (appData.showButtonBar) {
2318       widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2319       XtSetArg(args[0], XtNleft,  XtChainRight); // [HGM] glue to right window edge
2320       XtSetArg(args[1], XtNright, XtChainRight); //       for good run-time sizing
2321       XtSetArg(args[2], XtNtop,    XtChainTop);
2322       XtSetArg(args[3], XtNbottom, XtChainTop);
2323       XtSetValues(buttonBarWidget, args, 4);
2324     }
2325
2326     widgetList[j++] = messageWidget =
2327       XtCreateWidget("message", labelWidgetClass, formWidget,
2328                      messageArgs, XtNumber(messageArgs));
2329     XtSetArg(args[0], XtNtop,    XtChainTop);
2330     XtSetArg(args[1], XtNbottom, XtChainTop);
2331     XtSetValues(messageWidget, args, 2);
2332
2333     widgetList[j++] = boardWidget =
2334       XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2335                      XtNumber(boardArgs));
2336
2337     XtManageChildren(widgetList, j);
2338
2339     timerWidth = (boardWidth - sep) / 2;
2340     XtSetArg(args[0], XtNwidth, timerWidth);
2341     XtSetValues(whiteTimerWidget, args, 1);
2342     XtSetValues(blackTimerWidget, args, 1);
2343
2344     XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2345     XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2346     XtGetValues(whiteTimerWidget, args, 2);
2347
2348     if (appData.showButtonBar) {
2349       XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2350       XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2351       XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2352     }
2353
2354     /*
2355      * formWidget uses these constraints but they are stored
2356      * in the children.
2357      */
2358     i = 0;
2359     XtSetArg(args[i], XtNfromHoriz, 0); i++;
2360     XtSetValues(menuBarWidget, args, i);
2361     if (appData.titleInWindow) {
2362         if (smallLayout) {
2363             i = 0;
2364             XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2365             XtSetValues(whiteTimerWidget, args, i);
2366             i = 0;
2367             XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2368             XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2369             XtSetValues(blackTimerWidget, args, i);
2370             i = 0;
2371             XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2372             XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2373             XtSetValues(titleWidget, args, i);
2374             i = 0;
2375             XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2376             XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2377             XtSetValues(messageWidget, args, i);
2378             if (appData.showButtonBar) {
2379               i = 0;
2380               XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2381               XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2382               XtSetValues(buttonBarWidget, args, i);
2383             }
2384         } else {
2385             i = 0;
2386             XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2387             XtSetValues(whiteTimerWidget, args, i);
2388             i = 0;
2389             XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2390             XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2391             XtSetValues(blackTimerWidget, args, i);
2392             i = 0;
2393             XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2394             XtSetValues(titleWidget, args, i);
2395             i = 0;
2396             XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2397             XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2398             XtSetValues(messageWidget, args, i);
2399             if (appData.showButtonBar) {
2400               i = 0;
2401               XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2402               XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2403               XtSetValues(buttonBarWidget, args, i);
2404             }
2405         }
2406     } else {
2407         i = 0;
2408         XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2409         XtSetValues(whiteTimerWidget, args, i);
2410         i = 0;
2411         XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2412         XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2413         XtSetValues(blackTimerWidget, args, i);
2414         i = 0;
2415         XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2416         XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2417         XtSetValues(messageWidget, args, i);
2418         if (appData.showButtonBar) {
2419           i = 0;
2420           XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2421           XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2422           XtSetValues(buttonBarWidget, args, i);
2423         }
2424     }
2425     i = 0;
2426     XtSetArg(args[0], XtNfromVert, messageWidget);
2427     XtSetArg(args[1], XtNtop,    XtChainTop);
2428     XtSetArg(args[2], XtNbottom, XtChainBottom);
2429     XtSetArg(args[3], XtNleft,   XtChainLeft);
2430     XtSetArg(args[4], XtNright,  XtChainRight);
2431     XtSetValues(boardWidget, args, 5);
2432
2433     XtRealizeWidget(shellWidget);
2434
2435     if(wpMain.x > 0) {
2436       XtSetArg(args[0], XtNx, wpMain.x);
2437       XtSetArg(args[1], XtNy, wpMain.y);
2438       XtSetValues(shellWidget, args, 2);
2439     }
2440
2441     /*
2442      * Correct the width of the message and title widgets.
2443      * It is not known why some systems need the extra fudge term.
2444      * The value "2" is probably larger than needed.
2445      */
2446     XawFormDoLayout(formWidget, False);
2447
2448 #define WIDTH_FUDGE 2
2449     i = 0;
2450     XtSetArg(args[i], XtNborderWidth, &bor);  i++;
2451     XtSetArg(args[i], XtNheight, &h);  i++;
2452     XtGetValues(messageWidget, args, i);
2453     if (appData.showButtonBar) {
2454       i = 0;
2455       XtSetArg(args[i], XtNwidth, &w);  i++;
2456       XtGetValues(buttonBarWidget, args, i);
2457       w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2458     } else {
2459       w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2460     }
2461
2462     gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2463     if (gres != XtGeometryYes && appData.debugMode) {
2464       fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2465               programName, gres, w, h, wr, hr);
2466     }
2467
2468     /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2469     /* The size used for the child widget in layout lags one resize behind
2470        its true size, so we resize a second time, 1 pixel smaller.  Yeech! */
2471     w--;
2472     gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2473     if (gres != XtGeometryYes && appData.debugMode) {
2474       fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2475               programName, gres, w, h, wr, hr);
2476     }
2477     /* !! end hack */
2478     XtSetArg(args[0], XtNleft,  XtChainLeft);  // [HGM] glue ends for good run-time sizing
2479     XtSetArg(args[1], XtNright, XtChainRight);
2480     XtSetValues(messageWidget, args, 2);
2481
2482     if (appData.titleInWindow) {
2483         i = 0;
2484         XtSetArg(args[i], XtNborderWidth, &bor); i++;
2485         XtSetArg(args[i], XtNheight, &h);  i++;
2486         XtGetValues(titleWidget, args, i);
2487         if (smallLayout) {
2488             w = boardWidth - 2*bor;
2489         } else {
2490             XtSetArg(args[0], XtNwidth, &w);
2491             XtGetValues(menuBarWidget, args, 1);
2492             w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2493         }
2494
2495         gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2496         if (gres != XtGeometryYes && appData.debugMode) {
2497             fprintf(stderr,
2498                     _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2499                     programName, gres, w, h, wr, hr);
2500         }
2501     }
2502     XawFormDoLayout(formWidget, True);
2503
2504     xBoardWindow = XtWindow(boardWidget);
2505
2506     // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2507     //       not need to go into InitDrawingSizes().
2508 #endif
2509
2510     /*
2511      * Create X checkmark bitmap and initialize option menu checks.
2512      */
2513     ReadBitmap(&xMarkPixmap, "checkmark.bm",
2514                checkmark_bits, checkmark_width, checkmark_height);
2515     XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2516 #ifndef OPTIONSDIALOG
2517     if (appData.alwaysPromoteToQueen) {
2518         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2519                     args, 1);
2520     }
2521     if (appData.animateDragging) {
2522         XtSetValues(XtNameToWidget(menuBarWidget,
2523                                    "menuOptions.Animate Dragging"),
2524                     args, 1);
2525     }
2526     if (appData.animate) {
2527         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2528                     args, 1);
2529     }
2530     if (appData.autoCallFlag) {
2531         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2532                     args, 1);
2533     }
2534     if (appData.autoFlipView) {
2535         XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2536                     args, 1);
2537     }
2538     if (appData.blindfold) {
2539         XtSetValues(XtNameToWidget(menuBarWidget,
2540                                    "menuOptions.Blindfold"), args, 1);
2541     }
2542     if (appData.flashCount > 0) {
2543         XtSetValues(XtNameToWidget(menuBarWidget,
2544                                    "menuOptions.Flash Moves"),
2545                     args, 1);
2546     }
2547 #if HIGHDRAG
2548     if (appData.highlightDragging) {
2549         XtSetValues(XtNameToWidget(menuBarWidget,
2550                                    "menuOptions.Highlight Dragging"),
2551                     args, 1);
2552     }
2553 #endif
2554     if (appData.highlightLastMove) {
2555         XtSetValues(XtNameToWidget(menuBarWidget,
2556                                    "menuOptions.Highlight Last Move"),
2557                     args, 1);
2558     }
2559     if (appData.highlightMoveWithArrow) {
2560         XtSetValues(XtNameToWidget(menuBarWidget,
2561                                    "menuOptions.Arrow"),
2562                     args, 1);
2563     }
2564 //    if (appData.icsAlarm) {
2565 //      XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2566 //                  args, 1);
2567 //    }
2568     if (appData.ringBellAfterMoves) {
2569         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2570                     args, 1);
2571     }
2572     if (appData.oneClick) {
2573         XtSetValues(XtNameToWidget(menuBarWidget,
2574                                    "menuOptions.OneClick"), args, 1);
2575     }
2576     if (appData.periodicUpdates) {
2577         XtSetValues(XtNameToWidget(menuBarWidget,
2578                                    "menuOptions.Periodic Updates"), args, 1);
2579     }
2580     if (appData.ponderNextMove) {
2581         XtSetValues(XtNameToWidget(menuBarWidget,
2582                                    "menuOptions.Ponder Next Move"), args, 1);
2583     }
2584     if (appData.popupExitMessage) {
2585         XtSetValues(XtNameToWidget(menuBarWidget,
2586                                    "menuOptions.Popup Exit Message"), args, 1);
2587     }
2588     if (appData.popupMoveErrors) {
2589         XtSetValues(XtNameToWidget(menuBarWidget,
2590                                    "menuOptions.Popup Move Errors"), args, 1);
2591     }
2592 //    if (appData.premove) {
2593 //      XtSetValues(XtNameToWidget(menuBarWidget,
2594 //                                 "menuOptions.Premove"), args, 1);
2595 //    }
2596     if (appData.showCoords) {
2597         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2598                     args, 1);
2599     }
2600     if (appData.hideThinkingFromHuman) {
2601         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2602                     args, 1);
2603     }
2604     if (appData.testLegality) {
2605         XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2606                     args, 1);
2607     }
2608 #endif
2609     if (saveSettingsOnExit) {
2610         XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2611                     args, 1);
2612     }
2613
2614     /*
2615      * Create an icon.
2616      */
2617     ReadBitmap(&wIconPixmap, "icon_white.bm",
2618                icon_white_bits, icon_white_width, icon_white_height);
2619     ReadBitmap(&bIconPixmap, "icon_black.bm",
2620                icon_black_bits, icon_black_width, icon_black_height);
2621     iconPixmap = wIconPixmap;
2622     i = 0;
2623     XtSetArg(args[i], XtNiconPixmap, iconPixmap);  i++;
2624     XtSetValues(shellWidget, args, i);
2625
2626     /*
2627      * Create a cursor for the board widget.
2628      */
2629     window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2630     XChangeWindowAttributes(xDisplay, xBoardWindow,
2631                             CWCursor, &window_attributes);
2632
2633     /*
2634      * Inhibit shell resizing.
2635      */
2636     shellArgs[0].value = (XtArgVal) &w;
2637     shellArgs[1].value = (XtArgVal) &h;
2638     XtGetValues(shellWidget, shellArgs, 2);
2639     shellArgs[4].value = shellArgs[2].value = w;
2640     shellArgs[5].value = shellArgs[3].value = h;
2641     XtSetValues(shellWidget, &shellArgs[2], 4);
2642     marginW =  w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2643     marginH =  h - boardHeight;
2644
2645     CatchDeleteWindow(shellWidget, "QuitProc");
2646
2647     CreateGCs(False);
2648     CreateGrid();
2649     CreateAnyPieces();
2650
2651     CreatePieceMenus();
2652
2653     if (appData.animate || appData.animateDragging)
2654       CreateAnimVars();
2655
2656     XtAugmentTranslations(formWidget,
2657                           XtParseTranslationTable(globalTranslations));
2658     XtAugmentTranslations(boardWidget,
2659                           XtParseTranslationTable(boardTranslations));
2660     XtAugmentTranslations(whiteTimerWidget,
2661                           XtParseTranslationTable(whiteTranslations));
2662     XtAugmentTranslations(blackTimerWidget,
2663                           XtParseTranslationTable(blackTranslations));
2664
2665     /* Why is the following needed on some versions of X instead
2666      * of a translation? */
2667     XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2668                       (XtEventHandler) EventProc, NULL);
2669     /* end why */
2670     XtAddEventHandler(formWidget, KeyPressMask, False,
2671                       (XtEventHandler) MoveTypeInProc, NULL);
2672
2673     /* [AS] Restore layout */
2674     if( wpMoveHistory.visible ) {
2675       HistoryPopUp();
2676     }
2677
2678     if( wpEvalGraph.visible )
2679       {
2680         EvalGraphPopUp();
2681       };
2682
2683     if( wpEngineOutput.visible ) {
2684       EngineOutputPopUp();
2685     }
2686
2687     InitBackEnd2();
2688
2689     if (errorExitStatus == -1) {
2690         if (appData.icsActive) {
2691             /* We now wait until we see "login:" from the ICS before
2692                sending the logon script (problems with timestamp otherwise) */
2693             /*ICSInitScript();*/
2694             if (appData.icsInputBox) ICSInputBoxPopUp();
2695         }
2696
2697     #ifdef SIGWINCH
2698     signal(SIGWINCH, TermSizeSigHandler);
2699     #endif
2700         signal(SIGINT, IntSigHandler);
2701         signal(SIGTERM, IntSigHandler);
2702         if (*appData.cmailGameName != NULLCHAR) {
2703             signal(SIGUSR1, CmailSigHandler);
2704         }
2705     }
2706     gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2707     InitPosition(TRUE);
2708 //    XtSetKeyboardFocus(shellWidget, formWidget);
2709     XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
2710
2711     XtAppMainLoop(appContext);
2712     if (appData.debugMode) fclose(debugFP); // [DM] debug
2713     return 0;
2714 }
2715
2716 static Boolean noEcho;
2717
2718 void
2719 ShutDownFrontEnd()
2720 {
2721     if (appData.icsActive && oldICSInteractionTitle != NULL) {
2722         DisplayIcsInteractionTitle(oldICSInteractionTitle);
2723     }
2724     if (saveSettingsOnExit) SaveSettings(settingsFileName);
2725     unlink(gameCopyFilename);
2726     unlink(gamePasteFilename);
2727     if(noEcho) EchoOn();
2728 }
2729
2730 RETSIGTYPE TermSizeSigHandler(int sig)
2731 {
2732     update_ics_width();
2733 }
2734
2735 RETSIGTYPE
2736 IntSigHandler(sig)
2737      int sig;
2738 {
2739     ExitEvent(sig);
2740 }
2741
2742 RETSIGTYPE
2743 CmailSigHandler(sig)
2744      int sig;
2745 {
2746     int dummy = 0;
2747     int error;
2748
2749     signal(SIGUSR1, SIG_IGN);   /* suspend handler     */
2750
2751     /* Activate call-back function CmailSigHandlerCallBack()             */
2752     OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2753
2754     signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2755 }
2756
2757 void
2758 CmailSigHandlerCallBack(isr, closure, message, count, error)
2759      InputSourceRef isr;
2760      VOIDSTAR closure;
2761      char *message;
2762      int count;
2763      int error;
2764 {
2765     BoardToTop();
2766     ReloadCmailMsgEvent(TRUE);  /* Reload cmail msg  */
2767 }
2768 /**** end signal code ****/
2769
2770
2771 void
2772 ICSInitScript()
2773 {
2774   /* try to open the icsLogon script, either in the location given
2775    * or in the users HOME directory
2776    */
2777
2778   FILE *f;
2779   char buf[MSG_SIZ];
2780   char *homedir;
2781
2782   f = fopen(appData.icsLogon, "r");
2783   if (f == NULL)
2784     {
2785       homedir = getenv("HOME");
2786       if (homedir != NULL)
2787         {
2788           safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2789           strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2790           strncat(buf, appData.icsLogon,  MSG_SIZ - strlen(buf) - 1);
2791           f = fopen(buf, "r");
2792         }
2793     }
2794
2795   if (f != NULL)
2796     ProcessICSInitScript(f);
2797   else
2798     printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2799
2800   return;
2801 }
2802
2803 void
2804 ResetFrontEnd()
2805 {
2806     CommentPopDown();
2807     TagsPopDown();
2808     return;
2809 }
2810
2811 typedef struct {
2812     char *name;
2813     Boolean value;
2814 } Enables;
2815
2816 void
2817 GreyRevert(grey)
2818      Boolean grey;
2819 {
2820     Widget w;
2821     if (!menuBarWidget) return;
2822     w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2823     if (w == NULL) {
2824       DisplayError("menuEdit.Revert", 0);
2825     } else {
2826       XtSetSensitive(w, !grey);
2827     }
2828     w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2829     if (w == NULL) {
2830       DisplayError("menuEdit.Annotate", 0);
2831     } else {
2832       XtSetSensitive(w, !grey);
2833     }
2834 }
2835
2836 void
2837 SetMenuEnables(enab)
2838      Enables *enab;
2839 {
2840   Widget w;
2841   if (!menuBarWidget) return;
2842   while (enab->name != NULL) {
2843     w = XtNameToWidget(menuBarWidget, enab->name);
2844     if (w == NULL) {
2845       DisplayError(enab->name, 0);
2846     } else {
2847       XtSetSensitive(w, enab->value);
2848     }
2849     enab++;
2850   }
2851 }
2852
2853 Enables icsEnables[] = {
2854     { "menuFile.Mail Move", False },
2855     { "menuFile.Reload CMail Message", False },
2856     { "menuMode.Machine Black", False },
2857     { "menuMode.Machine White", False },
2858     { "menuMode.Analysis Mode", False },
2859     { "menuMode.Analyze File", False },
2860     { "menuMode.Two Machines", False },
2861     { "menuMode.Machine Match", False },
2862 #ifndef ZIPPY
2863     { "menuEngine.Hint", False },
2864     { "menuEngine.Book", False },
2865     { "menuEngine.Move Now", False },
2866 #ifndef OPTIONSDIALOG
2867     { "menuOptions.Periodic Updates", False },
2868     { "menuOptions.Hide Thinking", False },
2869     { "menuOptions.Ponder Next Move", False },
2870 #endif
2871 #endif
2872     { "menuEngine.Engine #1 Settings", False },
2873     { "menuEngine.Engine #2 Settings", False },
2874     { "menuEngine.Load Engine", False },
2875     { "menuEdit.Annotate", False },
2876     { "menuOptions.Match", False },
2877     { NULL, False }
2878 };
2879
2880 Enables ncpEnables[] = {
2881     { "menuFile.Mail Move", False },
2882     { "menuFile.Reload CMail Message", False },
2883     { "menuMode.Machine White", False },
2884     { "menuMode.Machine Black", False },
2885     { "menuMode.Analysis Mode", False },
2886     { "menuMode.Analyze File", False },
2887     { "menuMode.Two Machines", False },
2888     { "menuMode.Machine Match", False },
2889     { "menuMode.ICS Client", False },
2890     { "menuView.ICStex", False },
2891     { "menuView.ICS Input Box", False },
2892     { "Action", False },
2893     { "menuEdit.Revert", False },
2894     { "menuEdit.Annotate", False },
2895     { "menuEngine.Engine #1 Settings", False },
2896     { "menuEngine.Engine #2 Settings", False },
2897     { "menuEngine.Move Now", False },
2898     { "menuEngine.Retract Move", False },
2899     { "menuOptions.ICS", False },
2900 #ifndef OPTIONSDIALOG
2901     { "menuOptions.Auto Flag", False },
2902     { "menuOptions.Auto Flip View", False },
2903 //    { "menuOptions.ICS Alarm", False },
2904     { "menuOptions.Move Sound", False },
2905     { "menuOptions.Hide Thinking", False },
2906     { "menuOptions.Periodic Updates", False },
2907     { "menuOptions.Ponder Next Move", False },
2908 #endif
2909     { "menuEngine.Hint", False },
2910     { "menuEngine.Book", False },
2911     { NULL, False }
2912 };
2913
2914 Enables gnuEnables[] = {
2915     { "menuMode.ICS Client", False },
2916     { "menuView.ICStex", False },
2917     { "menuView.ICS Input Box", False },
2918     { "menuAction.Accept", False },
2919     { "menuAction.Decline", False },
2920     { "menuAction.Rematch", False },
2921     { "menuAction.Adjourn", False },
2922     { "menuAction.Stop Examining", False },
2923     { "menuAction.Stop Observing", False },
2924     { "menuAction.Upload to Examine", False },
2925     { "menuEdit.Revert", False },
2926     { "menuEdit.Annotate", False },
2927     { "menuOptions.ICS", False },
2928
2929     /* The next two options rely on SetCmailMode being called *after*    */
2930     /* SetGNUMode so that when GNU is being used to give hints these     */
2931     /* menu options are still available                                  */
2932
2933     { "menuFile.Mail Move", False },
2934     { "menuFile.Reload CMail Message", False },
2935     // [HGM] The following have been added to make a switch from ncp to GNU mode possible
2936     { "menuMode.Machine White", True },
2937     { "menuMode.Machine Black", True },
2938     { "menuMode.Analysis Mode", True },
2939     { "menuMode.Analyze File", True },
2940     { "menuMode.Two Machines", True },
2941     { "menuMode.Machine Match", True },
2942     { "menuEngine.Engine #1 Settings", True },
2943     { "menuEngine.Engine #2 Settings", True },
2944     { "menuEngine.Hint", True },
2945     { "menuEngine.Book", True },
2946     { "menuEngine.Move Now", True },
2947     { "menuEngine.Retract Move", True },
2948     { "Action", True },
2949     { NULL, False }
2950 };
2951
2952 Enables cmailEnables[] = {
2953     { "Action", True },
2954     { "menuAction.Call Flag", False },
2955     { "menuAction.Draw", True },
2956     { "menuAction.Adjourn", False },
2957     { "menuAction.Abort", False },
2958     { "menuAction.Stop Observing", False },
2959     { "menuAction.Stop Examining", False },
2960     { "menuFile.Mail Move", True },
2961     { "menuFile.Reload CMail Message", True },
2962     { NULL, False }
2963 };
2964
2965 Enables trainingOnEnables[] = {
2966   { "menuMode.Edit Comment", False },
2967   { "menuMode.Pause", False },
2968   { "menuEdit.Forward", False },
2969   { "menuEdit.Backward", False },
2970   { "menuEdit.Forward to End", False },
2971   { "menuEdit.Back to Start", False },
2972   { "menuEngine.Move Now", False },
2973   { "menuEdit.Truncate Game", False },
2974   { NULL, False }
2975 };
2976
2977 Enables trainingOffEnables[] = {
2978   { "menuMode.Edit Comment", True },
2979   { "menuMode.Pause", True },
2980   { "menuEdit.Forward", True },
2981   { "menuEdit.Backward", True },
2982   { "menuEdit.Forward to End", True },
2983   { "menuEdit.Back to Start", True },
2984   { "menuEngine.Move Now", True },
2985   { "menuEdit.Truncate Game", True },
2986   { NULL, False }
2987 };
2988
2989 Enables machineThinkingEnables[] = {
2990   { "menuFile.Load Game", False },
2991 //  { "menuFile.Load Next Game", False },
2992 //  { "menuFile.Load Previous Game", False },
2993 //  { "menuFile.Reload Same Game", False },
2994   { "menuEdit.Paste Game", False },
2995   { "menuFile.Load Position", False },
2996 //  { "menuFile.Load Next Position", False },
2997 //  { "menuFile.Load Previous Position", False },
2998 //  { "menuFile.Reload Same Position", False },
2999   { "menuEdit.Paste Position", False },
3000   { "menuMode.Machine White", False },
3001   { "menuMode.Machine Black", False },
3002   { "menuMode.Two Machines", False },
3003 //  { "menuMode.Machine Match", False },
3004   { "menuEngine.Retract Move", False },
3005   { NULL, False }
3006 };
3007
3008 Enables userThinkingEnables[] = {
3009   { "menuFile.Load Game", True },
3010 //  { "menuFile.Load Next Game", True },
3011 //  { "menuFile.Load Previous Game", True },
3012 //  { "menuFile.Reload Same Game", True },
3013   { "menuEdit.Paste Game", True },
3014   { "menuFile.Load Position", True },
3015 //  { "menuFile.Load Next Position", True },
3016 //  { "menuFile.Load Previous Position", True },
3017 //  { "menuFile.Reload Same Position", True },
3018   { "menuEdit.Paste Position", True },
3019   { "menuMode.Machine White", True },
3020   { "menuMode.Machine Black", True },
3021   { "menuMode.Two Machines", True },
3022 //  { "menuMode.Machine Match", True },
3023   { "menuEngine.Retract Move", True },
3024   { NULL, False }
3025 };
3026
3027 void SetICSMode()
3028 {
3029   SetMenuEnables(icsEnables);
3030
3031 #if ZIPPY
3032   if (appData.zippyPlay && !appData.noChessProgram) { /* [DM] icsEngineAnalyze */
3033      XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
3034      XtSetSensitive(XtNameToWidget(menuBarWidget, "menuEngine.Engine #1 Settings"), True);
3035   }
3036 #endif
3037 }
3038
3039 void
3040 SetNCPMode()
3041 {
3042   SetMenuEnables(ncpEnables);
3043 }
3044
3045 void
3046 SetGNUMode()
3047 {
3048   SetMenuEnables(gnuEnables);
3049 }
3050
3051 void
3052 SetCmailMode()
3053 {
3054   SetMenuEnables(cmailEnables);
3055 }
3056
3057 void
3058 SetTrainingModeOn()
3059 {
3060   SetMenuEnables(trainingOnEnables);
3061   if (appData.showButtonBar) {
3062     XtSetSensitive(buttonBarWidget, False);
3063   }
3064   CommentPopDown();
3065 }
3066
3067 void
3068 SetTrainingModeOff()
3069 {
3070   SetMenuEnables(trainingOffEnables);
3071   if (appData.showButtonBar) {
3072     XtSetSensitive(buttonBarWidget, True);
3073   }
3074 }
3075
3076 void
3077 SetUserThinkingEnables()
3078 {
3079   if (appData.noChessProgram) return;
3080   SetMenuEnables(userThinkingEnables);
3081 }
3082
3083 void
3084 SetMachineThinkingEnables()
3085 {
3086   if (appData.noChessProgram) return;
3087   SetMenuEnables(machineThinkingEnables);
3088   switch (gameMode) {
3089   case MachinePlaysBlack:
3090   case MachinePlaysWhite:
3091   case TwoMachinesPlay:
3092     XtSetSensitive(XtNameToWidget(menuBarWidget,
3093                                   ModeToWidgetName(gameMode)), True);
3094     break;
3095   default:
3096     break;
3097   }
3098 }
3099
3100 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
3101 #define HISTORY_SIZE 64
3102 static char *history[HISTORY_SIZE];
3103 int histIn = 0, histP = 0;
3104
3105 void
3106 SaveInHistory(char *cmd)
3107 {
3108   if (history[histIn] != NULL) {
3109     free(history[histIn]);
3110     history[histIn] = NULL;
3111   }
3112   if (*cmd == NULLCHAR) return;
3113   history[histIn] = StrSave(cmd);
3114   histIn = (histIn + 1) % HISTORY_SIZE;
3115   if (history[histIn] != NULL) {
3116     free(history[histIn]);
3117     history[histIn] = NULL;
3118   }
3119   histP = histIn;
3120 }
3121
3122 char *
3123 PrevInHistory(char *cmd)
3124 {
3125   int newhp;
3126   if (histP == histIn) {
3127     if (history[histIn] != NULL) free(history[histIn]);
3128     history[histIn] = StrSave(cmd);
3129   }
3130   newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
3131   if (newhp == histIn || history[newhp] == NULL) return NULL;
3132   histP = newhp;
3133   return history[histP];
3134 }
3135
3136 char *
3137 NextInHistory()
3138 {
3139   if (histP == histIn) return NULL;
3140   histP = (histP + 1) % HISTORY_SIZE;
3141   return history[histP];   
3142 }
3143 // end of borrowed code
3144
3145 #define Abs(n) ((n)<0 ? -(n) : (n))
3146
3147 #ifdef ENABLE_NLS
3148 char *
3149 InsertPxlSize(pattern, targetPxlSize)
3150      char *pattern;
3151      int targetPxlSize;
3152 {
3153     char *base_fnt_lst, strInt[12], *p, *q;
3154     int alternatives, i, len, strIntLen;
3155
3156     /*
3157      * Replace the "*" (if present) in the pixel-size slot of each
3158      * alternative with the targetPxlSize.
3159      */
3160     p = pattern;
3161     alternatives = 1;
3162     while ((p = strchr(p, ',')) != NULL) {
3163       alternatives++;
3164       p++;
3165     }
3166     snprintf(strInt, sizeof(strInt), "%d", targetPxlSize);
3167     strIntLen = strlen(strInt);
3168     base_fnt_lst = calloc(1, strlen(pattern) + strIntLen * alternatives + 1);
3169
3170     p = pattern;
3171     q = base_fnt_lst;
3172     while (alternatives--) {
3173       char *comma = strchr(p, ',');
3174       for (i=0; i<14; i++) {
3175         char *hyphen = strchr(p, '-');
3176         if (!hyphen) break;
3177         if (comma && hyphen > comma) break;
3178         len = hyphen + 1 - p;
3179         if (i == 7 && *p == '*' && len == 2) {
3180           p += len;
3181           memcpy(q, strInt, strIntLen);
3182           q += strIntLen;
3183           *q++ = '-';
3184         } else {
3185           memcpy(q, p, len);
3186           p += len;
3187           q += len;
3188         }
3189       }
3190       if (!comma) break;
3191       len = comma + 1 - p;
3192       memcpy(q, p, len);
3193       p += len;
3194       q += len;
3195     }
3196     strcpy(q, p);
3197
3198     return base_fnt_lst;
3199 }
3200
3201 XFontSet
3202 CreateFontSet(base_fnt_lst)
3203      char *base_fnt_lst;
3204 {
3205     XFontSet fntSet;
3206     char **missing_list;
3207     int missing_count;
3208     char *def_string;
3209
3210     fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
3211                             &missing_list, &missing_count, &def_string);
3212     if (appData.debugMode) {
3213       int i, count;
3214       XFontStruct **font_struct_list;
3215       char **font_name_list;
3216       fprintf(debugFP, "Requested font set for list %s\n", base_fnt_lst);
3217       if (fntSet) {
3218         fprintf(debugFP, " got list %s, locale %s\n",
3219                 XBaseFontNameListOfFontSet(fntSet),
3220                 XLocaleOfFontSet(fntSet));
3221         count = XFontsOfFontSet(fntSet, &font_struct_list, &font_name_list);
3222         for (i = 0; i < count; i++) {
3223           fprintf(debugFP, " got charset %s\n", font_name_list[i]);
3224         }
3225       }
3226       for (i = 0; i < missing_count; i++) {
3227         fprintf(debugFP, " missing charset %s\n", missing_list[i]);
3228       }
3229     }
3230     if (fntSet == NULL) {
3231       fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
3232       exit(2);
3233     }
3234     return fntSet;
3235 }
3236 #else // not ENABLE_NLS
3237 /*
3238  * Find a font that matches "pattern" that is as close as
3239  * possible to the targetPxlSize.  Prefer fonts that are k
3240  * pixels smaller to fonts that are k pixels larger.  The
3241  * pattern must be in the X Consortium standard format,
3242  * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3243  * The return value should be freed with XtFree when no
3244  * longer needed.
3245  */
3246 char *
3247 FindFont(pattern, targetPxlSize)
3248      char *pattern;
3249      int targetPxlSize;
3250 {
3251     char **fonts, *p, *best, *scalable, *scalableTail;
3252     int i, j, nfonts, minerr, err, pxlSize;
3253
3254     fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3255     if (nfonts < 1) {
3256         fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3257                 programName, pattern);
3258         exit(2);
3259     }
3260
3261     best = fonts[0];
3262     scalable = NULL;
3263     minerr = 999999;
3264     for (i=0; i<nfonts; i++) {
3265         j = 0;
3266         p = fonts[i];
3267         if (*p != '-') continue;
3268         while (j < 7) {
3269             if (*p == NULLCHAR) break;
3270             if (*p++ == '-') j++;
3271         }
3272         if (j < 7) continue;
3273         pxlSize = atoi(p);
3274         if (pxlSize == 0) {
3275             scalable = fonts[i];
3276             scalableTail = p;
3277         } else {
3278             err = pxlSize - targetPxlSize;
3279             if (Abs(err) < Abs(minerr) ||
3280                 (minerr > 0 && err < 0 && -err == minerr)) {
3281                 best = fonts[i];
3282                 minerr = err;
3283             }
3284         }
3285     }
3286     if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3287         /* If the error is too big and there is a scalable font,
3288            use the scalable font. */
3289         int headlen = scalableTail - scalable;
3290         p = (char *) XtMalloc(strlen(scalable) + 10);
3291         while (isdigit(*scalableTail)) scalableTail++;
3292         sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3293     } else {
3294         p = (char *) XtMalloc(strlen(best) + 2);
3295         safeStrCpy(p, best, strlen(best)+1 );
3296     }
3297     if (appData.debugMode) {
3298         fprintf(debugFP, _("resolved %s at pixel size %d\n  to %s\n"),
3299                 pattern, targetPxlSize, p);
3300     }
3301     XFreeFontNames(fonts);
3302     return p;
3303 }
3304 #endif
3305
3306 void DeleteGCs()
3307 {   // [HGM] deletes GCs that are to be remade, to prevent resource leak;
3308     // must be called before all non-first callse to CreateGCs()
3309     XtReleaseGC(shellWidget, highlineGC);
3310     XtReleaseGC(shellWidget, lightSquareGC);
3311     XtReleaseGC(shellWidget, darkSquareGC);
3312     XtReleaseGC(shellWidget, lineGC);
3313     if (appData.monoMode) {
3314         if (DefaultDepth(xDisplay, xScreen) == 1) {
3315             XtReleaseGC(shellWidget, wbPieceGC);
3316         } else {
3317             XtReleaseGC(shellWidget, bwPieceGC);
3318         }
3319     } else {
3320         XtReleaseGC(shellWidget, prelineGC);
3321         XtReleaseGC(shellWidget, jailSquareGC);
3322         XtReleaseGC(shellWidget, wdPieceGC);
3323         XtReleaseGC(shellWidget, wlPieceGC);
3324         XtReleaseGC(shellWidget, wjPieceGC);
3325         XtReleaseGC(shellWidget, bdPieceGC);
3326         XtReleaseGC(shellWidget, blPieceGC);
3327         XtReleaseGC(shellWidget, bjPieceGC);
3328     }
3329 }
3330
3331 void CreateGCs(int redo)
3332 {
3333     XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3334       | GCBackground | GCFunction | GCPlaneMask;
3335     XGCValues gc_values;
3336     GC copyInvertedGC;
3337
3338     gc_values.plane_mask = AllPlanes;
3339     gc_values.line_width = lineGap;
3340     gc_values.line_style = LineSolid;
3341     gc_values.function = GXcopy;
3342
3343   if(redo) {
3344     DeleteGCs(); // called a second time; clean up old GCs first
3345   } else { // [HGM] grid and font GCs created on first call only
3346     gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3347     gc_values.background = XWhitePixel(xDisplay, xScreen);
3348     coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3349     XSetFont(xDisplay, coordGC, coordFontID);
3350
3351     // [HGM] make font for holdings counts (white on black)
3352     gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3353     gc_values.background = XBlackPixel(xDisplay, xScreen);
3354     countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3355     XSetFont(xDisplay, countGC, countFontID);
3356   }
3357     gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3358     gc_values.background = XBlackPixel(xDisplay, xScreen);
3359     lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3360
3361     if (appData.monoMode) {
3362         gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3363         gc_values.background = XWhitePixel(xDisplay, xScreen);
3364         highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3365
3366         gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3367         gc_values.background = XBlackPixel(xDisplay, xScreen);
3368         lightSquareGC = wbPieceGC
3369           = XtGetGC(shellWidget, value_mask, &gc_values);
3370
3371         gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3372         gc_values.background = XWhitePixel(xDisplay, xScreen);
3373         darkSquareGC = bwPieceGC
3374           = XtGetGC(shellWidget, value_mask, &gc_values);
3375
3376         if (DefaultDepth(xDisplay, xScreen) == 1) {
3377             /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3378             gc_values.function = GXcopyInverted;
3379             copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3380             gc_values.function = GXcopy;
3381             if (XBlackPixel(xDisplay, xScreen) == 1) {
3382                 bwPieceGC = darkSquareGC;
3383                 wbPieceGC = copyInvertedGC;
3384             } else {
3385                 bwPieceGC = copyInvertedGC;
3386                 wbPieceGC = lightSquareGC;
3387             }
3388         }
3389     } else {
3390         gc_values.foreground = highlightSquareColor;
3391         gc_values.background = highlightSquareColor;
3392         highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3393
3394         gc_values.foreground = premoveHighlightColor;
3395         gc_values.background = premoveHighlightColor;
3396         prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3397
3398         gc_values.foreground = lightSquareColor;
3399         gc_values.background = darkSquareColor;
3400         lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3401
3402         gc_values.foreground = darkSquareColor;
3403         gc_values.background = lightSquareColor;
3404         darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3405
3406         gc_values.foreground = jailSquareColor;
3407         gc_values.background = jailSquareColor;
3408         jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3409
3410         gc_values.foreground = whitePieceColor;
3411         gc_values.background = darkSquareColor;
3412         wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3413
3414         gc_values.foreground = whitePieceColor;
3415         gc_values.background = lightSquareColor;
3416         wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3417
3418         gc_values.foreground = whitePieceColor;
3419         gc_values.background = jailSquareColor;
3420         wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3421
3422         gc_values.foreground = blackPieceColor;
3423         gc_values.background = darkSquareColor;
3424         bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3425
3426         gc_values.foreground = blackPieceColor;
3427         gc_values.background = lightSquareColor;
3428         blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3429
3430         gc_values.foreground = blackPieceColor;
3431         gc_values.background = jailSquareColor;
3432         bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3433     }
3434 }
3435
3436 void loadXIM(xim, xmask, filename, dest, mask)
3437      XImage *xim;
3438      XImage *xmask;
3439      char *filename;
3440      Pixmap *dest;
3441      Pixmap *mask;
3442 {
3443     int x, y, w, h, p;
3444     FILE *fp;
3445     Pixmap temp;
3446     XGCValues   values;
3447     GC maskGC;
3448
3449     fp = fopen(filename, "rb");
3450     if (!fp) {
3451         fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3452         exit(1);
3453     }
3454
3455     w = fgetc(fp);
3456     h = fgetc(fp);
3457
3458     for (y=0; y<h; ++y) {
3459         for (x=0; x<h; ++x) {
3460             p = fgetc(fp);
3461
3462             switch (p) {
3463               case 0:
3464                 XPutPixel(xim, x, y, blackPieceColor);
3465                 if (xmask)
3466                   XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3467                 break;
3468               case 1:
3469                 XPutPixel(xim, x, y, darkSquareColor);
3470                 if (xmask)
3471                   XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3472                 break;
3473               case 2:
3474                 XPutPixel(xim, x, y, whitePieceColor);
3475                 if (xmask)
3476                   XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3477                 break;
3478               case 3:
3479                 XPutPixel(xim, x, y, lightSquareColor);
3480                 if (xmask)
3481                   XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3482                 break;
3483             }
3484         }
3485     }
3486
3487     fclose(fp);
3488
3489     /* create Pixmap of piece */
3490     *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3491                           w, h, xim->depth);
3492     XPutImage(xDisplay, *dest, lightSquareGC, xim,
3493               0, 0, 0, 0, w, h);
3494
3495     /* create Pixmap of clipmask
3496        Note: We assume the white/black pieces have the same
3497              outline, so we make only 6 masks. This is okay
3498              since the XPM clipmask routines do the same. */
3499     if (xmask) {
3500       temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3501                             w, h, xim->depth);
3502       XPutImage(xDisplay, temp, lightSquareGC, xmask,
3503               0, 0, 0, 0, w, h);
3504
3505       /* now create the 1-bit version */
3506       *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3507                           w, h, 1);
3508
3509       values.foreground = 1;
3510       values.background = 0;
3511
3512       /* Don't use XtGetGC, not read only */
3513       maskGC = XCreateGC(xDisplay, *mask,
3514                     GCForeground | GCBackground, &values);
3515       XCopyPlane(xDisplay, temp, *mask, maskGC,
3516                   0, 0, squareSize, squareSize, 0, 0, 1);
3517       XFreePixmap(xDisplay, temp);
3518     }
3519 }
3520
3521
3522 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3523
3524 void CreateXIMPieces()
3525 {
3526     int piece, kind;
3527     char buf[MSG_SIZ];
3528     u_int ss;
3529     static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3530     XImage *ximtemp;
3531
3532     ss = squareSize;
3533
3534     /* The XSynchronize calls were copied from CreatePieces.
3535        Not sure if needed, but can't hurt */
3536     XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3537                                      buffering bug */
3538
3539     /* temp needed by loadXIM() */
3540     ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3541                  0, 0, ss, ss, AllPlanes, XYPixmap);
3542
3543     if (strlen(appData.pixmapDirectory) == 0) {
3544       useImages = 0;
3545     } else {
3546         useImages = 1;
3547         if (appData.monoMode) {
3548           DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3549                             0, 2);
3550           ExitEvent(2);
3551         }
3552         fprintf(stderr, _("\nLoading XIMs...\n"));
3553         /* Load pieces */
3554         for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3555             fprintf(stderr, "%d", piece+1);
3556             for (kind=0; kind<4; kind++) {
3557                 fprintf(stderr, ".");
3558                 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3559                         ExpandPathName(appData.pixmapDirectory),
3560                         piece <= (int) WhiteKing ? "" : "w",
3561                         pieceBitmapNames[piece],
3562                         ximkind[kind], ss);
3563                 ximPieceBitmap[kind][piece] =
3564                   XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3565                             0, 0, ss, ss, AllPlanes, XYPixmap);
3566                 if (appData.debugMode)
3567                   fprintf(stderr, _("(File:%s:) "), buf);
3568                 loadXIM(ximPieceBitmap[kind][piece],
3569                         ximtemp, buf,
3570                         &(xpmPieceBitmap2[kind][piece]),
3571                         &(ximMaskPm2[piece]));
3572                 if(piece <= (int)WhiteKing)
3573                     xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3574             }
3575             fprintf(stderr," ");
3576         }
3577         /* Load light and dark squares */
3578         /* If the LSQ and DSQ pieces don't exist, we will
3579            draw them with solid squares. */
3580         snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3581         if (access(buf, 0) != 0) {
3582             useImageSqs = 0;
3583         } else {
3584             useImageSqs = 1;
3585             fprintf(stderr, _("light square "));
3586             ximLightSquare=
3587               XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3588                         0, 0, ss, ss, AllPlanes, XYPixmap);
3589             if (appData.debugMode)
3590               fprintf(stderr, _("(File:%s:) "), buf);
3591
3592             loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3593             fprintf(stderr, _("dark square "));
3594             snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3595                     ExpandPathName(appData.pixmapDirectory), ss);
3596             if (appData.debugMode)
3597               fprintf(stderr, _("(File:%s:) "), buf);
3598             ximDarkSquare=
3599               XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3600                         0, 0, ss, ss, AllPlanes, XYPixmap);
3601             loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3602             xpmJailSquare = xpmLightSquare;
3603         }
3604         fprintf(stderr, _("Done.\n"));
3605     }
3606     XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3607 }
3608
3609 static VariantClass oldVariant = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
3610
3611 #if HAVE_LIBXPM
3612 void CreateXPMBoard(char *s, int kind)
3613 {
3614     XpmAttributes attr;
3615     attr.valuemask = 0;
3616     if(!appData.useBitmaps || s == NULL || *s == 0 || *s == '*') { useTexture &= ~(kind+1); return; }
3617     if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3618         useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3619     }
3620 }
3621
3622 void FreeXPMPieces()
3623 {   // [HGM] to prevent resoucre leak on calling CreaeXPMPieces() a second time,
3624     // thisroutine has to be called t free the old piece pixmaps
3625     int piece, kind;
3626     for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++)
3627         for (kind=0; kind<4; kind++) XFreePixmap(xDisplay, xpmPieceBitmap2[kind][piece]);
3628     if(useImageSqs) {
3629         XFreePixmap(xDisplay, xpmLightSquare);
3630         XFreePixmap(xDisplay, xpmDarkSquare);
3631     }
3632 }
3633
3634 void CreateXPMPieces()
3635 {
3636     int piece, kind, r;
3637     char buf[MSG_SIZ];
3638     u_int ss = squareSize;
3639     XpmAttributes attr;
3640     static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3641     XpmColorSymbol symbols[4];
3642     static int redo = False;
3643
3644     if(redo) FreeXPMPieces(); else redo = 1;
3645
3646     /* The XSynchronize calls were copied from CreatePieces.
3647        Not sure if needed, but can't hurt */
3648     XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3649
3650     /* Setup translations so piece colors match square colors */