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