removed Iconify function. Should be handled by the window manager.
[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 DisplayMove P((int moveNumber));
448 void DisplayTitle P((char *title));
449 void ICSInitScript P((void));
450 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
451 void ErrorPopUp P((char *title, char *text, int modal));
452 void ErrorPopDown P((void));
453 static char *ExpandPathName P((char *path));
454 static void CreateAnimVars P((void));
455 static void DragPieceMove P((int x, int y));
456 static void DrawDragPiece P((void));
457 char *ModeToWidgetName P((GameMode mode));
458 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
459 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
460 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
461 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
462 void OptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
463 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
464 void IcsTextProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
465 void LoadEngineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
466 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
467 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
468 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
469 void IcsOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
470 void SoundOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
471 void BoardOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
472 void LoadOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
473 void SaveOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
474 void EditBookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
475 void SelectMove P((Widget w, XEvent * event, String * params, Cardinal * nParams));
476 void GameListOptionsPopDown P(());
477 void GenericPopDown P(());
478 void update_ics_width P(());
479 int get_term_width P(());
480 int CopyMemoProc P(());
481 void DrawArrowHighlight P((int fromX, int fromY, int toX,int toY));
482 Boolean IsDrawArrowEnabled P(());
483
484 /*
485 * XBoard depends on Xt R4 or higher
486 */
487 int xtVersion = XtSpecificationRelease;
488
489 int xScreen;
490 Display *xDisplay;
491 Window xBoardWindow;
492 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
493   jailSquareColor, highlightSquareColor, premoveHighlightColor;
494 Pixel lowTimeWarningColor;
495 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
496   bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
497   wjPieceGC, bjPieceGC, prelineGC, countGC;
498 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
499 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
500   whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
501   commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
502   menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
503   ICSInputShell, fileNameShell, askQuestionShell;
504 Widget historyShell, evalGraphShell, gameListShell;
505 int hOffset; // [HGM] dual
506 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
507 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
508 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
509 #if ENABLE_NLS
510 XFontSet fontSet, clockFontSet;
511 #else
512 Font clockFontID;
513 XFontStruct *clockFontStruct;
514 #endif
515 Font coordFontID, countFontID;
516 XFontStruct *coordFontStruct, *countFontStruct;
517 XtAppContext appContext;
518 char *layoutName;
519 char *oldICSInteractionTitle;
520
521 FileProc fileProc;
522 char *fileOpenMode;
523 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
524
525 Position commentX = -1, commentY = -1;
526 Dimension commentW, commentH;
527 typedef unsigned int BoardSize;
528 BoardSize boardSize;
529 Boolean chessProgram;
530
531 int  minX, minY; // [HGM] placement: volatile limits on upper-left corner
532 int squareSize, smallLayout = 0, tinyLayout = 0,
533   marginW, marginH, // [HGM] for run-time resizing
534   fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
535   ICSInputBoxUp = False, askQuestionUp = False,
536   filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
537   errorUp = False, errorExitStatus = -1, lineGap, defaultLineGap;
538 Pixel timerForegroundPixel, timerBackgroundPixel;
539 Pixel buttonForegroundPixel, buttonBackgroundPixel;
540 char *chessDir, *programName, *programVersion,
541   *gameCopyFilename, *gamePasteFilename;
542 Boolean alwaysOnTop = False;
543 Boolean saveSettingsOnExit;
544 char *settingsFileName;
545 char *icsTextMenuString;
546 char *icsNames;
547 char *firstChessProgramNames;
548 char *secondChessProgramNames;
549
550 WindowPlacement wpMain;
551 WindowPlacement wpConsole;
552 WindowPlacement wpComment;
553 WindowPlacement wpMoveHistory;
554 WindowPlacement wpEvalGraph;
555 WindowPlacement wpEngineOutput;
556 WindowPlacement wpGameList;
557 WindowPlacement wpTags;
558
559 extern Widget shells[];
560 extern Boolean shellUp[];
561
562 #define SOLID 0
563 #define OUTLINE 1
564 Pixmap pieceBitmap[2][(int)BlackPawn];
565 Pixmap pieceBitmap2[2][(int)BlackPawn+4];       /* [HGM] pieces */
566 Pixmap xpmPieceBitmap[4][(int)BlackPawn];       /* LL, LD, DL, DD actually used*/
567 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4];    /* LL, LD, DL, DD set to select from */
568 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
569 Pixmap xpmBoardBitmap[2];
570 int useImages, useImageSqs, useTexture, textureW[2], textureH[2];
571 XImage *ximPieceBitmap[4][(int)BlackPawn+4];    /* LL, LD, DL, DD */
572 Pixmap ximMaskPm[(int)BlackPawn];               /* clipmasks, used for XIM pieces */
573 Pixmap ximMaskPm2[(int)BlackPawn+4];            /* clipmasks, used for XIM pieces */
574 XImage *ximLightSquare, *ximDarkSquare;
575 XImage *xim_Cross;
576
577 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
578 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
579
580 #define White(piece) ((int)(piece) < (int)BlackPawn)
581
582 /* Variables for doing smooth animation. This whole thing
583    would be much easier if the board was double-buffered,
584    but that would require a fairly major rewrite.       */
585
586 typedef struct {
587         Pixmap  saveBuf;
588         Pixmap  newBuf;
589         GC      blitGC, pieceGC, outlineGC;
590         XPoint  startSquare, prevFrame, mouseDelta;
591         int     startColor;
592         int     dragPiece;
593         Boolean dragActive;
594         int     startBoardX, startBoardY;
595     } AnimState;
596
597 /* There can be two pieces being animated at once: a player
598    can begin dragging a piece before the remote opponent has moved. */
599
600 static AnimState game, player;
601
602 /* Bitmaps for use as masks when drawing XPM pieces.
603    Need one for each black and white piece.             */
604 static Pixmap xpmMask[BlackKing + 1];
605
606 /* This magic number is the number of intermediate frames used
607    in each half of the animation. For short moves it's reduced
608    by 1. The total number of frames will be factor * 2 + 1.  */
609 #define kFactor    4
610
611 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
612
613 MenuItem fileMenu[] = {
614     {N_("New Game        Ctrl+N"),        "New Game", ResetProc},
615     {N_("New Shuffle Game ..."),          "New Shuffle Game", ShuffleMenuProc},
616     {N_("New Variant ...   Alt+Shift+V"), "New Variant", NewVariantProc},      // [HGM] variant: not functional yet
617     {"----", NULL, NothingProc},
618     {N_("Load Game       Ctrl+O"),        "Load Game", LoadGameProc},
619     {N_("Load Position    Ctrl+Shift+O"), "Load Position", LoadPositionProc},
620 //    {N_("Load Next Game"), "Load Next Game", LoadNextGameProc},
621 //    {N_("Load Previous Game"), "Load Previous Game", LoadPrevGameProc},
622 //    {N_("Reload Same Game"), "Reload Same Game", ReloadGameProc},
623     {N_("Next Position     Shift+PgDn"), "Load Next Position", LoadNextPositionProc},
624     {N_("Prev Position     Shift+PgUp"), "Load Previous Position", LoadPrevPositionProc},
625     {"----", NULL, NothingProc},
626 //    {N_("Reload Same Position"), "Reload Same Position", ReloadPositionProc},
627     {N_("Save Game       Ctrl+S"),        "Save Game", SaveGameProc},
628     {N_("Save Position    Ctrl+Shift+S"), "Save Position", SavePositionProc},
629     {"----", NULL, NothingProc},
630     {N_("Mail Move"),            "Mail Move", MailMoveProc},
631     {N_("Reload CMail Message"), "Reload CMail Message", ReloadCmailMsgProc},
632     {"----", NULL, NothingProc},
633     {N_("Quit                 Ctr+Q"), "Exit", QuitProc},
634     {NULL, NULL, NULL}
635 };
636
637 MenuItem editMenu[] = {
638     {N_("Copy Game    Ctrl+C"),        "Copy Game", CopyGameProc},
639     {N_("Copy Position Ctrl+Shift+C"), "Copy Position", CopyPositionProc},
640     {N_("Copy Game List"),        "Copy Game List", CopyGameListProc},
641     {"----", NULL, NothingProc},
642     {N_("Paste Game    Ctrl+V"),        "Paste Game", PasteGameProc},
643     {N_("Paste Position Ctrl+Shift+V"), "Paste Position", PastePositionProc},
644     {"----", NULL, NothingProc},
645     {N_("Edit Game      Ctrl+E"),        "Edit Game", EditGameProc},
646     {N_("Edit Position   Ctrl+Shift+E"), "Edit Position", EditPositionProc},
647     {N_("Edit Tags"),                    "Edit Tags", EditTagsProc},
648     {N_("Edit Comment"),                 "Edit Comment", EditCommentProc},
649     {N_("Edit Book"),                    "Edit Book", EditBookProc},
650     {"----", NULL, NothingProc},
651     {N_("Revert              Home"), "Revert", RevertProc},
652     {N_("Annotate"),                 "Annotate", AnnotateProc},
653     {N_("Truncate Game  End"),       "Truncate Game", TruncateGameProc},
654     {"----", NULL, NothingProc},
655     {N_("Backward         Alt+Left"),   "Backward", BackwardProc},
656     {N_("Forward           Alt+Right"), "Forward", ForwardProc},
657     {N_("Back to Start     Alt+Home"),  "Back to Start", ToStartProc},
658     {N_("Forward to End Alt+End"),      "Forward to End", ToEndProc},
659     {NULL, NULL, NULL}
660 };
661
662 MenuItem viewMenu[] = {
663     {N_("Flip View             F2"),         "Flip View", FlipViewProc},
664     {"----", NULL, NothingProc},
665     {N_("Engine Output      Alt+Shift+O"),   "Show Engine Output", EngineOutputProc},
666     {N_("Move History       Alt+Shift+H"),   "Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
667     {N_("Evaluation Graph  Alt+Shift+E"),    "Show Evaluation Graph", EvalGraphProc},
668     {N_("Game List            Alt+Shift+G"), "Show Game List", ShowGameListProc},
669     {N_("ICS text menu"), "ICStex", IcsTextProc},
670     {"----", NULL, NothingProc},
671     {N_("Tags"),             "Show Tags", EditTagsProc},
672     {N_("Comments"),         "Show Comments", EditCommentProc},
673     {N_("ICS Input Box"),    "ICS Input Box", IcsInputBoxProc},
674     {"----", NULL, NothingProc},
675     {N_("Board..."),          "Board Options", BoardOptionsProc},
676     {N_("Game List Tags..."), "Game List", GameListOptionsPopUp},
677     {NULL, NULL, NULL}
678 };
679
680 MenuItem modeMenu[] = {
681     {N_("Machine White  Ctrl+W"), "Machine White", MachineWhiteProc},
682     {N_("Machine Black  Ctrl+B"), "Machine Black", MachineBlackProc},
683     {N_("Two Machines   Ctrl+T"), "Two Machines", TwoMachinesProc},
684     {N_("Analysis Mode  Ctrl+A"), "Analysis Mode", AnalyzeModeProc},
685     {N_("Analyze Game   Ctrl+G"), "Analyze File", AnalyzeFileProc },
686     {N_("Edit Game         Ctrl+E"), "Edit Game", EditGameProc},
687     {N_("Edit Position      Ctrl+Shift+E"), "Edit Position", EditPositionProc},
688     {N_("Training"),      "Training", TrainingProc},
689     {N_("ICS Client"),    "ICS Client", IcsClientProc},
690     {"----", NULL, NothingProc},
691     {N_("Machine Match"),         "Machine Match", MatchProc},
692     {N_("Pause               Pause"),         "Pause", PauseProc},
693     {NULL, NULL, NULL}
694 };
695
696 MenuItem actionMenu[] = {
697     {N_("Accept             F3"), "Accept", AcceptProc},
698     {N_("Decline            F4"), "Decline", DeclineProc},
699     {N_("Rematch           F12"), "Rematch", RematchProc},
700     {"----", NULL, NothingProc},
701     {N_("Call Flag          F5"), "Call Flag", CallFlagProc},
702     {N_("Draw                F6"), "Draw", DrawProc},
703     {N_("Adjourn            F7"),  "Adjourn", AdjournProc},
704     {N_("Abort                F8"),"Abort", AbortProc},
705     {N_("Resign              F9"), "Resign", ResignProc},
706     {"----", NULL, NothingProc},
707     {N_("Stop Observing  F10"), "Stop Observing", StopObservingProc},
708     {N_("Stop Examining  F11"), "Stop Examining", StopExaminingProc},
709     {N_("Upload to Examine"),   "Upload to Examine", UploadProc},
710     {"----", NULL, NothingProc},
711     {N_("Adjudicate to White"), "Adjudicate to White", AdjuWhiteProc},
712     {N_("Adjudicate to Black"), "Adjudicate to Black", AdjuBlackProc},
713     {N_("Adjudicate Draw"),     "Adjudicate Draw", AdjuDrawProc},
714     {NULL, NULL, NULL}
715 };
716
717 MenuItem engineMenu[] = {
718     {N_("Load New Engine ..."), "Load Engine", LoadEngineProc},
719     {"----", NULL, NothingProc},
720     {N_("Engine #1 Settings ..."), "Engine #1 Settings", FirstSettingsProc},
721     {N_("Engine #2 Settings ..."), "Engine #2 Settings", SecondSettingsProc},
722     {"----", NULL, NothingProc},
723     {N_("Hint"), "Hint", HintProc},
724     {N_("Book"), "Book", BookProc},
725     {"----", NULL, NothingProc},
726     {N_("Move Now     Ctrl+M"),     "Move Now", MoveNowProc},
727     {N_("Retract Move  Ctrl+X"), "Retract Move", RetractMoveProc},
728     {NULL, NULL, NULL}
729 };
730
731 MenuItem optionsMenu[] = {
732 #define OPTIONSDIALOG
733 #ifdef OPTIONSDIALOG
734     {N_("General ..."), "General", OptionsProc},
735 #endif
736     {N_("Time Control ...       Alt+Shift+T"), "Time Control", TimeControlProc},
737     {N_("Common Engine ...  Alt+Shift+U"),     "Common Engine", UciMenuProc},
738     {N_("Adjudications ...      Alt+Shift+J"), "Adjudications", EngineMenuProc},
739     {N_("ICS ..."),    "ICS", IcsOptionsProc},
740     {N_("Match ..."), "Match", MatchOptionsProc},
741     {N_("Load Game ..."),    "Load Game", LoadOptionsProc},
742     {N_("Save Game ..."),    "Save Game", SaveOptionsProc},
743 //    {N_(" ..."),    "", OptionsProc},
744     {N_("Game List ..."),    "Game List", GameListOptionsPopUp},
745     {N_("Sounds ..."),    "Sounds", SoundOptionsProc},
746     {"----", NULL, NothingProc},
747 #ifndef OPTIONSDIALOG
748     {N_("Always Queen        Ctrl+Shift+Q"),   "Always Queen", AlwaysQueenProc},
749     {N_("Animate Dragging"), "Animate Dragging", AnimateDraggingProc},
750     {N_("Animate Moving      Ctrl+Shift+A"),   "Animate Moving", AnimateMovingProc},
751     {N_("Auto Flag               Ctrl+Shift+F"), "Auto Flag", AutoflagProc},
752     {N_("Auto Flip View"),   "Auto Flip View", AutoflipProc},
753     {N_("Blindfold"),        "Blindfold", BlindfoldProc},
754     {N_("Flash Moves"),      "Flash Moves", FlashMovesProc},
755 #if HIGHDRAG
756     {N_("Highlight Dragging"),    "Highlight Dragging", HighlightDraggingProc},
757 #endif
758     {N_("Highlight Last Move"),   "Highlight Last Move", HighlightLastMoveProc},
759     {N_("Highlight With Arrow"),  "Arrow", HighlightArrowProc},
760     {N_("Move Sound"),            "Move Sound", MoveSoundProc},
761 //    {N_("ICS Alarm"),             "ICS Alarm", IcsAlarmProc},
762     {N_("One-Click Moving"),      "OneClick", OneClickProc},
763     {N_("Periodic Updates"),      "Periodic Updates", PeriodicUpdatesProc},
764     {N_("Ponder Next Move  Ctrl+Shift+P"), "Ponder Next Move", PonderNextMoveProc},
765     {N_("Popup Exit Message"),    "Popup Exit Message", PopupExitMessageProc},
766     {N_("Popup Move Errors"),     "Popup Move Errors", PopupMoveErrorsProc},
767 //    {N_("Premove"),               "Premove", PremoveProc},
768     {N_("Show Coords"),           "Show Coords", ShowCoordsProc},
769     {N_("Hide Thinking        Ctrl+Shift+H"),   "Hide Thinking", HideThinkingProc},
770     {N_("Test Legality          Ctrl+Shift+L"), "Test Legality", TestLegalityProc},
771     {"----", NULL, NothingProc},
772 #endif
773     {N_("Save Settings Now"),     "Save Settings Now", SaveSettingsProc},
774     {N_("Save Settings on Exit"), "Save Settings on Exit", SaveOnExitProc},
775     {NULL, NULL, NULL}
776 };
777
778 MenuItem helpMenu[] = {
779     {N_("Info XBoard"),     "Info XBoard", InfoProc},
780     {N_("Man XBoard   F1"), "Man XBoard", ManProc},
781     {"----", NULL, NothingProc},
782     {N_("About XBoard"), "About XBoard", AboutProc},
783     {NULL, NULL, NULL}
784 };
785
786 Menu menuBar[] = {
787     {N_("File"),    "File", fileMenu},
788     {N_("Edit"),    "Edit", editMenu},
789     {N_("View"),    "View", viewMenu},
790     {N_("Mode"),    "Mode", modeMenu},
791     {N_("Action"),  "Action", actionMenu},
792     {N_("Engine"),  "Engine", engineMenu},
793     {N_("Options"), "Options", optionsMenu},
794     {N_("Help"),    "Help", helpMenu},
795     {NULL, NULL, NULL}
796 };
797
798 #define PAUSE_BUTTON "P"
799 MenuItem buttonBar[] = {
800     {"<<", "<<", ToStartProc},
801     {"<", "<", BackwardProc},
802     {N_(PAUSE_BUTTON), PAUSE_BUTTON, PauseProc},
803     {">", ">", ForwardProc},
804     {">>", ">>", ToEndProc},
805     {NULL, NULL, NULL}
806 };
807
808 #define PIECE_MENU_SIZE 18
809 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
810     { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
811       N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
812       N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
813       N_("Empty square"), N_("Clear board") },
814     { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
815       N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
816       N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
817       N_("Empty square"), N_("Clear board") }
818 };
819 /* must be in same order as pieceMenuStrings! */
820 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
821     { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
822         WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
823         WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
824         PromotePiece, DemotePiece, EmptySquare, ClearBoard },
825     { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
826         BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
827         BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
828         PromotePiece, DemotePiece, EmptySquare, ClearBoard },
829 };
830
831 #define DROP_MENU_SIZE 6
832 String dropMenuStrings[DROP_MENU_SIZE] = {
833     "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
834   };
835 /* must be in same order as dropMenuStrings! */
836 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
837     (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
838     WhiteRook, WhiteQueen
839 };
840
841 typedef struct {
842     char piece;
843     char* widget;
844 } DropMenuEnables;
845
846 DropMenuEnables dmEnables[] = {
847     { 'P', "Pawn" },
848     { 'N', "Knight" },
849     { 'B', "Bishop" },
850     { 'R', "Rook" },
851     { 'Q', "Queen" }
852 };
853
854 Arg shellArgs[] = {
855     { XtNwidth, 0 },
856     { XtNheight, 0 },
857     { XtNminWidth, 0 },
858     { XtNminHeight, 0 },
859     { XtNmaxWidth, 0 },
860     { XtNmaxHeight, 0 }
861 };
862
863 Arg layoutArgs[] = {
864     { XtNborderWidth, 0 },
865     { XtNdefaultDistance, 0 },
866 };
867
868 Arg formArgs[] = {
869     { XtNborderWidth, 0 },
870     { XtNresizable, (XtArgVal) True },
871 };
872
873 Arg boardArgs[] = {
874     { XtNborderWidth, 0 },
875     { XtNwidth, 0 },
876     { XtNheight, 0 }
877 };
878
879 Arg titleArgs[] = {
880     { XtNjustify, (XtArgVal) XtJustifyRight },
881     { XtNlabel, (XtArgVal) "..." },
882     { XtNresizable, (XtArgVal) True },
883     { XtNresize, (XtArgVal) False }
884 };
885
886 Arg messageArgs[] = {
887     { XtNjustify, (XtArgVal) XtJustifyLeft },
888     { XtNlabel, (XtArgVal) "..." },
889     { XtNresizable, (XtArgVal) True },
890     { XtNresize, (XtArgVal) False }
891 };
892
893 Arg timerArgs[] = {
894     { XtNborderWidth, 0 },
895     { XtNjustify, (XtArgVal) XtJustifyLeft }
896 };
897
898 XtResource clientResources[] = {
899     { "flashCount", "flashCount", XtRInt, sizeof(int),
900         XtOffset(AppDataPtr, flashCount), XtRImmediate,
901         (XtPointer) FLASH_COUNT  },
902 };
903
904 XrmOptionDescRec shellOptions[] = {
905     { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
906     { "-flash", "flashCount", XrmoptionNoArg, "3" },
907     { "-xflash", "flashCount", XrmoptionNoArg, "0" },
908 };
909
910 XtActionsRec boardActions[] = {
911     { "DrawPosition", DrawPositionProc },
912     { "HandleUserMove", HandleUserMove },
913     { "AnimateUserMove", AnimateUserMove },
914     { "HandlePV", HandlePV },
915     { "SelectPV", SelectPV },
916     { "StopPV", StopPV },
917     { "FileNameAction", FileNameAction },
918     { "AskQuestionProc", AskQuestionProc },
919     { "AskQuestionReplyAction", AskQuestionReplyAction },
920     { "PieceMenuPopup", PieceMenuPopup },
921     { "WhiteClock", WhiteClock },
922     { "BlackClock", BlackClock },
923     { "ResetProc", ResetProc },
924     { "NewVariantProc", NewVariantProc },
925     { "LoadGameProc", LoadGameProc },
926     { "LoadNextGameProc", LoadNextGameProc },
927     { "LoadPrevGameProc", LoadPrevGameProc },
928     { "LoadSelectedProc", LoadSelectedProc },
929     { "SetFilterProc", SetFilterProc },
930     { "ReloadGameProc", ReloadGameProc },
931     { "LoadPositionProc", LoadPositionProc },
932     { "LoadNextPositionProc", LoadNextPositionProc },
933     { "LoadPrevPositionProc", LoadPrevPositionProc },
934     { "ReloadPositionProc", ReloadPositionProc },
935     { "CopyPositionProc", CopyPositionProc },
936     { "PastePositionProc", PastePositionProc },
937     { "CopyGameProc", CopyGameProc },
938     { "CopyGameListProc", CopyGameListProc },
939     { "PasteGameProc", PasteGameProc },
940     { "SaveGameProc", SaveGameProc },
941     { "SavePositionProc", SavePositionProc },
942     { "MailMoveProc", MailMoveProc },
943     { "ReloadCmailMsgProc", ReloadCmailMsgProc },
944     { "QuitProc", QuitProc },
945     { "MachineWhiteProc", MachineWhiteProc },
946     { "MachineBlackProc", MachineBlackProc },
947     { "AnalysisModeProc", AnalyzeModeProc },
948     { "AnalyzeFileProc", AnalyzeFileProc },
949     { "TwoMachinesProc", TwoMachinesProc },
950     { "IcsClientProc", IcsClientProc },
951     { "EditGameProc", EditGameProc },
952     { "EditPositionProc", EditPositionProc },
953     { "TrainingProc", EditPositionProc },
954     { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
955     { "EvalGraphProc", EvalGraphProc},       // [HGM] Winboard_x avaluation graph window
956     { "ShowGameListProc", ShowGameListProc },
957     { "ShowMoveListProc", HistoryShowProc},
958     { "EditTagsProc", EditCommentProc },
959     { "EditBookProc", EditBookProc },
960     { "EditCommentProc", EditCommentProc },
961     { "IcsInputBoxProc", IcsInputBoxProc },
962     { "PauseProc", PauseProc },
963     { "AcceptProc", AcceptProc },
964     { "DeclineProc", DeclineProc },
965     { "RematchProc", RematchProc },
966     { "CallFlagProc", CallFlagProc },
967     { "DrawProc", DrawProc },
968     { "AdjournProc", AdjournProc },
969     { "AbortProc", AbortProc },
970     { "ResignProc", ResignProc },
971     { "AdjuWhiteProc", AdjuWhiteProc },
972     { "AdjuBlackProc", AdjuBlackProc },
973     { "AdjuDrawProc", AdjuDrawProc },
974     { "TypeInProc", TypeInProc },
975     { "EnterKeyProc", EnterKeyProc },
976     { "UpKeyProc", UpKeyProc },
977     { "DownKeyProc", DownKeyProc },
978     { "StopObservingProc", StopObservingProc },
979     { "StopExaminingProc", StopExaminingProc },
980     { "UploadProc", UploadProc },
981     { "BackwardProc", BackwardProc },
982     { "ForwardProc", ForwardProc },
983     { "ToStartProc", ToStartProc },
984     { "ToEndProc", ToEndProc },
985     { "RevertProc", RevertProc },
986     { "AnnotateProc", AnnotateProc },
987     { "TruncateGameProc", TruncateGameProc },
988     { "MoveNowProc", MoveNowProc },
989     { "RetractMoveProc", RetractMoveProc },
990     { "EngineMenuProc", (XtActionProc) EngineMenuProc },
991     { "UciMenuProc", (XtActionProc) UciMenuProc },
992     { "TimeControlProc", (XtActionProc) TimeControlProc },
993     { "FlipViewProc", FlipViewProc },
994     { "PonderNextMoveProc", PonderNextMoveProc },
995 #ifndef OPTIONSDIALOG
996     { "AlwaysQueenProc", AlwaysQueenProc },
997     { "AnimateDraggingProc", AnimateDraggingProc },
998     { "AnimateMovingProc", AnimateMovingProc },
999     { "AutoflagProc", AutoflagProc },
1000     { "AutoflipProc", AutoflipProc },
1001     { "BlindfoldProc", BlindfoldProc },
1002     { "FlashMovesProc", FlashMovesProc },
1003 #if HIGHDRAG
1004     { "HighlightDraggingProc", HighlightDraggingProc },
1005 #endif
1006     { "HighlightLastMoveProc", HighlightLastMoveProc },
1007 //    { "IcsAlarmProc", IcsAlarmProc },
1008     { "MoveSoundProc", MoveSoundProc },
1009     { "PeriodicUpdatesProc", PeriodicUpdatesProc },
1010     { "PopupExitMessageProc", PopupExitMessageProc },
1011     { "PopupMoveErrorsProc", PopupMoveErrorsProc },
1012 //    { "PremoveProc", PremoveProc },
1013     { "ShowCoordsProc", ShowCoordsProc },
1014     { "ShowThinkingProc", ShowThinkingProc },
1015     { "HideThinkingProc", HideThinkingProc },
1016     { "TestLegalityProc", TestLegalityProc },
1017 #endif
1018     { "SaveSettingsProc", SaveSettingsProc },
1019     { "SaveOnExitProc", SaveOnExitProc },
1020     { "InfoProc", InfoProc },
1021     { "ManProc", ManProc },
1022     { "HintProc", HintProc },
1023     { "BookProc", BookProc },
1024     { "AboutGameProc", AboutGameProc },
1025     { "AboutProc", AboutProc },
1026     { "DebugProc", DebugProc },
1027     { "NothingProc", NothingProc },
1028     { "CommentClick", (XtActionProc) CommentClick },
1029     { "CommentPopDown", (XtActionProc) CommentPopDown },
1030     { "TagsPopDown", (XtActionProc) TagsPopDown },
1031     { "ErrorPopDown", (XtActionProc) ErrorPopDown },
1032     { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
1033     { "FileNamePopDown", (XtActionProc) FileNamePopDown },
1034     { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
1035     { "GameListPopDown", (XtActionProc) GameListPopDown },
1036     { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
1037     { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1038     { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1039     { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1040     { "GenericPopDown", (XtActionProc) GenericPopDown },
1041     { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1042     { "SelectMove", (XtActionProc) SelectMove },
1043 };
1044
1045 char globalTranslations[] =
1046   ":<Key>F9: ResignProc() \n \
1047    :Ctrl<Key>n: ResetProc() \n \
1048    :Meta<Key>V: NewVariantProc() \n \
1049    :Ctrl<Key>o: LoadGameProc() \n \
1050    :Meta<Key>Next: LoadNextGameProc() \n \
1051    :Meta<Key>Prior: LoadPrevGameProc() \n \
1052    :Ctrl<Key>Down: LoadSelectedProc(3) \n \
1053    :Ctrl<Key>Up: LoadSelectedProc(-3) \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>g: 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>F1: ManProc() \n \
1110    :<Key>F2: FlipViewProc() \n \
1111    <KeyDown>.: BackwardProc() \n \
1112    <KeyUp>.: ForwardProc() \n \
1113    Shift<Key>1: AskQuestionProc(\"Direct command\",\
1114                                 \"Send to chess program:\",,1) \n \
1115    Shift<Key>2: AskQuestionProc(\"Direct command\",\
1116                                 \"Send to second chess program:\",,2) \n";
1117
1118 char boardTranslations[] =
1119    "<Btn1Down>: HandleUserMove(0) \n \
1120    Shift<Btn1Up>: HandleUserMove(1) \n \
1121    <Btn1Up>: HandleUserMove(0) \n \
1122    <Btn1Motion>: AnimateUserMove() \n \
1123    <Btn3Motion>: HandlePV() \n \
1124    <Btn3Up>: PieceMenuPopup(menuB) \n \
1125    Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1126                  PieceMenuPopup(menuB) \n \
1127    Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1128                  PieceMenuPopup(menuW) \n \
1129    Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1130                  PieceMenuPopup(menuW) \n \
1131    Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1132                  PieceMenuPopup(menuB) \n";
1133
1134 char whiteTranslations[] =
1135    "Shift<BtnDown>: WhiteClock(1)\n \
1136    <BtnDown>: WhiteClock(0)\n";
1137 char blackTranslations[] =
1138    "Shift<BtnDown>: BlackClock(1)\n \
1139    <BtnDown>: BlackClock(0)\n";
1140
1141 char ICSInputTranslations[] =
1142     "<Key>Up: UpKeyProc() \n "
1143     "<Key>Down: DownKeyProc() \n "
1144     "<Key>Return: EnterKeyProc() \n";
1145
1146 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1147 //             as the widget is destroyed before the up-click can call extend-end
1148 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1149
1150 String xboardResources[] = {
1151     "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1152     "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1153     "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1154     NULL
1155   };
1156
1157
1158 /* Max possible square size */
1159 #define MAXSQSIZE 256
1160
1161 static int xpm_avail[MAXSQSIZE];
1162
1163 #ifdef HAVE_DIR_STRUCT
1164
1165 /* Extract piece size from filename */
1166 static int
1167 xpm_getsize(name, len, ext)
1168      char *name;
1169      int len;
1170      char *ext;
1171 {
1172     char *p, *d;
1173     char buf[10];
1174
1175     if (len < 4)
1176       return 0;
1177
1178     if ((p=strchr(name, '.')) == NULL ||
1179         StrCaseCmp(p+1, ext) != 0)
1180       return 0;
1181
1182     p = name + 3;
1183     d = buf;
1184
1185     while (*p && isdigit(*p))
1186       *(d++) = *(p++);
1187
1188     *d = 0;
1189     return atoi(buf);
1190 }
1191
1192 /* Setup xpm_avail */
1193 static int
1194 xpm_getavail(dirname, ext)
1195      char *dirname;
1196      char *ext;
1197 {
1198     DIR *dir;
1199     struct dirent *ent;
1200     int  i;
1201
1202     for (i=0; i<MAXSQSIZE; ++i)
1203       xpm_avail[i] = 0;
1204
1205     if (appData.debugMode)
1206       fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1207
1208     dir = opendir(dirname);
1209     if (!dir)
1210       {
1211           fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1212                   programName, dirname);
1213           exit(1);
1214       }
1215
1216     while ((ent=readdir(dir)) != NULL) {
1217         i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1218         if (i > 0 && i < MAXSQSIZE)
1219           xpm_avail[i] = 1;
1220     }
1221
1222     closedir(dir);
1223
1224     return 0;
1225 }
1226
1227 void
1228 xpm_print_avail(fp, ext)
1229      FILE *fp;
1230      char *ext;
1231 {
1232     int i;
1233
1234     fprintf(fp, _("Available `%s' sizes:\n"), ext);
1235     for (i=1; i<MAXSQSIZE; ++i) {
1236         if (xpm_avail[i])
1237           printf("%d\n", i);
1238     }
1239 }
1240
1241 /* Return XPM piecesize closest to size */
1242 int
1243 xpm_closest_to(dirname, size, ext)
1244      char *dirname;
1245      int size;
1246      char *ext;
1247 {
1248     int i;
1249     int sm_diff = MAXSQSIZE;
1250     int sm_index = 0;
1251     int diff;
1252
1253     xpm_getavail(dirname, ext);
1254
1255     if (appData.debugMode)
1256       xpm_print_avail(stderr, ext);
1257
1258     for (i=1; i<MAXSQSIZE; ++i) {
1259         if (xpm_avail[i]) {
1260             diff = size - i;
1261             diff = (diff<0) ? -diff : diff;
1262             if (diff < sm_diff) {
1263                 sm_diff = diff;
1264                 sm_index = i;
1265             }
1266         }
1267     }
1268
1269     if (!sm_index) {
1270         fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1271         exit(1);
1272     }
1273
1274     return sm_index;
1275 }
1276 #else   /* !HAVE_DIR_STRUCT */
1277 /* If we are on a system without a DIR struct, we can't
1278    read the directory, so we can't collect a list of
1279    filenames, etc., so we can't do any size-fitting. */
1280 int
1281 xpm_closest_to(dirname, size, ext)
1282      char *dirname;
1283      int size;
1284      char *ext;
1285 {
1286     fprintf(stderr, _("\
1287 Warning: No DIR structure found on this system --\n\
1288          Unable to autosize for XPM/XIM pieces.\n\
1289    Please report this error to %s.\n\
1290    Include system type & operating system in message.\n"), PACKAGE_BUGREPORT););
1291     return size;
1292 }
1293 #endif /* HAVE_DIR_STRUCT */
1294
1295 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1296                              "magenta", "cyan", "white" };
1297 typedef struct {
1298     int attr, bg, fg;
1299 } TextColors;
1300 TextColors textColors[(int)NColorClasses];
1301
1302 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1303 static int
1304 parse_color(str, which)
1305      char *str;
1306      int which;
1307 {
1308     char *p, buf[100], *d;
1309     int i;
1310
1311     if (strlen(str) > 99)       /* watch bounds on buf */
1312       return -1;
1313
1314     p = str;
1315     d = buf;
1316     for (i=0; i<which; ++i) {
1317         p = strchr(p, ',');
1318         if (!p)
1319           return -1;
1320         ++p;
1321     }
1322
1323     /* Could be looking at something like:
1324        black, , 1
1325        .. in which case we want to stop on a comma also */
1326     while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1327       ++p;
1328
1329     if (*p == ',') {
1330         return -1;              /* Use default for empty field */
1331     }
1332
1333     if (which == 2 || isdigit(*p))
1334       return atoi(p);
1335
1336     while (*p && isalpha(*p))
1337       *(d++) = *(p++);
1338
1339     *d = 0;
1340
1341     for (i=0; i<8; ++i) {
1342         if (!StrCaseCmp(buf, cnames[i]))
1343           return which? (i+40) : (i+30);
1344     }
1345     if (!StrCaseCmp(buf, "default")) return -1;
1346
1347     fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1348     return -2;
1349 }
1350
1351 static int
1352 parse_cpair(cc, str)
1353      ColorClass cc;
1354      char *str;
1355 {
1356     if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1357         fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1358                 programName, str);
1359         return -1;
1360     }
1361
1362     /* bg and attr are optional */
1363     textColors[(int)cc].bg = parse_color(str, 1);
1364     if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1365         textColors[(int)cc].attr = 0;
1366     }
1367     return 0;
1368 }
1369
1370
1371 /* Arrange to catch delete-window events */
1372 Atom wm_delete_window;
1373 void
1374 CatchDeleteWindow(Widget w, String procname)
1375 {
1376   char buf[MSG_SIZ];
1377   XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1378   snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1379   XtAugmentTranslations(w, XtParseTranslationTable(buf));
1380 }
1381
1382 void
1383 BoardToTop()
1384 {
1385   Arg args[16];
1386   XtSetArg(args[0], XtNiconic, False);
1387   XtSetValues(shellWidget, args, 1);
1388
1389   XtPopup(shellWidget, XtGrabNone); /* Raise if lowered  */
1390 }
1391
1392 //---------------------------------------------------------------------------------------------------------
1393 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1394 #define XBOARD True
1395 #define JAWS_ARGS
1396 #define CW_USEDEFAULT (1<<31)
1397 #define ICS_TEXT_MENU_SIZE 90
1398 #define DEBUG_FILE "xboard.debug"
1399 #define SetCurrentDirectory chdir
1400 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1401 #define OPTCHAR "-"
1402 #define SEPCHAR " "
1403
1404 // these two must some day move to frontend.h, when they are implemented
1405 Boolean GameListIsUp();
1406
1407 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1408 #include "args.h"
1409
1410 // front-end part of option handling
1411
1412 // [HGM] This platform-dependent table provides the location for storing the color info
1413 extern char *crWhite, * crBlack;
1414
1415 void *
1416 colorVariable[] = {
1417   &appData.whitePieceColor,
1418   &appData.blackPieceColor,
1419   &appData.lightSquareColor,
1420   &appData.darkSquareColor,
1421   &appData.highlightSquareColor,
1422   &appData.premoveHighlightColor,
1423   &appData.lowTimeWarningColor,
1424   NULL,
1425   NULL,
1426   NULL,
1427   NULL,
1428   NULL,
1429   &crWhite,
1430   &crBlack,
1431   NULL
1432 };
1433
1434 // [HGM] font: keep a font for each square size, even non-stndard ones
1435 #define NUM_SIZES 18
1436 #define MAX_SIZE 130
1437 Boolean fontIsSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1438 char *fontTable[NUM_FONTS][MAX_SIZE];
1439
1440 void
1441 ParseFont(char *name, int number)
1442 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1443   int size;
1444   if(sscanf(name, "size%d:", &size)) {
1445     // [HGM] font: font is meant for specific boardSize (likely from settings file);
1446     //       defer processing it until we know if it matches our board size
1447     if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1448         fontTable[number][size] = strdup(strchr(name, ':')+1);
1449         fontValid[number][size] = True;
1450     }
1451     return;
1452   }
1453   switch(number) {
1454     case 0: // CLOCK_FONT
1455         appData.clockFont = strdup(name);
1456       break;
1457     case 1: // MESSAGE_FONT
1458         appData.font = strdup(name);
1459       break;
1460     case 2: // COORD_FONT
1461         appData.coordFont = strdup(name);
1462       break;
1463     default:
1464       return;
1465   }
1466   fontIsSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1467 }
1468
1469 void
1470 SetFontDefaults()
1471 { // only 2 fonts currently
1472   appData.clockFont = CLOCK_FONT_NAME;
1473   appData.coordFont = COORD_FONT_NAME;
1474   appData.font  =   DEFAULT_FONT_NAME;
1475 }
1476
1477 void
1478 CreateFonts()
1479 { // no-op, until we identify the code for this already in XBoard and move it here
1480 }
1481
1482 void
1483 ParseColor(int n, char *name)
1484 { // in XBoard, just copy the color-name string
1485   if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1486 }
1487
1488 void
1489 ParseTextAttribs(ColorClass cc, char *s)
1490 {
1491     (&appData.colorShout)[cc] = strdup(s);
1492 }
1493
1494 void
1495 ParseBoardSize(void *addr, char *name)
1496 {
1497     appData.boardSize = strdup(name);
1498 }
1499
1500 void
1501 LoadAllSounds()
1502 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1503 }
1504
1505 void
1506 SetCommPortDefaults()
1507 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1508 }
1509
1510 // [HGM] args: these three cases taken out to stay in front-end
1511 void
1512 SaveFontArg(FILE *f, ArgDescriptor *ad)
1513 {
1514   char *name;
1515   int i, n = (int)(intptr_t)ad->argLoc;
1516   switch(n) {
1517     case 0: // CLOCK_FONT
1518         name = appData.clockFont;
1519       break;
1520     case 1: // MESSAGE_FONT
1521         name = appData.font;
1522       break;
1523     case 2: // COORD_FONT
1524         name = appData.coordFont;
1525       break;
1526     default:
1527       return;
1528   }
1529   for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1530     if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1531         fontTable[n][squareSize] = strdup(name);
1532         fontValid[n][squareSize] = True;
1533         break;
1534   }
1535   for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1536     fprintf(f, OPTCHAR "%s" SEPCHAR "\"size%d:%s\"\n", ad->argName, i, fontTable[n][i]);
1537 }
1538
1539 void
1540 ExportSounds()
1541 { // nothing to do, as the sounds are at all times represented by their text-string names already
1542 }
1543
1544 void
1545 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1546 {       // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1547         fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
1548 }
1549
1550 void
1551 SaveColor(FILE *f, ArgDescriptor *ad)
1552 {       // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1553         if(colorVariable[(int)(intptr_t)ad->argLoc])
1554         fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
1555 }
1556
1557 void
1558 SaveBoardSize(FILE *f, char *name, void *addr)
1559 { // wrapper to shield back-end from BoardSize & sizeInfo
1560   fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1561 }
1562
1563 void
1564 ParseCommPortSettings(char *s)
1565 { // no such option in XBoard (yet)
1566 }
1567
1568 extern Widget engineOutputShell;
1569
1570 void
1571 GetActualPlacement(Widget wg, WindowPlacement *wp)
1572 {
1573   Arg args[16];
1574   Dimension w, h;
1575   Position x, y;
1576   int i;
1577
1578   if(!wg) return;
1579
1580     i = 0;
1581     XtSetArg(args[i], XtNx, &x); i++;
1582     XtSetArg(args[i], XtNy, &y); i++;
1583     XtSetArg(args[i], XtNwidth, &w); i++;
1584     XtSetArg(args[i], XtNheight, &h); i++;
1585     XtGetValues(wg, args, i);
1586     wp->x = x - 4;
1587     wp->y = y - 23;
1588     wp->height = h;
1589     wp->width = w;
1590 }
1591
1592 void
1593 GetWindowCoords()
1594 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1595   // In XBoard this will have to wait until awareness of window parameters is implemented
1596   GetActualPlacement(shellWidget, &wpMain);
1597   if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput);
1598   if(MoveHistoryIsUp()) GetActualPlacement(shells[7], &wpMoveHistory);
1599   if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1600   if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1601   if(shellUp[1]) GetActualPlacement(shells[1], &wpComment);
1602   if(shellUp[2]) GetActualPlacement(shells[2], &wpTags);
1603 }
1604
1605 void
1606 PrintCommPortSettings(FILE *f, char *name)
1607 { // This option does not exist in XBoard
1608 }
1609
1610 int
1611 MySearchPath(char *installDir, char *name, char *fullname)
1612 { // just append installDir and name. Perhaps ExpandPath should be used here?
1613   name = ExpandPathName(name);
1614   if(name && name[0] == '/')
1615     safeStrCpy(fullname, name, MSG_SIZ );
1616   else {
1617     sprintf(fullname, "%s%c%s", installDir, '/', name);
1618   }
1619   return 1;
1620 }
1621
1622 int
1623 MyGetFullPathName(char *name, char *fullname)
1624 { // should use ExpandPath?
1625   name = ExpandPathName(name);
1626   safeStrCpy(fullname, name, MSG_SIZ );
1627   return 1;
1628 }
1629
1630 void
1631 EnsureOnScreen(int *x, int *y, int minX, int minY)
1632 {
1633   return;
1634 }
1635
1636 int
1637 MainWindowUp()
1638 { // [HGM] args: allows testing if main window is realized from back-end
1639   return xBoardWindow != 0;
1640 }
1641
1642 void
1643 PopUpStartupDialog()
1644 {  // start menu not implemented in XBoard
1645 }
1646
1647 char *
1648 ConvertToLine(int argc, char **argv)
1649 {
1650   static char line[128*1024], buf[1024];
1651   int i;
1652
1653   line[0] = NULLCHAR;
1654   for(i=1; i<argc; i++)
1655     {
1656       if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') || argv[i][0] == NULLCHAR)
1657           && argv[i][0] != '{' )
1658         snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1659       else
1660         snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1661       strncat(line, buf, 128*1024 - strlen(line) - 1 );
1662     }
1663
1664   line[strlen(line)-1] = NULLCHAR;
1665   return line;
1666 }
1667
1668 //--------------------------------------------------------------------------------------------
1669
1670 extern Boolean twoBoards, partnerUp;
1671
1672 #ifdef IDSIZES
1673   // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1674 #else
1675 #define BoardSize int
1676 void InitDrawingSizes(BoardSize boardSize, int flags)
1677 {   // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1678     Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1679     Arg args[16];
1680     XtGeometryResult gres;
1681     int i;
1682     static Dimension oldWidth, oldHeight;
1683     static VariantClass oldVariant;
1684     static int oldDual = -1;
1685
1686     if(!formWidget) return;
1687
1688     if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1689     boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1690     boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1691
1692   if(boardWidth != oldWidth || boardHeight != oldHeight || oldDual != twoBoards) { // do resizing stuff only if size actually changed
1693     /*
1694      * Enable shell resizing.
1695      */
1696     shellArgs[0].value = (XtArgVal) &w;
1697     shellArgs[1].value = (XtArgVal) &h;
1698     XtGetValues(shellWidget, shellArgs, 2);
1699
1700     shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1701     shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1702     XtSetValues(shellWidget, &shellArgs[2], 4);
1703
1704     XtSetArg(args[0], XtNdefaultDistance, &sep);
1705     XtGetValues(formWidget, args, 1);
1706
1707     oldWidth = boardWidth; oldHeight = boardHeight; oldDual = twoBoards;
1708     CreateGrid();
1709     hOffset = boardWidth + 10;
1710     for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1711         secondSegments[i] = gridSegments[i];
1712         secondSegments[i].x1 += hOffset;
1713         secondSegments[i].x2 += hOffset;
1714     }
1715
1716     XtSetArg(args[0], XtNwidth, boardWidth);
1717     XtSetArg(args[1], XtNheight, boardHeight);
1718     XtSetValues(boardWidget, args, 2);
1719
1720     timerWidth = (boardWidth - sep) / 2;
1721     XtSetArg(args[0], XtNwidth, timerWidth);
1722     XtSetValues(whiteTimerWidget, args, 1);
1723     XtSetValues(blackTimerWidget, args, 1);
1724
1725     XawFormDoLayout(formWidget, False);
1726
1727     if (appData.titleInWindow) {
1728         i = 0;
1729         XtSetArg(args[i], XtNborderWidth, &bor); i++;
1730         XtSetArg(args[i], XtNheight, &h);  i++;
1731         XtGetValues(titleWidget, args, i);
1732         if (smallLayout) {
1733             w = boardWidth - 2*bor;
1734         } else {
1735             XtSetArg(args[0], XtNwidth, &w);
1736             XtGetValues(menuBarWidget, args, 1);
1737             w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1738         }
1739
1740         gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1741         if (gres != XtGeometryYes && appData.debugMode) {
1742             fprintf(stderr,
1743                     _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1744                     programName, gres, w, h, wr, hr);
1745         }
1746     }
1747
1748     XawFormDoLayout(formWidget, True);
1749
1750     /*
1751      * Inhibit shell resizing.
1752      */
1753     shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1754     shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1755     shellArgs[4].value = shellArgs[2].value = w;
1756     shellArgs[5].value = shellArgs[3].value = h;
1757     XtSetValues(shellWidget, &shellArgs[0], 6);
1758   }
1759
1760     // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1761     // (only for xpm)
1762
1763     if(gameInfo.variant == oldVariant) return; // and only if variant changed
1764
1765     if(useImages) {
1766       for(i=0; i<4; i++) {
1767         int p;
1768         for(p=0; p<=(int)WhiteKing; p++)
1769            xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1770         if(gameInfo.variant == VariantShogi) {
1771            xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1772            xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1773            xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1774            xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1775            xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1776         }
1777 #ifdef GOTHIC
1778         if(gameInfo.variant == VariantGothic) {
1779            xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1780         }
1781 #endif
1782         if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1783            xpmPieceBitmap[i][(int)WhiteAngel]    = xpmPieceBitmap2[i][(int)WhiteFalcon];
1784            xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1785         }
1786 #if !HAVE_LIBXPM
1787         // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1788         for(p=0; p<=(int)WhiteKing; p++)
1789            ximMaskPm[p] = ximMaskPm2[p]; // defaults
1790         if(gameInfo.variant == VariantShogi) {
1791            ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1792            ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1793            ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1794            ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1795            ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1796         }
1797 #ifdef GOTHIC
1798         if(gameInfo.variant == VariantGothic) {
1799            ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1800         }
1801 #endif
1802         if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1803            ximMaskPm[(int)WhiteAngel]    = ximMaskPm2[(int)WhiteFalcon];
1804            ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1805         }
1806 #endif
1807       }
1808     } else {
1809       for(i=0; i<2; i++) {
1810         int p;
1811         for(p=0; p<=(int)WhiteKing; p++)
1812            pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1813         if(gameInfo.variant == VariantShogi) {
1814            pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1815            pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1816            pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1817            pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1818            pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1819         }
1820 #ifdef GOTHIC
1821         if(gameInfo.variant == VariantGothic) {
1822            pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1823         }
1824 #endif
1825         if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1826            pieceBitmap[i][(int)WhiteAngel]    = pieceBitmap2[i][(int)WhiteFalcon];
1827            pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1828         }
1829       }
1830     }
1831 #if HAVE_LIBXPM
1832     CreateAnimVars();
1833 #endif
1834 }
1835 #endif
1836
1837 void ParseIcsTextColors()
1838 {   // [HGM] tken out of main(), so it can be called from ICS-Options dialog
1839     if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1840         parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1841         parse_cpair(ColorChannel1, appData.colorChannel1) < 0  ||
1842         parse_cpair(ColorChannel, appData.colorChannel) < 0  ||
1843         parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1844         parse_cpair(ColorTell, appData.colorTell) < 0 ||
1845         parse_cpair(ColorChallenge, appData.colorChallenge) < 0  ||
1846         parse_cpair(ColorRequest, appData.colorRequest) < 0  ||
1847         parse_cpair(ColorSeek, appData.colorSeek) < 0  ||
1848         parse_cpair(ColorNormal, appData.colorNormal) < 0)
1849       {
1850           if (appData.colorize) {
1851               fprintf(stderr,
1852                       _("%s: can't parse color names; disabling colorization\n"),
1853                       programName);
1854           }
1855           appData.colorize = FALSE;
1856       }
1857 }
1858
1859 int MakeColors()
1860 {   // [HGM] taken out of main(), so it can be called from BoardOptions dialog
1861     XrmValue vFrom, vTo;
1862     int forceMono = False;
1863
1864     if (!appData.monoMode) {
1865         vFrom.addr = (caddr_t) appData.lightSquareColor;
1866         vFrom.size = strlen(appData.lightSquareColor);
1867         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1868         if (vTo.addr == NULL) {
1869           appData.monoMode = True;
1870           forceMono = True;
1871         } else {
1872           lightSquareColor = *(Pixel *) vTo.addr;
1873         }
1874     }
1875     if (!appData.monoMode) {
1876         vFrom.addr = (caddr_t) appData.darkSquareColor;
1877         vFrom.size = strlen(appData.darkSquareColor);
1878         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1879         if (vTo.addr == NULL) {
1880           appData.monoMode = True;
1881           forceMono = True;
1882         } else {
1883           darkSquareColor = *(Pixel *) vTo.addr;
1884         }
1885     }
1886     if (!appData.monoMode) {
1887         vFrom.addr = (caddr_t) appData.whitePieceColor;
1888         vFrom.size = strlen(appData.whitePieceColor);
1889         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1890         if (vTo.addr == NULL) {
1891           appData.monoMode = True;
1892           forceMono = True;
1893         } else {
1894           whitePieceColor = *(Pixel *) vTo.addr;
1895         }
1896     }
1897     if (!appData.monoMode) {
1898         vFrom.addr = (caddr_t) appData.blackPieceColor;
1899         vFrom.size = strlen(appData.blackPieceColor);
1900         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1901         if (vTo.addr == NULL) {
1902           appData.monoMode = True;
1903           forceMono = True;
1904         } else {
1905           blackPieceColor = *(Pixel *) vTo.addr;
1906         }
1907     }
1908
1909     if (!appData.monoMode) {
1910         vFrom.addr = (caddr_t) appData.highlightSquareColor;
1911         vFrom.size = strlen(appData.highlightSquareColor);
1912         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1913         if (vTo.addr == NULL) {
1914           appData.monoMode = True;
1915           forceMono = True;
1916         } else {
1917           highlightSquareColor = *(Pixel *) vTo.addr;
1918         }
1919     }
1920
1921     if (!appData.monoMode) {
1922         vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1923         vFrom.size = strlen(appData.premoveHighlightColor);
1924         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1925         if (vTo.addr == NULL) {
1926           appData.monoMode = True;
1927           forceMono = True;
1928         } else {
1929           premoveHighlightColor = *(Pixel *) vTo.addr;
1930         }
1931     }
1932     return forceMono;
1933 }
1934
1935 void
1936 CreateAnyPieces()
1937 {   // [HGM] taken out of main
1938 #if HAVE_LIBXPM
1939     if (appData.monoMode && // [HGM] no sense to go on to certain doom
1940        (appData.bitmapDirectory == NULL || appData.bitmapDirectory[0] == NULLCHAR))
1941             appData.bitmapDirectory = DEF_BITMAP_DIR;
1942
1943     if (appData.bitmapDirectory[0] != NULLCHAR) {
1944       CreatePieces();
1945     } else {
1946       CreateXPMPieces();
1947       CreateXPMBoard(appData.liteBackTextureFile, 1);
1948       CreateXPMBoard(appData.darkBackTextureFile, 0);
1949     }
1950 #else
1951     CreateXIMPieces();
1952     /* Create regular pieces */
1953     if (!useImages) CreatePieces();
1954 #endif
1955 }
1956
1957 int
1958 main(argc, argv)
1959      int argc;
1960      char **argv;
1961 {
1962     int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1963     XSetWindowAttributes window_attributes;
1964     Arg args[16];
1965     Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1966     XrmValue vFrom, vTo;
1967     XtGeometryResult gres;
1968     char *p;
1969     XrmDatabase xdb;
1970     int forceMono = False;
1971
1972     srandom(time(0)); // [HGM] book: make random truly random
1973
1974     setbuf(stdout, NULL);
1975     setbuf(stderr, NULL);
1976     debugFP = stderr;
1977
1978     if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1979         printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1980         exit(0);
1981     }
1982
1983     programName = strrchr(argv[0], '/');
1984     if (programName == NULL)
1985       programName = argv[0];
1986     else
1987       programName++;
1988
1989 #ifdef ENABLE_NLS
1990     XtSetLanguageProc(NULL, NULL, NULL);
1991     bindtextdomain(PACKAGE, LOCALEDIR);
1992     textdomain(PACKAGE);
1993 #endif
1994
1995     shellWidget =
1996       XtAppInitialize(&appContext, "XBoard", shellOptions,
1997                       XtNumber(shellOptions),
1998                       &argc, argv, xboardResources, NULL, 0);
1999     appData.boardSize = "";
2000     InitAppData(ConvertToLine(argc, argv));
2001     p = getenv("HOME");
2002     if (p == NULL) p = "/tmp";
2003     i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
2004     gameCopyFilename = (char*) malloc(i);
2005     gamePasteFilename = (char*) malloc(i);
2006     snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
2007     snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
2008
2009     XtGetApplicationResources(shellWidget, (XtPointer) &appData,
2010                               clientResources, XtNumber(clientResources),
2011                               NULL, 0);
2012
2013     { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
2014         static char buf[MSG_SIZ];
2015         EscapeExpand(buf, appData.firstInitString);
2016         appData.firstInitString = strdup(buf);
2017         EscapeExpand(buf, appData.secondInitString);
2018         appData.secondInitString = strdup(buf);
2019         EscapeExpand(buf, appData.firstComputerString);
2020         appData.firstComputerString = strdup(buf);
2021         EscapeExpand(buf, appData.secondComputerString);
2022         appData.secondComputerString = strdup(buf);
2023     }
2024
2025     if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
2026         chessDir = ".";
2027     } else {
2028         if (chdir(chessDir) != 0) {
2029             fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
2030             perror(chessDir);
2031             exit(1);
2032         }
2033     }
2034
2035     if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
2036         /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
2037         if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL)  {
2038            printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
2039            exit(errno);
2040         }
2041         setbuf(debugFP, NULL);
2042     }
2043
2044 #if ENABLE_NLS
2045     if (appData.debugMode) {
2046       fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
2047     }
2048 #endif
2049
2050     /* [HGM,HR] make sure board size is acceptable */
2051     if(appData.NrFiles > BOARD_FILES ||
2052        appData.NrRanks > BOARD_RANKS   )
2053          DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
2054
2055 #if !HIGHDRAG
2056     /* This feature does not work; animation needs a rewrite */
2057     appData.highlightDragging = FALSE;
2058 #endif
2059     InitBackEnd1();
2060
2061     xDisplay = XtDisplay(shellWidget);
2062     xScreen = DefaultScreen(xDisplay);
2063     wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
2064
2065         gameInfo.variant = StringToVariant(appData.variant);
2066         InitPosition(FALSE);
2067
2068 #ifdef IDSIZE
2069     InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
2070 #else
2071     if (isdigit(appData.boardSize[0])) {
2072         i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
2073                    &lineGap, &clockFontPxlSize, &coordFontPxlSize,
2074                    &fontPxlSize, &smallLayout, &tinyLayout);
2075         if (i == 0) {
2076             fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
2077                     programName, appData.boardSize);
2078             exit(2);
2079         }
2080         if (i < 7) {
2081             /* Find some defaults; use the nearest known size */
2082             SizeDefaults *szd, *nearest;
2083             int distance = 99999;
2084             nearest = szd = sizeDefaults;
2085             while (szd->name != NULL) {
2086                 if (abs(szd->squareSize - squareSize) < distance) {
2087                     nearest = szd;
2088                     distance = abs(szd->squareSize - squareSize);
2089                     if (distance == 0) break;
2090                 }
2091                 szd++;
2092             }
2093             if (i < 2) lineGap = nearest->lineGap;
2094             if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
2095             if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
2096             if (i < 5) fontPxlSize = nearest->fontPxlSize;
2097             if (i < 6) smallLayout = nearest->smallLayout;
2098             if (i < 7) tinyLayout = nearest->tinyLayout;
2099         }
2100     } else {
2101         SizeDefaults *szd = sizeDefaults;
2102         if (*appData.boardSize == NULLCHAR) {
2103             while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
2104                    DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
2105               szd++;
2106             }
2107             if (szd->name == NULL) szd--;
2108             appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
2109         } else {
2110             while (szd->name != NULL &&
2111                    StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
2112             if (szd->name == NULL) {
2113                 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
2114                         programName, appData.boardSize);
2115                 exit(2);
2116             }
2117         }
2118         squareSize = szd->squareSize;
2119         lineGap = szd->lineGap;
2120         clockFontPxlSize = szd->clockFontPxlSize;
2121         coordFontPxlSize = szd->coordFontPxlSize;
2122         fontPxlSize = szd->fontPxlSize;
2123         smallLayout = szd->smallLayout;
2124         tinyLayout = szd->tinyLayout;
2125         // [HGM] font: use defaults from settings file if available and not overruled
2126     }
2127     if(!fontIsSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
2128         appData.clockFont = fontTable[CLOCK_FONT][squareSize];
2129     if(!fontIsSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
2130         appData.font = fontTable[MESSAGE_FONT][squareSize];
2131     if(!fontIsSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
2132         appData.coordFont = fontTable[COORD_FONT][squareSize];
2133
2134     /* Now, using squareSize as a hint, find a good XPM/XIM set size */
2135     if (strlen(appData.pixmapDirectory) > 0) {
2136         p = ExpandPathName(appData.pixmapDirectory);
2137         if (!p) {
2138             fprintf(stderr, _("Error expanding path name \"%s\"\n"),
2139                    appData.pixmapDirectory);
2140             exit(1);
2141         }
2142         if (appData.debugMode) {
2143           fprintf(stderr, _("\
2144 XBoard square size (hint): %d\n\
2145 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
2146         }
2147         squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
2148         if (appData.debugMode) {
2149             fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
2150         }
2151     }
2152     defaultLineGap = lineGap;
2153     if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
2154
2155     /* [HR] height treated separately (hacked) */
2156     boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
2157     boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
2158     if (appData.showJail == 1) {
2159         /* Jail on top and bottom */
2160         XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2161         XtSetArg(boardArgs[2], XtNheight,
2162                  boardHeight + 2*(lineGap + squareSize));
2163     } else if (appData.showJail == 2) {
2164         /* Jail on sides */
2165         XtSetArg(boardArgs[1], XtNwidth,
2166                  boardWidth + 2*(lineGap + squareSize));
2167         XtSetArg(boardArgs[2], XtNheight, boardHeight);
2168     } else {
2169         /* No jail */
2170         XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2171         XtSetArg(boardArgs[2], XtNheight, boardHeight);
2172     }
2173
2174     /*
2175      * Determine what fonts to use.
2176      */
2177 #if ENABLE_NLS
2178     appData.font = InsertPxlSize(appData.font, fontPxlSize);
2179     appData.clockFont = InsertPxlSize(appData.clockFont, clockFontPxlSize);
2180     appData.coordFont = InsertPxlSize(appData.coordFont, coordFontPxlSize);
2181     fontSet = CreateFontSet(appData.font);
2182     clockFontSet = CreateFontSet(appData.clockFont);
2183     {
2184       /* For the coordFont, use the 0th font of the fontset. */
2185       XFontSet coordFontSet = CreateFontSet(appData.coordFont);
2186       XFontStruct **font_struct_list;
2187       char **font_name_list;
2188       XFontsOfFontSet(coordFontSet, &font_struct_list, &font_name_list);
2189       coordFontID = XLoadFont(xDisplay, font_name_list[0]);
2190       coordFontStruct = XQueryFont(xDisplay, coordFontID);
2191     }
2192 #else
2193     appData.font = FindFont(appData.font, fontPxlSize);
2194     appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2195     appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2196     clockFontID = XLoadFont(xDisplay, appData.clockFont);
2197     clockFontStruct = XQueryFont(xDisplay, clockFontID);
2198     coordFontID = XLoadFont(xDisplay, appData.coordFont);
2199     coordFontStruct = XQueryFont(xDisplay, coordFontID);
2200 #endif
2201     countFontID = coordFontID;  // [HGM] holdings
2202     countFontStruct = coordFontStruct;
2203
2204     xdb = XtDatabase(xDisplay);
2205 #if ENABLE_NLS
2206     XrmPutLineResource(&xdb, "*international: True");
2207     vTo.size = sizeof(XFontSet);
2208     vTo.addr = (XtPointer) &fontSet;
2209     XrmPutResource(&xdb, "*fontSet", XtRFontSet, &vTo);
2210 #else
2211     XrmPutStringResource(&xdb, "*font", appData.font);
2212 #endif
2213
2214     /*
2215      * Detect if there are not enough colors available and adapt.
2216      */
2217     if (DefaultDepth(xDisplay, xScreen) <= 2) {
2218       appData.monoMode = True;
2219     }
2220
2221     forceMono = MakeColors();
2222
2223     if (forceMono) {
2224       fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2225               programName);
2226         appData.monoMode = True;
2227     }
2228
2229     if (appData.lowTimeWarning && !appData.monoMode) {
2230       vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2231       vFrom.size = strlen(appData.lowTimeWarningColor);
2232       XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2233       if (vTo.addr == NULL)
2234                 appData.monoMode = True;
2235       else
2236                 lowTimeWarningColor = *(Pixel *) vTo.addr;
2237     }
2238
2239     if (appData.monoMode && appData.debugMode) {
2240         fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2241                 (unsigned long) XWhitePixel(xDisplay, xScreen),
2242                 (unsigned long) XBlackPixel(xDisplay, xScreen));
2243     }
2244
2245     ParseIcsTextColors();
2246     textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2247     textColors[ColorNone].attr = 0;
2248
2249     XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2250
2251     /*
2252      * widget hierarchy
2253      */
2254     if (tinyLayout) {
2255         layoutName = "tinyLayout";
2256     } else if (smallLayout) {
2257         layoutName = "smallLayout";
2258     } else {
2259         layoutName = "normalLayout";
2260     }
2261     /* Outer layoutWidget is there only to provide a name for use in
2262        resources that depend on the layout style */
2263     layoutWidget =
2264       XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2265                             layoutArgs, XtNumber(layoutArgs));
2266     formWidget =
2267       XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2268                             formArgs, XtNumber(formArgs));
2269     XtSetArg(args[0], XtNdefaultDistance, &sep);
2270     XtGetValues(formWidget, args, 1);
2271
2272     j = 0;
2273     widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2274     XtSetArg(args[0], XtNtop,    XtChainTop);
2275     XtSetArg(args[1], XtNbottom, XtChainTop);
2276     XtSetArg(args[2], XtNright,  XtChainLeft);
2277     XtSetValues(menuBarWidget, args, 3);
2278
2279     widgetList[j++] = whiteTimerWidget =
2280       XtCreateWidget("whiteTime", labelWidgetClass,
2281                      formWidget, timerArgs, XtNumber(timerArgs));
2282 #if ENABLE_NLS
2283     XtSetArg(args[0], XtNfontSet, clockFontSet);
2284 #else
2285     XtSetArg(args[0], XtNfont, clockFontStruct);
2286 #endif
2287     XtSetArg(args[1], XtNtop,    XtChainTop);
2288     XtSetArg(args[2], XtNbottom, XtChainTop);
2289     XtSetValues(whiteTimerWidget, args, 3);
2290
2291     widgetList[j++] = blackTimerWidget =
2292       XtCreateWidget("blackTime", labelWidgetClass,
2293                      formWidget, timerArgs, XtNumber(timerArgs));
2294 #if ENABLE_NLS
2295     XtSetArg(args[0], XtNfontSet, clockFontSet);
2296 #else
2297     XtSetArg(args[0], XtNfont, clockFontStruct);
2298 #endif
2299     XtSetArg(args[1], XtNtop,    XtChainTop);
2300     XtSetArg(args[2], XtNbottom, XtChainTop);
2301     XtSetValues(blackTimerWidget, args, 3);
2302
2303     if (appData.titleInWindow) {
2304         widgetList[j++] = titleWidget =
2305           XtCreateWidget("title", labelWidgetClass, formWidget,
2306                          titleArgs, XtNumber(titleArgs));
2307         XtSetArg(args[0], XtNtop,    XtChainTop);
2308         XtSetArg(args[1], XtNbottom, XtChainTop);
2309         XtSetValues(titleWidget, args, 2);
2310     }
2311
2312     if (appData.showButtonBar) {
2313       widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2314       XtSetArg(args[0], XtNleft,  XtChainRight); // [HGM] glue to right window edge
2315       XtSetArg(args[1], XtNright, XtChainRight); //       for good run-time sizing
2316       XtSetArg(args[2], XtNtop,    XtChainTop);
2317       XtSetArg(args[3], XtNbottom, XtChainTop);
2318       XtSetValues(buttonBarWidget, args, 4);
2319     }
2320
2321     widgetList[j++] = messageWidget =
2322       XtCreateWidget("message", labelWidgetClass, formWidget,
2323                      messageArgs, XtNumber(messageArgs));
2324     XtSetArg(args[0], XtNtop,    XtChainTop);
2325     XtSetArg(args[1], XtNbottom, XtChainTop);
2326     XtSetValues(messageWidget, args, 2);
2327
2328     widgetList[j++] = boardWidget =
2329       XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2330                      XtNumber(boardArgs));
2331
2332     XtManageChildren(widgetList, j);
2333
2334     timerWidth = (boardWidth - sep) / 2;
2335     XtSetArg(args[0], XtNwidth, timerWidth);
2336     XtSetValues(whiteTimerWidget, args, 1);
2337     XtSetValues(blackTimerWidget, args, 1);
2338
2339     XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2340     XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2341     XtGetValues(whiteTimerWidget, args, 2);
2342
2343     if (appData.showButtonBar) {
2344       XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2345       XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2346       XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2347     }
2348
2349     /*
2350      * formWidget uses these constraints but they are stored
2351      * in the children.
2352      */
2353     i = 0;
2354     XtSetArg(args[i], XtNfromHoriz, 0); i++;
2355     XtSetValues(menuBarWidget, args, i);
2356     if (appData.titleInWindow) {
2357         if (smallLayout) {
2358             i = 0;
2359             XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2360             XtSetValues(whiteTimerWidget, args, i);
2361             i = 0;
2362             XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2363             XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2364             XtSetValues(blackTimerWidget, args, i);
2365             i = 0;
2366             XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2367             XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2368             XtSetValues(titleWidget, args, i);
2369             i = 0;
2370             XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2371             XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2372             XtSetValues(messageWidget, args, i);
2373             if (appData.showButtonBar) {
2374               i = 0;
2375               XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2376               XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2377               XtSetValues(buttonBarWidget, args, i);
2378             }
2379         } else {
2380             i = 0;
2381             XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2382             XtSetValues(whiteTimerWidget, args, i);
2383             i = 0;
2384             XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2385             XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2386             XtSetValues(blackTimerWidget, args, i);
2387             i = 0;
2388             XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2389             XtSetValues(titleWidget, args, i);
2390             i = 0;
2391             XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2392             XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2393             XtSetValues(messageWidget, args, i);
2394             if (appData.showButtonBar) {
2395               i = 0;
2396               XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2397               XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2398               XtSetValues(buttonBarWidget, args, i);
2399             }
2400         }
2401     } else {
2402         i = 0;
2403         XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2404         XtSetValues(whiteTimerWidget, args, i);
2405         i = 0;
2406         XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2407         XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2408         XtSetValues(blackTimerWidget, args, i);
2409         i = 0;
2410         XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2411         XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2412         XtSetValues(messageWidget, args, i);
2413         if (appData.showButtonBar) {
2414           i = 0;
2415           XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2416           XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2417           XtSetValues(buttonBarWidget, args, i);
2418         }
2419     }
2420     i = 0;
2421     XtSetArg(args[0], XtNfromVert, messageWidget);
2422     XtSetArg(args[1], XtNtop,    XtChainTop);
2423     XtSetArg(args[2], XtNbottom, XtChainBottom);
2424     XtSetArg(args[3], XtNleft,   XtChainLeft);
2425     XtSetArg(args[4], XtNright,  XtChainRight);
2426     XtSetValues(boardWidget, args, 5);
2427
2428     XtRealizeWidget(shellWidget);
2429
2430     if(wpMain.x > 0) {
2431       XtSetArg(args[0], XtNx, wpMain.x);
2432       XtSetArg(args[1], XtNy, wpMain.y);
2433       XtSetValues(shellWidget, args, 2);
2434     }
2435
2436     /*
2437      * Correct the width of the message and title widgets.
2438      * It is not known why some systems need the extra fudge term.
2439      * The value "2" is probably larger than needed.
2440      */
2441     XawFormDoLayout(formWidget, False);
2442
2443 #define WIDTH_FUDGE 2
2444     i = 0;
2445     XtSetArg(args[i], XtNborderWidth, &bor);  i++;
2446     XtSetArg(args[i], XtNheight, &h);  i++;
2447     XtGetValues(messageWidget, args, i);
2448     if (appData.showButtonBar) {
2449       i = 0;
2450       XtSetArg(args[i], XtNwidth, &w);  i++;
2451       XtGetValues(buttonBarWidget, args, i);
2452       w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2453     } else {
2454       w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2455     }
2456
2457     gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2458     if (gres != XtGeometryYes && appData.debugMode) {
2459       fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2460               programName, gres, w, h, wr, hr);
2461     }
2462
2463     /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2464     /* The size used for the child widget in layout lags one resize behind
2465        its true size, so we resize a second time, 1 pixel smaller.  Yeech! */
2466     w--;
2467     gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2468     if (gres != XtGeometryYes && appData.debugMode) {
2469       fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2470               programName, gres, w, h, wr, hr);
2471     }
2472     /* !! end hack */
2473     XtSetArg(args[0], XtNleft,  XtChainLeft);  // [HGM] glue ends for good run-time sizing
2474     XtSetArg(args[1], XtNright, XtChainRight);
2475     XtSetValues(messageWidget, args, 2);
2476
2477     if (appData.titleInWindow) {
2478         i = 0;
2479         XtSetArg(args[i], XtNborderWidth, &bor); i++;
2480         XtSetArg(args[i], XtNheight, &h);  i++;
2481         XtGetValues(titleWidget, args, i);
2482         if (smallLayout) {
2483             w = boardWidth - 2*bor;
2484         } else {
2485             XtSetArg(args[0], XtNwidth, &w);
2486             XtGetValues(menuBarWidget, args, 1);
2487             w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2488         }
2489
2490         gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2491         if (gres != XtGeometryYes && appData.debugMode) {
2492             fprintf(stderr,
2493                     _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2494                     programName, gres, w, h, wr, hr);
2495         }
2496     }
2497     XawFormDoLayout(formWidget, True);
2498
2499     xBoardWindow = XtWindow(boardWidget);
2500
2501     // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2502     //       not need to go into InitDrawingSizes().
2503 #endif
2504
2505     /*
2506      * Create X checkmark bitmap and initialize option menu checks.
2507      */
2508     ReadBitmap(&xMarkPixmap, "checkmark.bm",
2509                checkmark_bits, checkmark_width, checkmark_height);
2510     XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2511 #ifndef OPTIONSDIALOG
2512     if (appData.alwaysPromoteToQueen) {
2513         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2514                     args, 1);
2515     }
2516     if (appData.animateDragging) {
2517         XtSetValues(XtNameToWidget(menuBarWidget,
2518                                    "menuOptions.Animate Dragging"),
2519                     args, 1);
2520     }
2521     if (appData.animate) {
2522         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2523                     args, 1);
2524     }
2525     if (appData.autoCallFlag) {
2526         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2527                     args, 1);
2528     }
2529     if (appData.autoFlipView) {
2530         XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2531                     args, 1);
2532     }
2533     if (appData.blindfold) {
2534         XtSetValues(XtNameToWidget(menuBarWidget,
2535                                    "menuOptions.Blindfold"), args, 1);
2536     }
2537     if (appData.flashCount > 0) {
2538         XtSetValues(XtNameToWidget(menuBarWidget,
2539                                    "menuOptions.Flash Moves"),
2540                     args, 1);
2541     }
2542 #if HIGHDRAG
2543     if (appData.highlightDragging) {
2544         XtSetValues(XtNameToWidget(menuBarWidget,
2545                                    "menuOptions.Highlight Dragging"),
2546                     args, 1);
2547     }
2548 #endif
2549     if (appData.highlightLastMove) {
2550         XtSetValues(XtNameToWidget(menuBarWidget,
2551                                    "menuOptions.Highlight Last Move"),
2552                     args, 1);
2553     }
2554     if (appData.highlightMoveWithArrow) {
2555         XtSetValues(XtNameToWidget(menuBarWidget,
2556                                    "menuOptions.Arrow"),
2557                     args, 1);
2558     }
2559 //    if (appData.icsAlarm) {
2560 //      XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2561 //                  args, 1);
2562 //    }
2563     if (appData.ringBellAfterMoves) {
2564         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2565                     args, 1);
2566     }
2567     if (appData.oneClick) {
2568         XtSetValues(XtNameToWidget(menuBarWidget,
2569                                    "menuOptions.OneClick"), args, 1);
2570     }
2571     if (appData.periodicUpdates) {
2572         XtSetValues(XtNameToWidget(menuBarWidget,
2573                                    "menuOptions.Periodic Updates"), args, 1);
2574     }
2575     if (appData.ponderNextMove) {
2576         XtSetValues(XtNameToWidget(menuBarWidget,
2577                                    "menuOptions.Ponder Next Move"), args, 1);
2578     }
2579     if (appData.popupExitMessage) {
2580         XtSetValues(XtNameToWidget(menuBarWidget,
2581                                    "menuOptions.Popup Exit Message"), args, 1);
2582     }
2583     if (appData.popupMoveErrors) {
2584         XtSetValues(XtNameToWidget(menuBarWidget,
2585                                    "menuOptions.Popup Move Errors"), args, 1);
2586     }
2587 //    if (appData.premove) {
2588 //      XtSetValues(XtNameToWidget(menuBarWidget,
2589 //                                 "menuOptions.Premove"), args, 1);
2590 //    }
2591     if (appData.showCoords) {
2592         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2593                     args, 1);
2594     }
2595     if (appData.hideThinkingFromHuman) {
2596         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2597                     args, 1);
2598     }
2599     if (appData.testLegality) {
2600         XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2601                     args, 1);
2602     }
2603 #endif
2604     if (saveSettingsOnExit) {
2605         XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2606                     args, 1);
2607     }
2608
2609     /*
2610      * Create an icon.
2611      */
2612     ReadBitmap(&wIconPixmap, "icon_white.bm",
2613                icon_white_bits, icon_white_width, icon_white_height);
2614     ReadBitmap(&bIconPixmap, "icon_black.bm",
2615                icon_black_bits, icon_black_width, icon_black_height);
2616     iconPixmap = wIconPixmap;
2617     i = 0;
2618     XtSetArg(args[i], XtNiconPixmap, iconPixmap);  i++;
2619     XtSetValues(shellWidget, args, i);
2620
2621     /*
2622      * Create a cursor for the board widget.
2623      */
2624     window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2625     XChangeWindowAttributes(xDisplay, xBoardWindow,
2626                             CWCursor, &window_attributes);
2627
2628     /*
2629      * Inhibit shell resizing.
2630      */
2631     shellArgs[0].value = (XtArgVal) &w;
2632     shellArgs[1].value = (XtArgVal) &h;
2633     XtGetValues(shellWidget, shellArgs, 2);
2634     shellArgs[4].value = shellArgs[2].value = w;
2635     shellArgs[5].value = shellArgs[3].value = h;
2636     XtSetValues(shellWidget, &shellArgs[2], 4);
2637     marginW =  w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2638     marginH =  h - boardHeight;
2639
2640     CatchDeleteWindow(shellWidget, "QuitProc");
2641
2642     CreateGCs(False);
2643     CreateGrid();
2644     CreateAnyPieces();
2645
2646     CreatePieceMenus();
2647
2648     if (appData.animate || appData.animateDragging)
2649       CreateAnimVars();
2650
2651     XtAugmentTranslations(formWidget,
2652                           XtParseTranslationTable(globalTranslations));
2653     XtAugmentTranslations(boardWidget,
2654                           XtParseTranslationTable(boardTranslations));
2655     XtAugmentTranslations(whiteTimerWidget,
2656                           XtParseTranslationTable(whiteTranslations));
2657     XtAugmentTranslations(blackTimerWidget,
2658                           XtParseTranslationTable(blackTranslations));
2659
2660     /* Why is the following needed on some versions of X instead
2661      * of a translation? */
2662     XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2663                       (XtEventHandler) EventProc, NULL);
2664     /* end why */
2665     XtAddEventHandler(formWidget, KeyPressMask, False,
2666                       (XtEventHandler) MoveTypeInProc, NULL);
2667
2668     /* [AS] Restore layout */
2669     if( wpMoveHistory.visible ) {
2670       HistoryPopUp();
2671     }
2672
2673     if( wpEvalGraph.visible )
2674       {
2675         EvalGraphPopUp();
2676       };
2677
2678     if( wpEngineOutput.visible ) {
2679       EngineOutputPopUp();
2680     }
2681
2682     InitBackEnd2();
2683
2684     if (errorExitStatus == -1) {
2685         if (appData.icsActive) {
2686             /* We now wait until we see "login:" from the ICS before
2687                sending the logon script (problems with timestamp otherwise) */
2688             /*ICSInitScript();*/
2689             if (appData.icsInputBox) ICSInputBoxPopUp();
2690         }
2691
2692     #ifdef SIGWINCH
2693     signal(SIGWINCH, TermSizeSigHandler);
2694     #endif
2695         signal(SIGINT, IntSigHandler);
2696         signal(SIGTERM, IntSigHandler);
2697         if (*appData.cmailGameName != NULLCHAR) {
2698             signal(SIGUSR1, CmailSigHandler);
2699         }
2700     }
2701     gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2702     InitPosition(TRUE);
2703 //    XtSetKeyboardFocus(shellWidget, formWidget);
2704     XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
2705
2706     XtAppMainLoop(appContext);
2707     if (appData.debugMode) fclose(debugFP); // [DM] debug
2708     return 0;
2709 }
2710
2711 static Boolean noEcho;
2712
2713 void
2714 ShutDownFrontEnd()
2715 {
2716     if (appData.icsActive && oldICSInteractionTitle != NULL) {
2717         DisplayIcsInteractionTitle(oldICSInteractionTitle);
2718     }
2719     if (saveSettingsOnExit) SaveSettings(settingsFileName);
2720     unlink(gameCopyFilename);
2721     unlink(gamePasteFilename);
2722     if(noEcho) EchoOn();
2723 }
2724
2725 RETSIGTYPE TermSizeSigHandler(int sig)
2726 {
2727     update_ics_width();
2728 }
2729
2730 RETSIGTYPE
2731 IntSigHandler(sig)
2732      int sig;
2733 {
2734     ExitEvent(sig);
2735 }
2736
2737 RETSIGTYPE
2738 CmailSigHandler(sig)
2739      int sig;
2740 {
2741     int dummy = 0;
2742     int error;
2743
2744     signal(SIGUSR1, SIG_IGN);   /* suspend handler     */
2745
2746     /* Activate call-back function CmailSigHandlerCallBack()             */
2747     OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2748
2749     signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2750 }
2751
2752 void
2753 CmailSigHandlerCallBack(isr, closure, message, count, error)
2754      InputSourceRef isr;
2755      VOIDSTAR closure;
2756      char *message;
2757      int count;
2758      int error;
2759 {
2760     BoardToTop();
2761     ReloadCmailMsgEvent(TRUE);  /* Reload cmail msg  */
2762 }
2763 /**** end signal code ****/
2764
2765
2766 void
2767 ICSInitScript()
2768 {
2769   /* try to open the icsLogon script, either in the location given
2770    * or in the users HOME directory
2771    */
2772
2773   FILE *f;
2774   char buf[MSG_SIZ];
2775   char *homedir;
2776
2777   f = fopen(appData.icsLogon, "r");
2778   if (f == NULL)
2779     {
2780       homedir = getenv("HOME");
2781       if (homedir != NULL)
2782         {
2783           safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2784           strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2785           strncat(buf, appData.icsLogon,  MSG_SIZ - strlen(buf) - 1);
2786           f = fopen(buf, "r");
2787         }
2788     }
2789
2790   if (f != NULL)
2791     ProcessICSInitScript(f);
2792   else
2793     printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2794
2795   return;
2796 }
2797
2798 void
2799 ResetFrontEnd()
2800 {
2801     CommentPopDown();
2802     TagsPopDown();
2803     return;
2804 }
2805
2806 typedef struct {
2807     char *name;
2808     Boolean value;
2809 } Enables;
2810
2811 void
2812 GreyRevert(grey)
2813      Boolean grey;
2814 {
2815     Widget w;
2816     if (!menuBarWidget) return;
2817     w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2818     if (w == NULL) {
2819       DisplayError("menuEdit.Revert", 0);
2820     } else {
2821       XtSetSensitive(w, !grey);
2822     }
2823     w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2824     if (w == NULL) {
2825       DisplayError("menuEdit.Annotate", 0);
2826     } else {
2827       XtSetSensitive(w, !grey);
2828     }
2829 }
2830
2831 void
2832 SetMenuEnables(enab)
2833      Enables *enab;
2834 {
2835   Widget w;
2836   if (!menuBarWidget) return;
2837   while (enab->name != NULL) {
2838     w = XtNameToWidget(menuBarWidget, enab->name);
2839     if (w == NULL) {
2840       DisplayError(enab->name, 0);
2841     } else {
2842       XtSetSensitive(w, enab->value);
2843     }
2844     enab++;
2845   }
2846 }
2847
2848 Enables icsEnables[] = {
2849     { "menuFile.Mail Move", False },
2850     { "menuFile.Reload CMail Message", False },
2851     { "menuMode.Machine Black", False },
2852     { "menuMode.Machine White", False },
2853     { "menuMode.Analysis Mode", False },
2854     { "menuMode.Analyze File", False },
2855     { "menuMode.Two Machines", False },
2856     { "menuMode.Machine Match", False },
2857 #ifndef ZIPPY
2858     { "menuEngine.Hint", False },
2859     { "menuEngine.Book", False },
2860     { "menuEngine.Move Now", False },
2861 #ifndef OPTIONSDIALOG
2862     { "menuOptions.Periodic Updates", False },
2863     { "menuOptions.Hide Thinking", False },
2864     { "menuOptions.Ponder Next Move", False },
2865 #endif
2866 #endif
2867     { "menuEngine.Engine #1 Settings", False },
2868     { "menuEngine.Engine #2 Settings", False },
2869     { "menuEngine.Load Engine", False },
2870     { "menuEdit.Annotate", False },
2871     { "menuOptions.Match", False },
2872     { NULL, False }
2873 };
2874
2875 Enables ncpEnables[] = {
2876     { "menuFile.Mail Move", False },
2877     { "menuFile.Reload CMail Message", False },
2878     { "menuMode.Machine White", False },
2879     { "menuMode.Machine Black", False },
2880     { "menuMode.Analysis Mode", False },
2881     { "menuMode.Analyze File", False },
2882     { "menuMode.Two Machines", False },
2883     { "menuMode.Machine Match", False },
2884     { "menuMode.ICS Client", False },
2885     { "menuView.ICStex", False },
2886     { "menuView.ICS Input Box", False },
2887     { "Action", False },
2888     { "menuEdit.Revert", False },
2889     { "menuEdit.Annotate", False },
2890     { "menuEngine.Engine #1 Settings", False },
2891     { "menuEngine.Engine #2 Settings", False },
2892     { "menuEngine.Move Now", False },
2893     { "menuEngine.Retract Move", False },
2894     { "menuOptions.ICS", False },
2895 #ifndef OPTIONSDIALOG
2896     { "menuOptions.Auto Flag", False },
2897     { "menuOptions.Auto Flip View", False },
2898 //    { "menuOptions.ICS Alarm", False },
2899     { "menuOptions.Move Sound", False },
2900     { "menuOptions.Hide Thinking", False },
2901     { "menuOptions.Periodic Updates", False },
2902     { "menuOptions.Ponder Next Move", False },
2903 #endif
2904     { "menuEngine.Hint", False },
2905     { "menuEngine.Book", False },
2906     { NULL, False }
2907 };
2908
2909 Enables gnuEnables[] = {
2910     { "menuMode.ICS Client", False },
2911     { "menuView.ICStex", False },
2912     { "menuView.ICS Input Box", False },
2913     { "menuAction.Accept", False },
2914     { "menuAction.Decline", False },
2915     { "menuAction.Rematch", False },
2916     { "menuAction.Adjourn", False },
2917     { "menuAction.Stop Examining", False },
2918     { "menuAction.Stop Observing", False },
2919     { "menuAction.Upload to Examine", False },
2920     { "menuEdit.Revert", False },
2921     { "menuEdit.Annotate", False },
2922     { "menuOptions.ICS", False },
2923
2924     /* The next two options rely on SetCmailMode being called *after*    */
2925     /* SetGNUMode so that when GNU is being used to give hints these     */
2926     /* menu options are still available                                  */
2927
2928     { "menuFile.Mail Move", False },
2929     { "menuFile.Reload CMail Message", False },
2930     // [HGM] The following have been added to make a switch from ncp to GNU mode possible
2931     { "menuMode.Machine White", True },
2932     { "menuMode.Machine Black", True },
2933     { "menuMode.Analysis Mode", True },
2934     { "menuMode.Analyze File", True },
2935     { "menuMode.Two Machines", True },
2936     { "menuMode.Machine Match", True },
2937     { "menuEngine.Engine #1 Settings", True },
2938     { "menuEngine.Engine #2 Settings", True },
2939     { "menuEngine.Hint", True },
2940     { "menuEngine.Book", True },
2941     { "menuEngine.Move Now", True },
2942     { "menuEngine.Retract Move", True },
2943     { "Action", True },
2944     { NULL, False }
2945 };
2946
2947 Enables cmailEnables[] = {
2948     { "Action", True },
2949     { "menuAction.Call Flag", False },
2950     { "menuAction.Draw", True },
2951     { "menuAction.Adjourn", False },
2952     { "menuAction.Abort", False },
2953     { "menuAction.Stop Observing", False },
2954     { "menuAction.Stop Examining", False },
2955     { "menuFile.Mail Move", True },
2956     { "menuFile.Reload CMail Message", True },
2957     { NULL, False }
2958 };
2959
2960 Enables trainingOnEnables[] = {
2961   { "menuMode.Edit Comment", False },
2962   { "menuMode.Pause", False },
2963   { "menuEdit.Forward", False },
2964   { "menuEdit.Backward", False },
2965   { "menuEdit.Forward to End", False },
2966   { "menuEdit.Back to Start", False },
2967   { "menuEngine.Move Now", False },
2968   { "menuEdit.Truncate Game", False },
2969   { NULL, False }
2970 };
2971
2972 Enables trainingOffEnables[] = {
2973   { "menuMode.Edit Comment", True },
2974   { "menuMode.Pause", True },
2975   { "menuEdit.Forward", True },
2976   { "menuEdit.Backward", True },
2977   { "menuEdit.Forward to End", True },
2978   { "menuEdit.Back to Start", True },
2979   { "menuEngine.Move Now", True },
2980   { "menuEdit.Truncate Game", True },
2981   { NULL, False }
2982 };
2983
2984 Enables machineThinkingEnables[] = {
2985   { "menuFile.Load Game", False },
2986 //  { "menuFile.Load Next Game", False },
2987 //  { "menuFile.Load Previous Game", False },
2988 //  { "menuFile.Reload Same Game", False },
2989   { "menuEdit.Paste Game", False },
2990   { "menuFile.Load Position", False },
2991 //  { "menuFile.Load Next Position", False },
2992 //  { "menuFile.Load Previous Position", False },
2993 //  { "menuFile.Reload Same Position", False },
2994   { "menuEdit.Paste Position", False },
2995   { "menuMode.Machine White", False },
2996   { "menuMode.Machine Black", False },
2997   { "menuMode.Two Machines", False },
2998 //  { "menuMode.Machine Match", False },
2999   { "menuEngine.Retract Move", False },
3000   { NULL, False }
3001 };
3002
3003 Enables userThinkingEnables[] = {
3004   { "menuFile.Load Game", True },
3005 //  { "menuFile.Load Next Game", True },
3006 //  { "menuFile.Load Previous Game", True },
3007 //  { "menuFile.Reload Same Game", True },
3008   { "menuEdit.Paste Game", True },
3009   { "menuFile.Load Position", True },
3010 //  { "menuFile.Load Next Position", True },
3011 //  { "menuFile.Load Previous Position", True },
3012 //  { "menuFile.Reload Same Position", True },
3013   { "menuEdit.Paste Position", True },
3014   { "menuMode.Machine White", True },
3015   { "menuMode.Machine Black", True },
3016   { "menuMode.Two Machines", True },
3017 //  { "menuMode.Machine Match", True },
3018   { "menuEngine.Retract Move", True },
3019   { NULL, False }
3020 };
3021
3022 void SetICSMode()
3023 {
3024   SetMenuEnables(icsEnables);
3025
3026 #if ZIPPY
3027   if (appData.zippyPlay && !appData.noChessProgram) { /* [DM] icsEngineAnalyze */
3028      XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
3029      XtSetSensitive(XtNameToWidget(menuBarWidget, "menuEngine.Engine #1 Settings"), True);
3030   }
3031 #endif
3032 }
3033
3034 void
3035 SetNCPMode()
3036 {
3037   SetMenuEnables(ncpEnables);
3038 }
3039
3040 void
3041 SetGNUMode()
3042 {
3043   SetMenuEnables(gnuEnables);
3044 }
3045
3046 void
3047 SetCmailMode()
3048 {
3049   SetMenuEnables(cmailEnables);
3050 }
3051
3052 void
3053 SetTrainingModeOn()
3054 {
3055   SetMenuEnables(trainingOnEnables);
3056   if (appData.showButtonBar) {
3057     XtSetSensitive(buttonBarWidget, False);
3058   }
3059   CommentPopDown();
3060 }
3061
3062 void
3063 SetTrainingModeOff()
3064 {
3065   SetMenuEnables(trainingOffEnables);
3066   if (appData.showButtonBar) {
3067     XtSetSensitive(buttonBarWidget, True);
3068   }
3069 }
3070
3071 void
3072 SetUserThinkingEnables()
3073 {
3074   if (appData.noChessProgram) return;
3075   SetMenuEnables(userThinkingEnables);
3076 }
3077
3078 void
3079 SetMachineThinkingEnables()
3080 {
3081   if (appData.noChessProgram) return;
3082   SetMenuEnables(machineThinkingEnables);
3083   switch (gameMode) {
3084   case MachinePlaysBlack:
3085   case MachinePlaysWhite:
3086   case TwoMachinesPlay:
3087     XtSetSensitive(XtNameToWidget(menuBarWidget,
3088                                   ModeToWidgetName(gameMode)), True);
3089     break;
3090   default:
3091     break;
3092   }
3093 }
3094
3095 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
3096 #define HISTORY_SIZE 64
3097 static char *history[HISTORY_SIZE];
3098 int histIn = 0, histP = 0;
3099
3100 void
3101 SaveInHistory(char *cmd)
3102 {
3103   if (history[histIn] != NULL) {
3104     free(history[histIn]);
3105     history[histIn] = NULL;
3106   }
3107   if (*cmd == NULLCHAR) return;
3108   history[histIn] = StrSave(cmd);
3109   histIn = (histIn + 1) % HISTORY_SIZE;
3110   if (history[histIn] != NULL) {
3111     free(history[histIn]);
3112     history[histIn] = NULL;
3113   }
3114   histP = histIn;
3115 }
3116
3117 char *
3118 PrevInHistory(char *cmd)
3119 {
3120   int newhp;
3121   if (histP == histIn) {
3122     if (history[histIn] != NULL) free(history[histIn]);
3123     history[histIn] = StrSave(cmd);
3124   }
3125   newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
3126   if (newhp == histIn || history[newhp] == NULL) return NULL;
3127   histP = newhp;
3128   return history[histP];
3129 }
3130
3131 char *
3132 NextInHistory()
3133 {
3134   if (histP == histIn) return NULL;
3135   histP = (histP + 1) % HISTORY_SIZE;
3136   return history[histP];   
3137 }
3138 // end of borrowed code
3139
3140 #define Abs(n) ((n)<0 ? -(n) : (n))
3141
3142 #ifdef ENABLE_NLS
3143 char *
3144 InsertPxlSize(pattern, targetPxlSize)
3145      char *pattern;
3146      int targetPxlSize;
3147 {
3148     char *base_fnt_lst, strInt[12], *p, *q;
3149     int alternatives, i, len, strIntLen;
3150
3151     /*
3152      * Replace the "*" (if present) in the pixel-size slot of each
3153      * alternative with the targetPxlSize.
3154      */
3155     p = pattern;
3156     alternatives = 1;
3157     while ((p = strchr(p, ',')) != NULL) {
3158       alternatives++;
3159       p++;
3160     }
3161     snprintf(strInt, sizeof(strInt), "%d", targetPxlSize);
3162     strIntLen = strlen(strInt);
3163     base_fnt_lst = calloc(1, strlen(pattern) + strIntLen * alternatives + 1);
3164
3165     p = pattern;
3166     q = base_fnt_lst;
3167     while (alternatives--) {
3168       char *comma = strchr(p, ',');
3169       for (i=0; i<14; i++) {
3170         char *hyphen = strchr(p, '-');
3171         if (!hyphen) break;
3172         if (comma && hyphen > comma) break;
3173         len = hyphen + 1 - p;
3174         if (i == 7 && *p == '*' && len == 2) {
3175           p += len;
3176           memcpy(q, strInt, strIntLen);
3177           q += strIntLen;
3178           *q++ = '-';
3179         } else {
3180           memcpy(q, p, len);
3181           p += len;
3182           q += len;
3183         }
3184       }
3185       if (!comma) break;
3186       len = comma + 1 - p;
3187       memcpy(q, p, len);
3188       p += len;
3189       q += len;
3190     }
3191     strcpy(q, p);
3192
3193     return base_fnt_lst;
3194 }
3195
3196 XFontSet
3197 CreateFontSet(base_fnt_lst)
3198      char *base_fnt_lst;
3199 {
3200     XFontSet fntSet;
3201     char **missing_list;
3202     int missing_count;
3203     char *def_string;
3204
3205     fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
3206                             &missing_list, &missing_count, &def_string);
3207     if (appData.debugMode) {
3208       int i, count;
3209       XFontStruct **font_struct_list;
3210       char **font_name_list;
3211       fprintf(debugFP, "Requested font set for list %s\n", base_fnt_lst);
3212       if (fntSet) {
3213         fprintf(debugFP, " got list %s, locale %s\n",
3214                 XBaseFontNameListOfFontSet(fntSet),
3215                 XLocaleOfFontSet(fntSet));
3216         count = XFontsOfFontSet(fntSet, &font_struct_list, &font_name_list);
3217         for (i = 0; i < count; i++) {
3218           fprintf(debugFP, " got charset %s\n", font_name_list[i]);
3219         }
3220       }
3221       for (i = 0; i < missing_count; i++) {
3222         fprintf(debugFP, " missing charset %s\n", missing_list[i]);
3223       }
3224     }
3225     if (fntSet == NULL) {
3226       fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
3227       exit(2);
3228     }
3229     return fntSet;
3230 }
3231 #else // not ENABLE_NLS
3232 /*
3233  * Find a font that matches "pattern" that is as close as
3234  * possible to the targetPxlSize.  Prefer fonts that are k
3235  * pixels smaller to fonts that are k pixels larger.  The
3236  * pattern must be in the X Consortium standard format,
3237  * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3238  * The return value should be freed with XtFree when no
3239  * longer needed.
3240  */
3241 char *
3242 FindFont(pattern, targetPxlSize)
3243      char *pattern;
3244      int targetPxlSize;
3245 {
3246     char **fonts, *p, *best, *scalable, *scalableTail;
3247     int i, j, nfonts, minerr, err, pxlSize;
3248
3249     fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3250     if (nfonts < 1) {
3251         fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3252                 programName, pattern);
3253         exit(2);
3254     }
3255
3256     best = fonts[0];
3257     scalable = NULL;
3258     minerr = 999999;
3259     for (i=0; i<nfonts; i++) {
3260         j = 0;
3261         p = fonts[i];
3262         if (*p != '-') continue;
3263         while (j < 7) {
3264             if (*p == NULLCHAR) break;
3265             if (*p++ == '-') j++;
3266         }
3267         if (j < 7) continue;
3268         pxlSize = atoi(p);
3269         if (pxlSize == 0) {
3270             scalable = fonts[i];
3271             scalableTail = p;
3272         } else {
3273             err = pxlSize - targetPxlSize;
3274             if (Abs(err) < Abs(minerr) ||
3275                 (minerr > 0 && err < 0 && -err == minerr)) {
3276                 best = fonts[i];
3277                 minerr = err;
3278             }
3279         }
3280     }
3281     if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3282         /* If the error is too big and there is a scalable font,
3283            use the scalable font. */
3284         int headlen = scalableTail - scalable;
3285         p = (char *) XtMalloc(strlen(scalable) + 10);
3286         while (isdigit(*scalableTail)) scalableTail++;
3287         sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3288     } else {
3289         p = (char *) XtMalloc(strlen(best) + 2);
3290         safeStrCpy(p, best, strlen(best)+1 );
3291     }
3292     if (appData.debugMode) {
3293         fprintf(debugFP, _("resolved %s at pixel size %d\n  to %s\n"),
3294                 pattern, targetPxlSize, p);
3295     }
3296     XFreeFontNames(fonts);
3297     return p;
3298 }
3299 #endif
3300
3301 void DeleteGCs()
3302 {   // [HGM] deletes GCs that are to be remade, to prevent resource leak;
3303     // must be called before all non-first callse to CreateGCs()
3304     XtReleaseGC(shellWidget, highlineGC);
3305     XtReleaseGC(shellWidget, lightSquareGC);
3306     XtReleaseGC(shellWidget, darkSquareGC);
3307     XtReleaseGC(shellWidget, lineGC);
3308     if (appData.monoMode) {
3309         if (DefaultDepth(xDisplay, xScreen) == 1) {
3310             XtReleaseGC(shellWidget, wbPieceGC);
3311         } else {
3312             XtReleaseGC(shellWidget, bwPieceGC);
3313         }
3314     } else {
3315         XtReleaseGC(shellWidget, prelineGC);
3316         XtReleaseGC(shellWidget, jailSquareGC);
3317         XtReleaseGC(shellWidget, wdPieceGC);
3318         XtReleaseGC(shellWidget, wlPieceGC);
3319         XtReleaseGC(shellWidget, wjPieceGC);
3320         XtReleaseGC(shellWidget, bdPieceGC);
3321         XtReleaseGC(shellWidget, blPieceGC);
3322         XtReleaseGC(shellWidget, bjPieceGC);
3323     }
3324 }
3325
3326 void CreateGCs(int redo)
3327 {
3328     XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3329       | GCBackground | GCFunction | GCPlaneMask;
3330     XGCValues gc_values;
3331     GC copyInvertedGC;
3332
3333     gc_values.plane_mask = AllPlanes;
3334     gc_values.line_width = lineGap;
3335     gc_values.line_style = LineSolid;
3336     gc_values.function = GXcopy;
3337
3338   if(redo) {
3339     DeleteGCs(); // called a second time; clean up old GCs first
3340   } else { // [HGM] grid and font GCs created on first call only
3341     gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3342     gc_values.background = XWhitePixel(xDisplay, xScreen);
3343     coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3344     XSetFont(xDisplay, coordGC, coordFontID);
3345
3346     // [HGM] make font for holdings counts (white on black)
3347     gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3348     gc_values.background = XBlackPixel(xDisplay, xScreen);
3349     countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3350     XSetFont(xDisplay, countGC, countFontID);
3351   }
3352     gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3353     gc_values.background = XBlackPixel(xDisplay, xScreen);
3354     lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3355
3356     if (appData.monoMode) {
3357         gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3358         gc_values.background = XWhitePixel(xDisplay, xScreen);
3359         highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3360
3361         gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3362         gc_values.background = XBlackPixel(xDisplay, xScreen);
3363         lightSquareGC = wbPieceGC
3364           = XtGetGC(shellWidget, value_mask, &gc_values);
3365
3366         gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3367         gc_values.background = XWhitePixel(xDisplay, xScreen);
3368         darkSquareGC = bwPieceGC
3369           = XtGetGC(shellWidget, value_mask, &gc_values);
3370
3371         if (DefaultDepth(xDisplay, xScreen) == 1) {
3372             /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3373             gc_values.function = GXcopyInverted;
3374             copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3375             gc_values.function = GXcopy;
3376             if (XBlackPixel(xDisplay, xScreen) == 1) {
3377                 bwPieceGC = darkSquareGC;
3378                 wbPieceGC = copyInvertedGC;
3379             } else {
3380                 bwPieceGC = copyInvertedGC;
3381                 wbPieceGC = lightSquareGC;
3382             }
3383         }
3384     } else {
3385         gc_values.foreground = highlightSquareColor;
3386         gc_values.background = highlightSquareColor;
3387         highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3388
3389         gc_values.foreground = premoveHighlightColor;
3390         gc_values.background = premoveHighlightColor;
3391         prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3392
3393         gc_values.foreground = lightSquareColor;
3394         gc_values.background = darkSquareColor;
3395         lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3396
3397         gc_values.foreground = darkSquareColor;
3398         gc_values.background = lightSquareColor;
3399         darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3400
3401         gc_values.foreground = jailSquareColor;
3402         gc_values.background = jailSquareColor;
3403         jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3404
3405         gc_values.foreground = whitePieceColor;
3406         gc_values.background = darkSquareColor;
3407         wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3408
3409         gc_values.foreground = whitePieceColor;
3410         gc_values.background = lightSquareColor;
3411         wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3412
3413         gc_values.foreground = whitePieceColor;
3414         gc_values.background = jailSquareColor;
3415         wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3416
3417         gc_values.foreground = blackPieceColor;
3418         gc_values.background = darkSquareColor;
3419         bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3420
3421         gc_values.foreground = blackPieceColor;
3422         gc_values.background = lightSquareColor;
3423         blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3424
3425         gc_values.foreground = blackPieceColor;
3426         gc_values.background = jailSquareColor;
3427         bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3428     }
3429 }
3430
3431 void loadXIM(xim, xmask, filename, dest, mask)
3432      XImage *xim;
3433      XImage *xmask;
3434      char *filename;
3435      Pixmap *dest;
3436      Pixmap *mask;
3437 {
3438     int x, y, w, h, p;
3439     FILE *fp;
3440     Pixmap temp;
3441     XGCValues   values;
3442     GC maskGC;
3443
3444     fp = fopen(filename, "rb");
3445     if (!fp) {
3446         fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3447         exit(1);
3448     }
3449
3450     w = fgetc(fp);
3451     h = fgetc(fp);
3452
3453     for (y=0; y<h; ++y) {
3454         for (x=0; x<h; ++x) {
3455             p = fgetc(fp);
3456
3457             switch (p) {
3458               case 0:
3459                 XPutPixel(xim, x, y, blackPieceColor);
3460                 if (xmask)
3461                   XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3462                 break;
3463               case 1:
3464                 XPutPixel(xim, x, y, darkSquareColor);
3465                 if (xmask)
3466                   XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3467                 break;
3468               case 2:
3469                 XPutPixel(xim, x, y, whitePieceColor);
3470                 if (xmask)
3471                   XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3472                 break;
3473               case 3:
3474                 XPutPixel(xim, x, y, lightSquareColor);
3475                 if (xmask)
3476                   XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3477                 break;
3478             }
3479         }
3480     }
3481
3482     fclose(fp);
3483
3484     /* create Pixmap of piece */
3485     *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3486                           w, h, xim->depth);
3487     XPutImage(xDisplay, *dest, lightSquareGC, xim,
3488               0, 0, 0, 0, w, h);
3489
3490     /* create Pixmap of clipmask
3491        Note: We assume the white/black pieces have the same
3492              outline, so we make only 6 masks. This is okay
3493              since the XPM clipmask routines do the same. */
3494     if (xmask) {
3495       temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3496                             w, h, xim->depth);
3497       XPutImage(xDisplay, temp, lightSquareGC, xmask,
3498               0, 0, 0, 0, w, h);
3499
3500       /* now create the 1-bit version */
3501       *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3502                           w, h, 1);
3503
3504       values.foreground = 1;
3505       values.background = 0;
3506
3507       /* Don't use XtGetGC, not read only */
3508       maskGC = XCreateGC(xDisplay, *mask,
3509                     GCForeground | GCBackground, &values);
3510       XCopyPlane(xDisplay, temp, *mask, maskGC,
3511                   0, 0, squareSize, squareSize, 0, 0, 1);
3512       XFreePixmap(xDisplay, temp);
3513     }
3514 }
3515
3516
3517 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3518
3519 void CreateXIMPieces()
3520 {
3521     int piece, kind;
3522     char buf[MSG_SIZ];
3523     u_int ss;
3524     static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3525     XImage *ximtemp;
3526
3527     ss = squareSize;
3528
3529     /* The XSynchronize calls were copied from CreatePieces.
3530        Not sure if needed, but can't hurt */
3531     XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3532                                      buffering bug */
3533
3534     /* temp needed by loadXIM() */
3535     ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3536                  0, 0, ss, ss, AllPlanes, XYPixmap);
3537
3538     if (strlen(appData.pixmapDirectory) == 0) {
3539       useImages = 0;
3540     } else {
3541         useImages = 1;
3542         if (appData.monoMode) {
3543           DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3544                             0, 2);
3545           ExitEvent(2);
3546         }
3547         fprintf(stderr, _("\nLoading XIMs...\n"));
3548         /* Load pieces */
3549         for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3550             fprintf(stderr, "%d", piece+1);
3551             for (kind=0; kind<4; kind++) {
3552                 fprintf(stderr, ".");
3553                 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3554                         ExpandPathName(appData.pixmapDirectory),
3555                         piece <= (int) WhiteKing ? "" : "w",
3556                         pieceBitmapNames[piece],
3557                         ximkind[kind], ss);
3558                 ximPieceBitmap[kind][piece] =
3559                   XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3560                             0, 0, ss, ss, AllPlanes, XYPixmap);
3561                 if (appData.debugMode)
3562                   fprintf(stderr, _("(File:%s:) "), buf);
3563                 loadXIM(ximPieceBitmap[kind][piece],
3564                         ximtemp, buf,
3565                         &(xpmPieceBitmap2[kind][piece]),
3566                         &(ximMaskPm2[piece]));
3567                 if(piece <= (int)WhiteKing)
3568                     xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3569             }
3570             fprintf(stderr," ");
3571         }
3572         /* Load light and dark squares */
3573         /* If the LSQ and DSQ pieces don't exist, we will
3574            draw them with solid squares. */
3575         snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3576         if (access(buf, 0) != 0) {
3577             useImageSqs = 0;
3578         } else {
3579             useImageSqs = 1;
3580             fprintf(stderr, _("light square "));
3581             ximLightSquare=
3582               XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3583                         0, 0, ss, ss, AllPlanes, XYPixmap);
3584             if (appData.debugMode)
3585               fprintf(stderr, _("(File:%s:) "), buf);
3586
3587             loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3588             fprintf(stderr, _("dark square "));
3589             snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3590                     ExpandPathName(appData.pixmapDirectory), ss);
3591             if (appData.debugMode)
3592               fprintf(stderr, _("(File:%s:) "), buf);
3593             ximDarkSquare=
3594               XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3595                         0, 0, ss, ss, AllPlanes, XYPixmap);
3596             loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3597             xpmJailSquare = xpmLightSquare;
3598         }
3599         fprintf(stderr, _("Done.\n"));
3600     }
3601     XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3602 }
3603
3604 static VariantClass oldVariant = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
3605
3606 #if HAVE_LIBXPM
3607 void CreateXPMBoard(char *s, int kind)
3608 {
3609     XpmAttributes attr;
3610     attr.valuemask = 0;
3611     if(!appData.useBitmaps || s == NULL || *s == 0 || *s == '*') { useTexture &= ~(kind+1); return; }
3612     if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3613         useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3614     }
3615 }
3616
3617 void FreeXPMPieces()
3618 {   // [HGM] to prevent resoucre leak on calling CreaeXPMPieces() a second time,
3619     // thisroutine has to be called t free the old piece pixmaps
3620     int piece, kind;
3621     for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++)
3622         for (kind=0; kind<4; kind++) XFreePixmap(xDisplay, xpmPieceBitmap2[kind][piece]);
3623     if(useImageSqs) {
3624         XFreePixmap(xDisplay, xpmLightSquare);
3625         XFreePixmap(xDisplay, xpmDarkSquare);
3626     }
3627 }
3628
3629 void CreateXPMPieces()
3630 {
3631     int piece, kind, r;
3632     char buf[MSG_SIZ];
3633     u_int ss = squareSize;
3634     XpmAttributes attr;
3635     static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3636     XpmColorSymbol symbols[4];
3637     static int redo = False;
3638
3639     if(redo) FreeXPMPieces(); else redo = 1;
3640
3641     /* The XSynchronize calls were copied from CreatePieces.
3642        Not sure if needed, but can't hurt */
3643     XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3644
3645     /* Setup translations so piece colors match square colors */
3646     symbols[0].name = "light_piece";
3647     symbols[0].value = appData.whitePieceColor;
3648     symbols[1].name = "dark_piece";
3649     symbols[1].value = appData.blackPieceColor;
3650     symbols[2].name = "light_square";
3651</