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