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