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