44fcb80907bc7c27179d92a3da1147741d38dc60
[xboard.git] / xboard.c
1 /*
2  * xboard.c -- X front end for XBoard
3  *
4  * Copyright 1991 by Digital Equipment Corporation, Maynard,
5  * Massachusetts.
6  *
7  * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
8  * 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
9  *
10  * The following terms apply to Digital Equipment Corporation's copyright
11  * interest in XBoard:
12  * ------------------------------------------------------------------------
13  * All Rights Reserved
14  *
15  * Permission to use, copy, modify, and distribute this software and its
16  * documentation for any purpose and without fee is hereby granted,
17  * provided that the above copyright notice appear in all copies and that
18  * both that copyright notice and this permission notice appear in
19  * supporting documentation, and that the name of Digital not be
20  * used in advertising or publicity pertaining to distribution of the
21  * software without specific, written prior permission.
22  *
23  * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25  * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26  * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
29  * SOFTWARE.
30  * ------------------------------------------------------------------------
31  *
32  * The following terms apply to the enhanced version of XBoard
33  * distributed by the Free Software Foundation:
34  * ------------------------------------------------------------------------
35  *
36  * GNU XBoard is free software: you can redistribute it and/or modify
37  * it under the terms of the GNU General Public License as published by
38  * the Free Software Foundation, either version 3 of the License, or (at
39  * your option) any later version.
40  *
41  * GNU XBoard is distributed in the hope that it will be useful, but
42  * WITHOUT ANY WARRANTY; without even the implied warranty of
43  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44  * General Public License for more details.
45  *
46  * You should have received a copy of the GNU General Public License
47  * along with this program. If not, see http://www.gnu.org/licenses/.  *
48  *
49  *------------------------------------------------------------------------
50  ** See the file ChangeLog for a revision history.  */
51
52 #define HIGHDRAG 1
53
54 #include "config.h"
55
56 #include <stdio.h>
57 #include <ctype.h>
58 #include <signal.h>
59 #include <errno.h>
60 #include <sys/types.h>
61 #include <sys/stat.h>
62 #include <pwd.h>
63 #include <math.h>
64
65 #if !OMIT_SOCKETS
66 # if HAVE_SYS_SOCKET_H
67 #  include <sys/socket.h>
68 #  include <netinet/in.h>
69 #  include <netdb.h>
70 # else /* not HAVE_SYS_SOCKET_H */
71 #  if HAVE_LAN_SOCKET_H
72 #   include <lan/socket.h>
73 #   include <lan/in.h>
74 #   include <lan/netdb.h>
75 #  else /* not HAVE_LAN_SOCKET_H */
76 #   define OMIT_SOCKETS 1
77 #  endif /* not HAVE_LAN_SOCKET_H */
78 # endif /* not HAVE_SYS_SOCKET_H */
79 #endif /* !OMIT_SOCKETS */
80
81 #if STDC_HEADERS
82 # include <stdlib.h>
83 # include <string.h>
84 #else /* not STDC_HEADERS */
85 extern char *getenv();
86 # if HAVE_STRING_H
87 #  include <string.h>
88 # else /* not HAVE_STRING_H */
89 #  include <strings.h>
90 # endif /* not HAVE_STRING_H */
91 #endif /* not STDC_HEADERS */
92
93 #if HAVE_SYS_FCNTL_H
94 # include <sys/fcntl.h>
95 #else /* not HAVE_SYS_FCNTL_H */
96 # if HAVE_FCNTL_H
97 #  include <fcntl.h>
98 # endif /* HAVE_FCNTL_H */
99 #endif /* not HAVE_SYS_FCNTL_H */
100
101 #if HAVE_SYS_SYSTEMINFO_H
102 # include <sys/systeminfo.h>
103 #endif /* HAVE_SYS_SYSTEMINFO_H */
104
105 #if TIME_WITH_SYS_TIME
106 # include <sys/time.h>
107 # include <time.h>
108 #else
109 # if HAVE_SYS_TIME_H
110 #  include <sys/time.h>
111 # else
112 #  include <time.h>
113 # endif
114 #endif
115
116 #if HAVE_UNISTD_H
117 # include <unistd.h>
118 #endif
119
120 #if HAVE_SYS_WAIT_H
121 # include <sys/wait.h>
122 #endif
123
124 #if HAVE_DIRENT_H
125 # include <dirent.h>
126 # define NAMLEN(dirent) strlen((dirent)->d_name)
127 # define HAVE_DIR_STRUCT
128 #else
129 # define dirent direct
130 # define NAMLEN(dirent) (dirent)->d_namlen
131 # if HAVE_SYS_NDIR_H
132 #  include <sys/ndir.h>
133 #  define HAVE_DIR_STRUCT
134 # endif
135 # if HAVE_SYS_DIR_H
136 #  include <sys/dir.h>
137 #  define HAVE_DIR_STRUCT
138 # endif
139 # if HAVE_NDIR_H
140 #  include <ndir.h>
141 #  define HAVE_DIR_STRUCT
142 # endif
143 #endif
144
145 #if ENABLE_NLS
146 #include <locale.h>
147 #endif
148
149 #include <X11/Intrinsic.h>
150 #include <X11/StringDefs.h>
151 #include <X11/Shell.h>
152 #include <X11/cursorfont.h>
153 #include <X11/Xatom.h>
154 #include <X11/Xmu/Atoms.h>
155 #if USE_XAW3D
156 #include <X11/Xaw3d/Dialog.h>
157 #include <X11/Xaw3d/Form.h>
158 #include <X11/Xaw3d/List.h>
159 #include <X11/Xaw3d/Label.h>
160 #include <X11/Xaw3d/SimpleMenu.h>
161 #include <X11/Xaw3d/SmeBSB.h>
162 #include <X11/Xaw3d/SmeLine.h>
163 #include <X11/Xaw3d/Box.h>
164 #include <X11/Xaw3d/MenuButton.h>
165 #include <X11/Xaw3d/Text.h>
166 #include <X11/Xaw3d/AsciiText.h>
167 #else
168 #include <X11/Xaw/Dialog.h>
169 #include <X11/Xaw/Form.h>
170 #include <X11/Xaw/List.h>
171 #include <X11/Xaw/Label.h>
172 #include <X11/Xaw/SimpleMenu.h>
173 #include <X11/Xaw/SmeBSB.h>
174 #include <X11/Xaw/SmeLine.h>
175 #include <X11/Xaw/Box.h>
176 #include <X11/Xaw/MenuButton.h>
177 #include <X11/Xaw/Text.h>
178 #include <X11/Xaw/AsciiText.h>
179 #endif
180
181 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
182 #include "common.h"
183
184 #if HAVE_LIBXPM
185 #include <X11/xpm.h>
186 #include "pixmaps/pixmaps.h"
187 #define IMAGE_EXT "xpm"
188 #else
189 #define IMAGE_EXT "xim"
190 #include "bitmaps/bitmaps.h"
191 #endif
192
193 #include "bitmaps/icon_white.bm"
194 #include "bitmaps/icon_black.bm"
195 #include "bitmaps/checkmark.bm"
196
197 #include "frontend.h"
198 #include "backend.h"
199 #include "backendz.h"
200 #include "moves.h"
201 #include "xboard.h"
202 #include "childio.h"
203 #include "xgamelist.h"
204 #include "xhistory.h"
205 #include "xedittags.h"
206 #include "gettext.h"
207
208 // must be moved to xengineoutput.h
209
210 void EngineOutputProc P((Widget w, XEvent *event,
211                          String *prms, Cardinal *nprms));
212 void EvalGraphProc P((Widget w, XEvent *event,
213                       String *prms, Cardinal *nprms));
214
215
216 #ifdef __EMX__
217 #ifndef HAVE_USLEEP
218 #define HAVE_USLEEP
219 #endif
220 #define usleep(t)   _sleep2(((t)+500)/1000)
221 #endif
222
223 #ifdef ENABLE_NLS
224 # define  _(s) gettext (s)
225 # define N_(s) gettext_noop (s)
226 #else
227 # define  _(s) (s)
228 # define N_(s)  s
229 #endif
230
231 typedef struct {
232     String string;
233     String ref;
234     XtActionProc proc;
235 } MenuItem;
236
237 typedef struct {
238     String name;
239     String ref;
240     MenuItem *mi;
241 } Menu;
242
243 int main P((int argc, char **argv));
244 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
245                 char *init_path, char *filter, char *mode, int (*show_entry)(), char **name_return));
246 RETSIGTYPE CmailSigHandler P((int sig));
247 RETSIGTYPE IntSigHandler P((int sig));
248 RETSIGTYPE TermSizeSigHandler P((int sig));
249 void CreateGCs P((int redo));
250 void CreateAnyPieces P((void));
251 void CreateXIMPieces P((void));
252 void CreateXPMPieces P((void));
253 void CreateXPMBoard P((char *s, int n));
254 void CreatePieces P((void));
255 void CreatePieceMenus P((void));
256 Widget CreateMenuBar P((Menu *mb));
257 Widget CreateButtonBar P ((MenuItem *mi));
258 #if ENABLE_NLS
259 char *InsertPxlSize P((char *pattern, int targetPxlSize));
260 XFontSet CreateFontSet P((char *base_fnt_lst));
261 #else
262 char *FindFont P((char *pattern, int targetPxlSize));
263 #endif
264 void PieceMenuPopup P((Widget w, XEvent *event,
265                        String *params, Cardinal *num_params));
266 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
267 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
268 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
269                    u_int wreq, u_int hreq));
270 void CreateGrid P((void));
271 int EventToSquare P((int x, int limit));
272 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
273 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
274 void MoveTypeInProc P((Widget widget, caddr_t unused, XEvent *event));
275 void HandleUserMove P((Widget w, XEvent *event,
276                      String *prms, Cardinal *nprms));
277 void AnimateUserMove P((Widget w, XEvent * event,
278                      String * params, Cardinal * nParams));
279 void HandlePV P((Widget w, XEvent * event,
280                      String * params, Cardinal * nParams));
281 void SelectPV P((Widget w, XEvent * event,
282                      String * params, Cardinal * nParams));
283 void StopPV P((Widget w, XEvent * event,
284                      String * params, Cardinal * nParams));
285 void WhiteClock P((Widget w, XEvent *event,
286                    String *prms, Cardinal *nprms));
287 void BlackClock P((Widget w, XEvent *event,
288                    String *prms, Cardinal *nprms));
289 void DrawPositionProc P((Widget w, XEvent *event,
290                      String *prms, Cardinal *nprms));
291 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
292                      Board board));
293 void CommentClick P((Widget w, XEvent * event,
294                    String * params, Cardinal * nParams));
295 void CommentPopUp P((char *title, char *label));
296 void CommentPopDown P((void));
297 void ICSInputBoxPopUp P((void));
298 void ICSInputBoxPopDown P((void));
299 void FileNamePopUp P((char *label, char *def, char *filter,
300                       FileProc proc, char *openMode));
301 void FileNamePopDown P((void));
302 void FileNameCallback P((Widget w, XtPointer client_data,
303                          XtPointer call_data));
304 void FileNameAction P((Widget w, XEvent *event,
305                        String *prms, Cardinal *nprms));
306 void AskQuestionReplyAction P((Widget w, XEvent *event,
307                           String *prms, Cardinal *nprms));
308 void AskQuestionProc P((Widget w, XEvent *event,
309                           String *prms, Cardinal *nprms));
310 void AskQuestionPopDown P((void));
311 void PromotionPopDown P((void));
312 void PromotionCallback P((Widget w, XtPointer client_data,
313                           XtPointer call_data));
314 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
315 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
316 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
317 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
318                          Cardinal *nprms));
319 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
320                          Cardinal *nprms));
321 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
322                        Cardinal *nprms));
323 void LoadPositionProc P((Widget w, XEvent *event,
324                          String *prms, Cardinal *nprms));
325 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
326                          Cardinal *nprms));
327 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
328                          Cardinal *nprms));
329 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
330                        Cardinal *nprms));
331 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
332                          Cardinal *nprms));
333 void PastePositionProc P((Widget w, XEvent *event, String *prms,
334                           Cardinal *nprms));
335 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
336 void CopyGameListProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
337 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
338 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
339 void SavePositionProc P((Widget w, XEvent *event,
340                          String *prms, Cardinal *nprms));
341 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
342 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
343                             Cardinal *nprms));
344 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
345 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
346 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
347                          Cardinal *nprms));
348 void MachineWhiteProc P((Widget w, XEvent *event,
349                          String *prms, Cardinal *nprms));
350 void AnalyzeModeProc P((Widget w, XEvent *event,
351                          String *prms, Cardinal *nprms));
352 void AnalyzeFileProc P((Widget w, XEvent *event,
353                          String *prms, Cardinal *nprms));
354 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
355                         Cardinal *nprms));
356 void MatchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
357 void MatchOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
358 void IcsClientProc P((Widget w, XEvent *event, String *prms,
359                       Cardinal *nprms));
360 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void EditPositionProc P((Widget w, XEvent *event,
362                          String *prms, Cardinal *nprms));
363 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void EditCommentProc P((Widget w, XEvent *event,
365                         String *prms, Cardinal *nprms));
366 void IcsInputBoxProc P((Widget w, XEvent *event,
367                         String *prms, Cardinal *nprms));
368 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
369 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
370 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
371 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
372 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
373 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
374 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
375 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
376 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
377 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
379 void TypeInProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
380 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void StopObservingProc P((Widget w, XEvent *event, String *prms,
384                           Cardinal *nprms));
385 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
386                           Cardinal *nprms));
387 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
388 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
389 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
390 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
391 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
392 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
393 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
394 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
395                          Cardinal *nprms));
396 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
397                         Cardinal *nprms));
398 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
399 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
400                         Cardinal *nprms));
401 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
402                          Cardinal *nprms));
403 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
404                          Cardinal *nprms));
405 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
406 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
407 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
408 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
409                        Cardinal *nprms));
410 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
411 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
412                               Cardinal *nprms));
413 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
414                               Cardinal *nprms));
415 void HighlightArrowProc P((Widget w, XEvent *event, String *prms,
416                               Cardinal *nprms));
417 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
418 //void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
419 void OneClickProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
420 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
421                          Cardinal *nprms));
422 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
423                            Cardinal *nprms));
424 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
425                         Cardinal *nprms));
426 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
427                              Cardinal *nprms));
428 //void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
429 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
430                        Cardinal *nprms));
431 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
432                          Cardinal *nprms));
433 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
434                          Cardinal *nprms));
435 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
436                           Cardinal *nprms));
437 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
442 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
443 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
444 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
445 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
446 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
447 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
448 void DisplayMove P((int moveNumber));
449 void DisplayTitle P((char *title));
450 void ICSInitScript P((void));
451 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
452 void ErrorPopUp P((char *title, char *text, int modal));
453 void ErrorPopDown P((void));
454 static char *ExpandPathName P((char *path));
455 static void CreateAnimVars P((void));
456 static void DragPieceMove P((int x, int y));
457 static void DrawDragPiece P((void));
458 char *ModeToWidgetName P((GameMode mode));
459 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
460 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
461 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
462 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
463 void OptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
464 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
465 void IcsTextProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
466 void LoadEngineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
467 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
468 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
469 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
470 void IcsOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
471 void SoundOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
472 void BoardOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
473 void LoadOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
474 void SaveOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
475 void EditBookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
476 void 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 File      Ctrl+F"), "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     {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     { "Iconify", Iconify },
924     { "ResetProc", ResetProc },
925     { "NewVariantProc", NewVariantProc },
926     { "LoadGameProc", LoadGameProc },
927     { "LoadNextGameProc", LoadNextGameProc },
928     { "LoadPrevGameProc", LoadPrevGameProc },
929     { "LoadSelectedProc", LoadSelectedProc },
930     { "SetFilterProc", SetFilterProc },
931     { "ReloadGameProc", ReloadGameProc },
932     { "LoadPositionProc", LoadPositionProc },
933     { "LoadNextPositionProc", LoadNextPositionProc },
934     { "LoadPrevPositionProc", LoadPrevPositionProc },
935     { "ReloadPositionProc", ReloadPositionProc },
936     { "CopyPositionProc", CopyPositionProc },
937     { "PastePositionProc", PastePositionProc },
938     { "CopyGameProc", CopyGameProc },
939     { "CopyGameListProc", CopyGameListProc },
940     { "PasteGameProc", PasteGameProc },
941     { "SaveGameProc", SaveGameProc },
942     { "SavePositionProc", SavePositionProc },
943     { "MailMoveProc", MailMoveProc },
944     { "ReloadCmailMsgProc", ReloadCmailMsgProc },
945     { "QuitProc", QuitProc },
946     { "MachineWhiteProc", MachineWhiteProc },
947     { "MachineBlackProc", MachineBlackProc },
948     { "AnalysisModeProc", AnalyzeModeProc },
949     { "AnalyzeFileProc", AnalyzeFileProc },
950     { "TwoMachinesProc", TwoMachinesProc },
951     { "IcsClientProc", IcsClientProc },
952     { "EditGameProc", EditGameProc },
953     { "EditPositionProc", EditPositionProc },
954     { "TrainingProc", EditPositionProc },
955     { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
956     { "EvalGraphProc", EvalGraphProc},       // [HGM] Winboard_x avaluation graph window
957     { "ShowGameListProc", ShowGameListProc },
958     { "ShowMoveListProc", HistoryShowProc},
959     { "EditTagsProc", EditCommentProc },
960     { "EditBookProc", EditBookProc },
961     { "EditCommentProc", EditCommentProc },
962     { "IcsInputBoxProc", IcsInputBoxProc },
963     { "PauseProc", PauseProc },
964     { "AcceptProc", AcceptProc },
965     { "DeclineProc", DeclineProc },
966     { "RematchProc", RematchProc },
967     { "CallFlagProc", CallFlagProc },
968     { "DrawProc", DrawProc },
969     { "AdjournProc", AdjournProc },
970     { "AbortProc", AbortProc },
971     { "ResignProc", ResignProc },
972     { "AdjuWhiteProc", AdjuWhiteProc },
973     { "AdjuBlackProc", AdjuBlackProc },
974     { "AdjuDrawProc", AdjuDrawProc },
975     { "TypeInProc", TypeInProc },
976     { "EnterKeyProc", EnterKeyProc },
977     { "UpKeyProc", UpKeyProc },
978     { "DownKeyProc", DownKeyProc },
979     { "StopObservingProc", StopObservingProc },
980     { "StopExaminingProc", StopExaminingProc },
981     { "UploadProc", UploadProc },
982     { "BackwardProc", BackwardProc },
983     { "ForwardProc", ForwardProc },
984     { "ToStartProc", ToStartProc },
985     { "ToEndProc", ToEndProc },
986     { "RevertProc", RevertProc },
987     { "AnnotateProc", AnnotateProc },
988     { "TruncateGameProc", TruncateGameProc },
989     { "MoveNowProc", MoveNowProc },
990     { "RetractMoveProc", RetractMoveProc },
991     { "EngineMenuProc", (XtActionProc) EngineMenuProc },
992     { "UciMenuProc", (XtActionProc) UciMenuProc },
993     { "TimeControlProc", (XtActionProc) TimeControlProc },
994     { "FlipViewProc", FlipViewProc },
995     { "PonderNextMoveProc", PonderNextMoveProc },
996 #ifndef OPTIONSDIALOG
997     { "AlwaysQueenProc", AlwaysQueenProc },
998     { "AnimateDraggingProc", AnimateDraggingProc },
999     { "AnimateMovingProc", AnimateMovingProc },
1000     { "AutoflagProc", AutoflagProc },
1001     { "AutoflipProc", AutoflipProc },
1002     { "BlindfoldProc", BlindfoldProc },
1003     { "FlashMovesProc", FlashMovesProc },
1004 #if HIGHDRAG
1005     { "HighlightDraggingProc", HighlightDraggingProc },
1006 #endif
1007     { "HighlightLastMoveProc", HighlightLastMoveProc },
1008 //    { "IcsAlarmProc", IcsAlarmProc },
1009     { "MoveSoundProc", MoveSoundProc },
1010     { "PeriodicUpdatesProc", PeriodicUpdatesProc },
1011     { "PopupExitMessageProc", PopupExitMessageProc },
1012     { "PopupMoveErrorsProc", PopupMoveErrorsProc },
1013 //    { "PremoveProc", PremoveProc },
1014     { "ShowCoordsProc", ShowCoordsProc },
1015     { "ShowThinkingProc", ShowThinkingProc },
1016     { "HideThinkingProc", HideThinkingProc },
1017     { "TestLegalityProc", TestLegalityProc },
1018 #endif
1019     { "SaveSettingsProc", SaveSettingsProc },
1020     { "SaveOnExitProc", SaveOnExitProc },
1021     { "InfoProc", InfoProc },
1022     { "ManProc", ManProc },
1023     { "HintProc", HintProc },
1024     { "BookProc", BookProc },
1025     { "AboutGameProc", AboutGameProc },
1026     { "AboutProc", AboutProc },
1027     { "DebugProc", DebugProc },
1028     { "NothingProc", NothingProc },
1029     { "CommentClick", (XtActionProc) CommentClick },
1030     { "CommentPopDown", (XtActionProc) CommentPopDown },
1031     { "TagsPopDown", (XtActionProc) TagsPopDown },
1032     { "ErrorPopDown", (XtActionProc) ErrorPopDown },
1033     { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
1034     { "FileNamePopDown", (XtActionProc) FileNamePopDown },
1035     { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
1036     { "GameListPopDown", (XtActionProc) GameListPopDown },
1037     { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
1038     { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1039     { "HistoryPopDown", (XtActionProc) HistoryPopDown },
1040     { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1041     { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1042     { "GenericPopDown", (XtActionProc) GenericPopDown },
1043     { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1044 };
1045
1046 char globalTranslations[] =
1047   ":<Key>F9: ResignProc() \n \
1048    :Ctrl<Key>n: ResetProc() \n \
1049    :Meta<Key>V: NewVariantProc() \n \
1050    :Ctrl<Key>o: LoadGameProc() \n \
1051    :Meta<Key>Next: LoadNextGameProc() \n \
1052    :Meta<Key>Prior: LoadPrevGameProc() \n \
1053    :Ctrl<Key>s: SaveGameProc() \n \
1054    :Ctrl<Key>c: CopyGameProc() \n \
1055    :Ctrl<Key>v: PasteGameProc() \n \
1056    :Ctrl<Key>O: LoadPositionProc() \n \
1057    :Shift<Key>Next: LoadNextPositionProc() \n \
1058    :Shift<Key>Prior: LoadPrevPositionProc() \n \
1059    :Ctrl<Key>S: SavePositionProc() \n \
1060    :Ctrl<Key>C: CopyPositionProc() \n \
1061    :Ctrl<Key>V: PastePositionProc() \n \
1062    :Ctrl<Key>q: QuitProc() \n \
1063    :Ctrl<Key>w: MachineWhiteProc() \n \
1064    :Ctrl<Key>b: MachineBlackProc() \n \
1065    :Ctrl<Key>t: TwoMachinesProc() \n \
1066    :Ctrl<Key>a: AnalysisModeProc() \n \
1067    :Ctrl<Key>f: AnalyzeFileProc() \n \
1068    :Ctrl<Key>e: EditGameProc() \n \
1069    :Ctrl<Key>E: EditPositionProc() \n \
1070    :Meta<Key>O: EngineOutputProc() \n \
1071    :Meta<Key>E: EvalGraphProc() \n \
1072    :Meta<Key>G: ShowGameListProc() \n \
1073    :Meta<Key>H: ShowMoveListProc() \n \
1074    :<Key>Pause: PauseProc() \n \
1075    :<Key>F3: AcceptProc() \n \
1076    :<Key>F4: DeclineProc() \n \
1077    :<Key>F12: RematchProc() \n \
1078    :<Key>F5: CallFlagProc() \n \
1079    :<Key>F6: DrawProc() \n \
1080    :<Key>F7: AdjournProc() \n \
1081    :<Key>F8: AbortProc() \n \
1082    :<Key>F10: StopObservingProc() \n \
1083    :<Key>F11: StopExaminingProc() \n \
1084    :Meta Ctrl<Key>F12: DebugProc() \n \
1085    :Meta<Key>End: ToEndProc() \n \
1086    :Meta<Key>Right: ForwardProc() \n \
1087    :Meta<Key>Home: ToStartProc() \n \
1088    :Meta<Key>Left: BackwardProc() \n \
1089    :<Key>Home: RevertProc() \n \
1090    :<Key>End: TruncateGameProc() \n \
1091    :Ctrl<Key>m: MoveNowProc() \n \
1092    :Ctrl<Key>x: RetractMoveProc() \n \
1093    :Meta<Key>J: EngineMenuProc() \n \
1094    :Meta<Key>U: UciMenuProc() \n \
1095    :Meta<Key>T: TimeControlProc() \n \
1096    :Ctrl<Key>P: PonderNextMoveProc() \n "
1097 #ifndef OPTIONSDIALOG
1098     "\
1099    :Ctrl<Key>Q: AlwaysQueenProc() \n \
1100    :Ctrl<Key>F: AutoflagProc() \n \
1101    :Ctrl<Key>A: AnimateMovingProc() \n \
1102    :Ctrl<Key>L: TestLegalityProc() \n \
1103    :Ctrl<Key>H: HideThinkingProc() \n "
1104 #endif
1105    "\
1106    :<Key>-: Iconify() \n \
1107    :<Key>F1: ManProc() \n \
1108    :<Key>F2: FlipViewProc() \n \
1109    <KeyDown>.: BackwardProc() \n \
1110    <KeyUp>.: ForwardProc() \n \
1111    Shift<Key>1: AskQuestionProc(\"Direct command\",\
1112                                 \"Send to chess program:\",,1) \n \
1113    Shift<Key>2: AskQuestionProc(\"Direct command\",\
1114                                 \"Send to second chess program:\",,2) \n";
1115
1116 char boardTranslations[] =
1117    "<Btn1Down>: HandleUserMove(0) \n \
1118    Shift<Btn1Up>: HandleUserMove(1) \n \
1119    <Btn1Up>: HandleUserMove(0) \n \
1120    <Btn1Motion>: AnimateUserMove() \n \
1121    <Btn3Motion>: HandlePV() \n \
1122    <Btn3Up>: PieceMenuPopup(menuB) \n \
1123    Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1124                  PieceMenuPopup(menuB) \n \
1125    Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1126                  PieceMenuPopup(menuW) \n \
1127    Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1128                  PieceMenuPopup(menuW) \n \
1129    Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1130                  PieceMenuPopup(menuB) \n";
1131
1132 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1133 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1134
1135 char ICSInputTranslations[] =
1136     "<Key>Up: UpKeyProc() \n "
1137     "<Key>Down: DownKeyProc() \n "
1138     "<Key>Return: EnterKeyProc() \n";
1139
1140 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1141 //             as the widget is destroyed before the up-click can call extend-end
1142 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1143
1144 String xboardResources[] = {
1145     "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1146     "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1147     "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1148     NULL
1149   };
1150
1151
1152 /* Max possible square size */
1153 #define MAXSQSIZE 256
1154
1155 static int xpm_avail[MAXSQSIZE];
1156
1157 #ifdef HAVE_DIR_STRUCT
1158
1159 /* Extract piece size from filename */
1160 static int
1161 xpm_getsize(name, len, ext)
1162      char *name;
1163      int len;
1164      char *ext;
1165 {
1166     char *p, *d;
1167     char buf[10];
1168
1169     if (len < 4)
1170       return 0;
1171
1172     if ((p=strchr(name, '.')) == NULL ||
1173         StrCaseCmp(p+1, ext) != 0)
1174       return 0;
1175
1176     p = name + 3;
1177     d = buf;
1178
1179     while (*p && isdigit(*p))
1180       *(d++) = *(p++);
1181
1182     *d = 0;
1183     return atoi(buf);
1184 }
1185
1186 /* Setup xpm_avail */
1187 static int
1188 xpm_getavail(dirname, ext)
1189      char *dirname;
1190      char *ext;
1191 {
1192     DIR *dir;
1193     struct dirent *ent;
1194     int  i;
1195
1196     for (i=0; i<MAXSQSIZE; ++i)
1197       xpm_avail[i] = 0;
1198
1199     if (appData.debugMode)
1200       fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1201
1202     dir = opendir(dirname);
1203     if (!dir)
1204       {
1205           fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1206                   programName, dirname);
1207           exit(1);
1208       }
1209
1210     while ((ent=readdir(dir)) != NULL) {
1211         i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1212         if (i > 0 && i < MAXSQSIZE)
1213           xpm_avail[i] = 1;
1214     }
1215
1216     closedir(dir);
1217
1218     return 0;
1219 }
1220
1221 void
1222 xpm_print_avail(fp, ext)
1223      FILE *fp;
1224      char *ext;
1225 {
1226     int i;
1227
1228     fprintf(fp, _("Available `%s' sizes:\n"), ext);
1229     for (i=1; i<MAXSQSIZE; ++i) {
1230         if (xpm_avail[i])
1231           printf("%d\n", i);
1232     }
1233 }
1234
1235 /* Return XPM piecesize closest to size */
1236 int
1237 xpm_closest_to(dirname, size, ext)
1238      char *dirname;
1239      int size;
1240      char *ext;
1241 {
1242     int i;
1243     int sm_diff = MAXSQSIZE;
1244     int sm_index = 0;
1245     int diff;
1246
1247     xpm_getavail(dirname, ext);
1248
1249     if (appData.debugMode)
1250       xpm_print_avail(stderr, ext);
1251
1252     for (i=1; i<MAXSQSIZE; ++i) {
1253         if (xpm_avail[i]) {
1254             diff = size - i;
1255             diff = (diff<0) ? -diff : diff;
1256             if (diff < sm_diff) {
1257                 sm_diff = diff;
1258                 sm_index = i;
1259             }
1260         }
1261     }
1262
1263     if (!sm_index) {
1264         fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1265         exit(1);
1266     }
1267
1268     return sm_index;
1269 }
1270 #else   /* !HAVE_DIR_STRUCT */
1271 /* If we are on a system without a DIR struct, we can't
1272    read the directory, so we can't collect a list of
1273    filenames, etc., so we can't do any size-fitting. */
1274 int
1275 xpm_closest_to(dirname, size, ext)
1276      char *dirname;
1277      int size;
1278      char *ext;
1279 {
1280     fprintf(stderr, _("\
1281 Warning: No DIR structure found on this system --\n\
1282          Unable to autosize for XPM/XIM pieces.\n\
1283    Please report this error to %s.\n\
1284    Include system type & operating system in message.\n"), PACKAGE_BUGREPORT););
1285     return size;
1286 }
1287 #endif /* HAVE_DIR_STRUCT */
1288
1289 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1290                              "magenta", "cyan", "white" };
1291 typedef struct {
1292     int attr, bg, fg;
1293 } TextColors;
1294 TextColors textColors[(int)NColorClasses];
1295
1296 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1297 static int
1298 parse_color(str, which)
1299      char *str;
1300      int which;
1301 {
1302     char *p, buf[100], *d;
1303     int i;
1304
1305     if (strlen(str) > 99)       /* watch bounds on buf */
1306       return -1;
1307
1308     p = str;
1309     d = buf;
1310     for (i=0; i<which; ++i) {
1311         p = strchr(p, ',');
1312         if (!p)
1313           return -1;
1314         ++p;
1315     }
1316
1317     /* Could be looking at something like:
1318        black, , 1
1319        .. in which case we want to stop on a comma also */
1320     while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1321       ++p;
1322
1323     if (*p == ',') {
1324         return -1;              /* Use default for empty field */
1325     }
1326
1327     if (which == 2 || isdigit(*p))
1328       return atoi(p);
1329
1330     while (*p && isalpha(*p))
1331       *(d++) = *(p++);
1332
1333     *d = 0;
1334
1335     for (i=0; i<8; ++i) {
1336         if (!StrCaseCmp(buf, cnames[i]))
1337           return which? (i+40) : (i+30);
1338     }
1339     if (!StrCaseCmp(buf, "default")) return -1;
1340
1341     fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1342     return -2;
1343 }
1344
1345 static int
1346 parse_cpair(cc, str)
1347      ColorClass cc;
1348      char *str;
1349 {
1350     if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1351         fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1352                 programName, str);
1353         return -1;
1354     }
1355
1356     /* bg and attr are optional */
1357     textColors[(int)cc].bg = parse_color(str, 1);
1358     if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1359         textColors[(int)cc].attr = 0;
1360     }
1361     return 0;
1362 }
1363
1364
1365 /* Arrange to catch delete-window events */
1366 Atom wm_delete_window;
1367 void
1368 CatchDeleteWindow(Widget w, String procname)
1369 {
1370   char buf[MSG_SIZ];
1371   XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1372   snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1373   XtAugmentTranslations(w, XtParseTranslationTable(buf));
1374 }
1375
1376 void
1377 BoardToTop()
1378 {
1379   Arg args[16];
1380   XtSetArg(args[0], XtNiconic, False);
1381   XtSetValues(shellWidget, args, 1);
1382
1383   XtPopup(shellWidget, XtGrabNone); /* Raise if lowered  */
1384 }
1385
1386 //---------------------------------------------------------------------------------------------------------
1387 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1388 #define XBOARD True
1389 #define JAWS_ARGS
1390 #define CW_USEDEFAULT (1<<31)
1391 #define ICS_TEXT_MENU_SIZE 90
1392 #define DEBUG_FILE "xboard.debug"
1393 #define SetCurrentDirectory chdir
1394 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1395 #define OPTCHAR "-"
1396 #define SEPCHAR " "
1397
1398 // these two must some day move to frontend.h, when they are implemented
1399 Boolean GameListIsUp();
1400
1401 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1402 #include "args.h"
1403
1404 // front-end part of option handling
1405
1406 // [HGM] This platform-dependent table provides the location for storing the color info
1407 extern char *crWhite, * crBlack;
1408
1409 void *
1410 colorVariable[] = {
1411   &appData.whitePieceColor,
1412   &appData.blackPieceColor,
1413   &appData.lightSquareColor,
1414   &appData.darkSquareColor,
1415   &appData.highlightSquareColor,
1416   &appData.premoveHighlightColor,
1417   &appData.lowTimeWarningColor,
1418   NULL,
1419   NULL,
1420   NULL,
1421   NULL,
1422   NULL,
1423   &crWhite,
1424   &crBlack,
1425   NULL
1426 };
1427
1428 // [HGM] font: keep a font for each square size, even non-stndard ones
1429 #define NUM_SIZES 18
1430 #define MAX_SIZE 130
1431 Boolean fontIsSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1432 char *fontTable[NUM_FONTS][MAX_SIZE];
1433
1434 void
1435 ParseFont(char *name, int number)
1436 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1437   int size;
1438   if(sscanf(name, "size%d:", &size)) {
1439     // [HGM] font: font is meant for specific boardSize (likely from settings file);
1440     //       defer processing it until we know if it matches our board size
1441     if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1442         fontTable[number][size] = strdup(strchr(name, ':')+1);
1443         fontValid[number][size] = True;
1444     }
1445     return;
1446   }
1447   switch(number) {
1448     case 0: // CLOCK_FONT
1449         appData.clockFont = strdup(name);
1450       break;
1451     case 1: // MESSAGE_FONT
1452         appData.font = strdup(name);
1453       break;
1454     case 2: // COORD_FONT
1455         appData.coordFont = strdup(name);
1456       break;
1457     default:
1458       return;
1459   }
1460   fontIsSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1461 }
1462
1463 void
1464 SetFontDefaults()
1465 { // only 2 fonts currently
1466   appData.clockFont = CLOCK_FONT_NAME;
1467   appData.coordFont = COORD_FONT_NAME;
1468   appData.font  =   DEFAULT_FONT_NAME;
1469 }
1470
1471 void
1472 CreateFonts()
1473 { // no-op, until we identify the code for this already in XBoard and move it here
1474 }
1475
1476 void
1477 ParseColor(int n, char *name)
1478 { // in XBoard, just copy the color-name string
1479   if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1480 }
1481
1482 void
1483 ParseTextAttribs(ColorClass cc, char *s)
1484 {
1485     (&appData.colorShout)[cc] = strdup(s);
1486 }
1487
1488 void
1489 ParseBoardSize(void *addr, char *name)
1490 {
1491     appData.boardSize = strdup(name);
1492 }
1493
1494 void
1495 LoadAllSounds()
1496 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1497 }
1498
1499 void
1500 SetCommPortDefaults()
1501 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1502 }
1503
1504 // [HGM] args: these three cases taken out to stay in front-end
1505 void
1506 SaveFontArg(FILE *f, ArgDescriptor *ad)
1507 {
1508   char *name;
1509   int i, n = (int)(intptr_t)ad->argLoc;
1510   switch(n) {
1511     case 0: // CLOCK_FONT
1512         name = appData.clockFont;
1513       break;
1514     case 1: // MESSAGE_FONT
1515         name = appData.font;
1516       break;
1517     case 2: // COORD_FONT
1518         name = appData.coordFont;
1519       break;
1520     default:
1521       return;
1522   }
1523   for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1524     if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1525         fontTable[n][squareSize] = strdup(name);
1526         fontValid[n][squareSize] = True;
1527         break;
1528   }
1529   for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1530     fprintf(f, OPTCHAR "%s" SEPCHAR "\"size%d:%s\"\n", ad->argName, i, fontTable[n][i]);
1531 }
1532
1533 void
1534 ExportSounds()
1535 { // nothing to do, as the sounds are at all times represented by their text-string names already
1536 }
1537
1538 void
1539 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1540 {       // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1541         fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
1542 }
1543
1544 void
1545 SaveColor(FILE *f, ArgDescriptor *ad)
1546 {       // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1547         if(colorVariable[(int)(intptr_t)ad->argLoc])
1548         fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
1549 }
1550
1551 void
1552 SaveBoardSize(FILE *f, char *name, void *addr)
1553 { // wrapper to shield back-end from BoardSize & sizeInfo
1554   fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1555 }
1556
1557 void
1558 ParseCommPortSettings(char *s)
1559 { // no such option in XBoard (yet)
1560 }
1561
1562 extern Widget engineOutputShell;
1563
1564 void
1565 GetActualPlacement(Widget wg, WindowPlacement *wp)
1566 {
1567   Arg args[16];
1568   Dimension w, h;
1569   Position x, y;
1570   int i;
1571
1572   if(!wg) return;
1573
1574     i = 0;
1575     XtSetArg(args[i], XtNx, &x); i++;
1576     XtSetArg(args[i], XtNy, &y); i++;
1577     XtSetArg(args[i], XtNwidth, &w); i++;
1578     XtSetArg(args[i], XtNheight, &h); i++;
1579     XtGetValues(wg, args, i);
1580     wp->x = x - 4;
1581     wp->y = y - 23;
1582     wp->height = h;
1583     wp->width = w;
1584 }
1585
1586 void
1587 GetWindowCoords()
1588 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1589   // In XBoard this will have to wait until awareness of window parameters is implemented
1590   GetActualPlacement(shellWidget, &wpMain);
1591   if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1592   if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1593   if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1594   if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1595   if(shellUp[1]) GetActualPlacement(shells[1], &wpComment);
1596   if(shellUp[2]) GetActualPlacement(shells[2], &wpTags);
1597 }
1598
1599 void
1600 PrintCommPortSettings(FILE *f, char *name)
1601 { // This option does not exist in XBoard
1602 }
1603
1604 int
1605 MySearchPath(char *installDir, char *name, char *fullname)
1606 { // just append installDir and name. Perhaps ExpandPath should be used here?
1607   name = ExpandPathName(name);
1608   if(name && name[0] == '/')
1609     safeStrCpy(fullname, name, MSG_SIZ );
1610   else {
1611     sprintf(fullname, "%s%c%s", installDir, '/', name);
1612   }
1613   return 1;
1614 }
1615
1616 int
1617 MyGetFullPathName(char *name, char *fullname)
1618 { // should use ExpandPath?
1619   name = ExpandPathName(name);
1620   safeStrCpy(fullname, name, MSG_SIZ );
1621   return 1;
1622 }
1623
1624 void
1625 EnsureOnScreen(int *x, int *y, int minX, int minY)
1626 {
1627   return;
1628 }
1629
1630 int
1631 MainWindowUp()
1632 { // [HGM] args: allows testing if main window is realized from back-end
1633   return xBoardWindow != 0;
1634 }
1635
1636 void
1637 PopUpStartupDialog()
1638 {  // start menu not implemented in XBoard
1639 }
1640
1641 char *
1642 ConvertToLine(int argc, char **argv)
1643 {
1644   static char line[128*1024], buf[1024];
1645   int i;
1646
1647   line[0] = NULLCHAR;
1648   for(i=1; i<argc; i++)
1649     {
1650       if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1651           && argv[i][0] != '{' )
1652         snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1653       else
1654         snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1655       strncat(line, buf, 128*1024 - strlen(line) - 1 );
1656     }
1657
1658   line[strlen(line)-1] = NULLCHAR;
1659   return line;
1660 }
1661
1662 //--------------------------------------------------------------------------------------------
1663
1664 extern Boolean twoBoards, partnerUp;
1665
1666 #ifdef IDSIZES
1667   // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1668 #else
1669 #define BoardSize int
1670 void InitDrawingSizes(BoardSize boardSize, int flags)
1671 {   // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1672     Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1673     Arg args[16];
1674     XtGeometryResult gres;
1675     int i;
1676
1677     if(!formWidget) return;
1678
1679     /*
1680      * Enable shell resizing.
1681      */
1682     shellArgs[0].value = (XtArgVal) &w;
1683     shellArgs[1].value = (XtArgVal) &h;
1684     XtGetValues(shellWidget, shellArgs, 2);
1685
1686     shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1687     shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1688     XtSetValues(shellWidget, &shellArgs[2], 4);
1689
1690     XtSetArg(args[0], XtNdefaultDistance, &sep);
1691     XtGetValues(formWidget, args, 1);
1692
1693     if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1694     boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1695     boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1696     CreateGrid();
1697     hOffset = boardWidth + 10;
1698     for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1699         secondSegments[i] = gridSegments[i];
1700         secondSegments[i].x1 += hOffset;
1701         secondSegments[i].x2 += hOffset;
1702     }
1703
1704     XtSetArg(args[0], XtNwidth, boardWidth);
1705     XtSetArg(args[1], XtNheight, boardHeight);
1706     XtSetValues(boardWidget, args, 2);
1707
1708     timerWidth = (boardWidth - sep) / 2;
1709     XtSetArg(args[0], XtNwidth, timerWidth);
1710     XtSetValues(whiteTimerWidget, args, 1);
1711     XtSetValues(blackTimerWidget, args, 1);
1712
1713     XawFormDoLayout(formWidget, False);
1714
1715     if (appData.titleInWindow) {
1716         i = 0;
1717         XtSetArg(args[i], XtNborderWidth, &bor); i++;
1718         XtSetArg(args[i], XtNheight, &h);  i++;
1719         XtGetValues(titleWidget, args, i);
1720         if (smallLayout) {
1721             w = boardWidth - 2*bor;
1722         } else {
1723             XtSetArg(args[0], XtNwidth, &w);
1724             XtGetValues(menuBarWidget, args, 1);
1725             w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1726         }
1727
1728         gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1729         if (gres != XtGeometryYes && appData.debugMode) {
1730             fprintf(stderr,
1731                     _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1732                     programName, gres, w, h, wr, hr);
1733         }
1734     }
1735
1736     XawFormDoLayout(formWidget, True);
1737
1738     /*
1739      * Inhibit shell resizing.
1740      */
1741     shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1742     shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1743     shellArgs[4].value = shellArgs[2].value = w;
1744     shellArgs[5].value = shellArgs[3].value = h;
1745     XtSetValues(shellWidget, &shellArgs[0], 6);
1746
1747     // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1748     // (only for xpm)
1749     if(useImages) {
1750       for(i=0; i<4; i++) {
1751         int p;
1752         for(p=0; p<=(int)WhiteKing; p++)
1753            xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1754         if(gameInfo.variant == VariantShogi) {
1755            xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1756            xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1757            xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1758            xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1759            xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1760         }
1761 #ifdef GOTHIC
1762         if(gameInfo.variant == VariantGothic) {
1763            xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1764         }
1765 #endif
1766         if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1767            xpmPieceBitmap[i][(int)WhiteAngel]    = xpmPieceBitmap2[i][(int)WhiteFalcon];
1768            xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1769         }
1770 #if !HAVE_LIBXPM
1771         // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1772         for(p=0; p<=(int)WhiteKing; p++)
1773            ximMaskPm[p] = ximMaskPm2[p]; // defaults
1774         if(gameInfo.variant == VariantShogi) {
1775            ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1776            ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1777            ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1778            ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1779            ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1780         }
1781 #ifdef GOTHIC
1782         if(gameInfo.variant == VariantGothic) {
1783            ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1784         }
1785 #endif
1786         if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1787            ximMaskPm[(int)WhiteAngel]    = ximMaskPm2[(int)WhiteFalcon];
1788            ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1789         }
1790 #endif
1791       }
1792     } else {
1793       for(i=0; i<2; i++) {
1794         int p;
1795         for(p=0; p<=(int)WhiteKing; p++)
1796            pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1797         if(gameInfo.variant == VariantShogi) {
1798            pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1799            pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1800            pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1801            pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1802            pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1803         }
1804 #ifdef GOTHIC
1805         if(gameInfo.variant == VariantGothic) {
1806            pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1807         }
1808 #endif
1809         if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1810            pieceBitmap[i][(int)WhiteAngel]    = pieceBitmap2[i][(int)WhiteFalcon];
1811            pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1812         }
1813       }
1814     }
1815 #if HAVE_LIBXPM
1816     CreateAnimVars();
1817 #endif
1818 }
1819 #endif
1820
1821 void ParseIcsTextColors()
1822 {   // [HGM] tken out of main(), so it can be called from ICS-Options dialog
1823     if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1824         parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1825         parse_cpair(ColorChannel1, appData.colorChannel1) < 0  ||
1826         parse_cpair(ColorChannel, appData.colorChannel) < 0  ||
1827         parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1828         parse_cpair(ColorTell, appData.colorTell) < 0 ||
1829         parse_cpair(ColorChallenge, appData.colorChallenge) < 0  ||
1830         parse_cpair(ColorRequest, appData.colorRequest) < 0  ||
1831         parse_cpair(ColorSeek, appData.colorSeek) < 0  ||
1832         parse_cpair(ColorNormal, appData.colorNormal) < 0)
1833       {
1834           if (appData.colorize) {
1835               fprintf(stderr,
1836                       _("%s: can't parse color names; disabling colorization\n"),
1837                       programName);
1838           }
1839           appData.colorize = FALSE;
1840       }
1841 }
1842
1843 int MakeColors()
1844 {   // [HGM] taken out of main(), so it can be called from BoardOptions dialog
1845     XrmValue vFrom, vTo;
1846     int forceMono = False;
1847
1848     if (!appData.monoMode) {
1849         vFrom.addr = (caddr_t) appData.lightSquareColor;
1850         vFrom.size = strlen(appData.lightSquareColor);
1851         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1852         if (vTo.addr == NULL) {
1853           appData.monoMode = True;
1854           forceMono = True;
1855         } else {
1856           lightSquareColor = *(Pixel *) vTo.addr;
1857         }
1858     }
1859     if (!appData.monoMode) {
1860         vFrom.addr = (caddr_t) appData.darkSquareColor;
1861         vFrom.size = strlen(appData.darkSquareColor);
1862         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1863         if (vTo.addr == NULL) {
1864           appData.monoMode = True;
1865           forceMono = True;
1866         } else {
1867           darkSquareColor = *(Pixel *) vTo.addr;
1868         }
1869     }
1870     if (!appData.monoMode) {
1871         vFrom.addr = (caddr_t) appData.whitePieceColor;
1872         vFrom.size = strlen(appData.whitePieceColor);
1873         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1874         if (vTo.addr == NULL) {
1875           appData.monoMode = True;
1876           forceMono = True;
1877         } else {
1878           whitePieceColor = *(Pixel *) vTo.addr;
1879         }
1880     }
1881     if (!appData.monoMode) {
1882         vFrom.addr = (caddr_t) appData.blackPieceColor;
1883         vFrom.size = strlen(appData.blackPieceColor);
1884         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1885         if (vTo.addr == NULL) {
1886           appData.monoMode = True;
1887           forceMono = True;
1888         } else {
1889           blackPieceColor = *(Pixel *) vTo.addr;
1890         }
1891     }
1892
1893     if (!appData.monoMode) {
1894         vFrom.addr = (caddr_t) appData.highlightSquareColor;
1895         vFrom.size = strlen(appData.highlightSquareColor);
1896         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1897         if (vTo.addr == NULL) {
1898           appData.monoMode = True;
1899           forceMono = True;
1900         } else {
1901           highlightSquareColor = *(Pixel *) vTo.addr;
1902         }
1903     }
1904
1905     if (!appData.monoMode) {
1906         vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1907         vFrom.size = strlen(appData.premoveHighlightColor);
1908         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1909         if (vTo.addr == NULL) {
1910           appData.monoMode = True;
1911           forceMono = True;
1912         } else {
1913           premoveHighlightColor = *(Pixel *) vTo.addr;
1914         }
1915     }
1916     return forceMono;
1917 }
1918
1919 void
1920 CreateAnyPieces()
1921 {   // [HGM] taken out of main
1922 #if HAVE_LIBXPM
1923     if (appData.monoMode && // [HGM] no sense to go on to certain doom
1924        (appData.bitmapDirectory == NULL || appData.bitmapDirectory[0] == NULLCHAR))
1925             appData.bitmapDirectory = DEF_BITMAP_DIR;
1926
1927     if (appData.bitmapDirectory[0] != NULLCHAR) {
1928       CreatePieces();
1929     } else {
1930       CreateXPMPieces();
1931       CreateXPMBoard(appData.liteBackTextureFile, 1);
1932       CreateXPMBoard(appData.darkBackTextureFile, 0);
1933     }
1934 #else
1935     CreateXIMPieces();
1936     /* Create regular pieces */
1937     if (!useImages) CreatePieces();
1938 #endif
1939 }
1940
1941 int
1942 main(argc, argv)
1943      int argc;
1944      char **argv;
1945 {
1946     int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1947     XSetWindowAttributes window_attributes;
1948     Arg args[16];
1949     Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1950     XrmValue vFrom, vTo;
1951     XtGeometryResult gres;
1952     char *p;
1953     XrmDatabase xdb;
1954     int forceMono = False;
1955
1956     srandom(time(0)); // [HGM] book: make random truly random
1957
1958     setbuf(stdout, NULL);
1959     setbuf(stderr, NULL);
1960     debugFP = stderr;
1961
1962     if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1963         printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1964         exit(0);
1965     }
1966
1967     programName = strrchr(argv[0], '/');
1968     if (programName == NULL)
1969       programName = argv[0];
1970     else
1971       programName++;
1972
1973 #ifdef ENABLE_NLS
1974     XtSetLanguageProc(NULL, NULL, NULL);
1975     bindtextdomain(PACKAGE, LOCALEDIR);
1976     textdomain(PACKAGE);
1977 #endif
1978
1979     shellWidget =
1980       XtAppInitialize(&appContext, "XBoard", shellOptions,
1981                       XtNumber(shellOptions),
1982                       &argc, argv, xboardResources, NULL, 0);
1983     appData.boardSize = "";
1984     InitAppData(ConvertToLine(argc, argv));
1985     p = getenv("HOME");
1986     if (p == NULL) p = "/tmp";
1987     i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1988     gameCopyFilename = (char*) malloc(i);
1989     gamePasteFilename = (char*) malloc(i);
1990     snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1991     snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1992
1993     XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1994                               clientResources, XtNumber(clientResources),
1995                               NULL, 0);
1996
1997     { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1998         static char buf[MSG_SIZ];
1999         EscapeExpand(buf, appData.firstInitString);
2000         appData.firstInitString = strdup(buf);
2001         EscapeExpand(buf, appData.secondInitString);
2002         appData.secondInitString = strdup(buf);
2003         EscapeExpand(buf, appData.firstComputerString);
2004         appData.firstComputerString = strdup(buf);
2005         EscapeExpand(buf, appData.secondComputerString);
2006         appData.secondComputerString = strdup(buf);
2007     }
2008
2009     if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
2010         chessDir = ".";
2011     } else {
2012         if (chdir(chessDir) != 0) {
2013             fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
2014             perror(chessDir);
2015             exit(1);
2016         }
2017     }
2018
2019     if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
2020         /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
2021         if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL)  {
2022            printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
2023            exit(errno);
2024         }
2025         setbuf(debugFP, NULL);
2026     }
2027
2028 #if ENABLE_NLS
2029     if (appData.debugMode) {
2030       fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
2031     }
2032 #endif
2033
2034     /* [HGM,HR] make sure board size is acceptable */
2035     if(appData.NrFiles > BOARD_FILES ||
2036        appData.NrRanks > BOARD_RANKS   )
2037          DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
2038
2039 #if !HIGHDRAG
2040     /* This feature does not work; animation needs a rewrite */
2041     appData.highlightDragging = FALSE;
2042 #endif
2043     InitBackEnd1();
2044
2045     xDisplay = XtDisplay(shellWidget);
2046     xScreen = DefaultScreen(xDisplay);
2047     wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
2048
2049         gameInfo.variant = StringToVariant(appData.variant);
2050         InitPosition(FALSE);
2051
2052 #ifdef IDSIZE
2053     InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
2054 #else
2055     if (isdigit(appData.boardSize[0])) {
2056         i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
2057                    &lineGap, &clockFontPxlSize, &coordFontPxlSize,
2058                    &fontPxlSize, &smallLayout, &tinyLayout);
2059         if (i == 0) {
2060             fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
2061                     programName, appData.boardSize);
2062             exit(2);
2063         }
2064         if (i < 7) {
2065             /* Find some defaults; use the nearest known size */
2066             SizeDefaults *szd, *nearest;
2067             int distance = 99999;
2068             nearest = szd = sizeDefaults;
2069             while (szd->name != NULL) {
2070                 if (abs(szd->squareSize - squareSize) < distance) {
2071                     nearest = szd;
2072                     distance = abs(szd->squareSize - squareSize);
2073                     if (distance == 0) break;
2074                 }
2075                 szd++;
2076             }
2077             if (i < 2) lineGap = nearest->lineGap;
2078             if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
2079             if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
2080             if (i < 5) fontPxlSize = nearest->fontPxlSize;
2081             if (i < 6) smallLayout = nearest->smallLayout;
2082             if (i < 7) tinyLayout = nearest->tinyLayout;
2083         }
2084     } else {
2085         SizeDefaults *szd = sizeDefaults;
2086         if (*appData.boardSize == NULLCHAR) {
2087             while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
2088                    DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
2089               szd++;
2090             }
2091             if (szd->name == NULL) szd--;
2092             appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
2093         } else {
2094             while (szd->name != NULL &&
2095                    StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
2096             if (szd->name == NULL) {
2097                 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
2098                         programName, appData.boardSize);
2099                 exit(2);
2100             }
2101         }
2102         squareSize = szd->squareSize;
2103         lineGap = szd->lineGap;
2104         clockFontPxlSize = szd->clockFontPxlSize;
2105         coordFontPxlSize = szd->coordFontPxlSize;
2106         fontPxlSize = szd->fontPxlSize;
2107         smallLayout = szd->smallLayout;
2108         tinyLayout = szd->tinyLayout;
2109         // [HGM] font: use defaults from settings file if available and not overruled
2110     }
2111     if(!fontIsSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
2112         appData.clockFont = fontTable[CLOCK_FONT][squareSize];
2113     if(!fontIsSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
2114         appData.font = fontTable[MESSAGE_FONT][squareSize];
2115     if(!fontIsSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
2116         appData.coordFont = fontTable[COORD_FONT][squareSize];
2117
2118     /* Now, using squareSize as a hint, find a good XPM/XIM set size */
2119     if (strlen(appData.pixmapDirectory) > 0) {
2120         p = ExpandPathName(appData.pixmapDirectory);
2121         if (!p) {
2122             fprintf(stderr, _("Error expanding path name \"%s\"\n"),
2123                    appData.pixmapDirectory);
2124             exit(1);
2125         }
2126         if (appData.debugMode) {
2127           fprintf(stderr, _("\
2128 XBoard square size (hint): %d\n\
2129 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
2130         }
2131         squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
2132         if (appData.debugMode) {
2133             fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
2134         }
2135     }
2136     defaultLineGap = lineGap;
2137     if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
2138
2139     /* [HR] height treated separately (hacked) */
2140     boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
2141     boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
2142     if (appData.showJail == 1) {
2143         /* Jail on top and bottom */
2144         XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2145         XtSetArg(boardArgs[2], XtNheight,
2146                  boardHeight + 2*(lineGap + squareSize));
2147     } else if (appData.showJail == 2) {
2148         /* Jail on sides */
2149         XtSetArg(boardArgs[1], XtNwidth,
2150                  boardWidth + 2*(lineGap + squareSize));
2151         XtSetArg(boardArgs[2], XtNheight, boardHeight);
2152     } else {
2153         /* No jail */
2154         XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2155         XtSetArg(boardArgs[2], XtNheight, boardHeight);
2156     }
2157
2158     /*
2159      * Determine what fonts to use.
2160      */
2161 #if ENABLE_NLS
2162     appData.font = InsertPxlSize(appData.font, fontPxlSize);
2163     appData.clockFont = InsertPxlSize(appData.clockFont, clockFontPxlSize);
2164     appData.coordFont = InsertPxlSize(appData.coordFont, coordFontPxlSize);
2165     fontSet = CreateFontSet(appData.font);
2166     clockFontSet = CreateFontSet(appData.clockFont);
2167     {
2168       /* For the coordFont, use the 0th font of the fontset. */
2169       XFontSet coordFontSet = CreateFontSet(appData.coordFont);
2170       XFontStruct **font_struct_list;
2171       char **font_name_list;
2172       XFontsOfFontSet(coordFontSet, &font_struct_list, &font_name_list);
2173       coordFontID = XLoadFont(xDisplay, font_name_list[0]);
2174       coordFontStruct = XQueryFont(xDisplay, coordFontID);
2175     }
2176 #else
2177     appData.font = FindFont(appData.font, fontPxlSize);
2178     appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2179     appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2180     clockFontID = XLoadFont(xDisplay, appData.clockFont);
2181     clockFontStruct = XQueryFont(xDisplay, clockFontID);
2182     coordFontID = XLoadFont(xDisplay, appData.coordFont);
2183     coordFontStruct = XQueryFont(xDisplay, coordFontID);
2184 #endif
2185     countFontID = coordFontID;  // [HGM] holdings
2186     countFontStruct = coordFontStruct;
2187
2188     xdb = XtDatabase(xDisplay);
2189 #if ENABLE_NLS
2190     XrmPutLineResource(&xdb, "*international: True");
2191     vTo.size = sizeof(XFontSet);
2192     vTo.addr = (XtPointer) &fontSet;
2193     XrmPutResource(&xdb, "*fontSet", XtRFontSet, &vTo);
2194 #else
2195     XrmPutStringResource(&xdb, "*font", appData.font);
2196 #endif
2197
2198     /*
2199      * Detect if there are not enough colors available and adapt.
2200      */
2201     if (DefaultDepth(xDisplay, xScreen) <= 2) {
2202       appData.monoMode = True;
2203     }
2204
2205     forceMono = MakeColors();
2206
2207     if (forceMono) {
2208       fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2209               programName);
2210         appData.monoMode = True;
2211     }
2212
2213     if (appData.lowTimeWarning && !appData.monoMode) {
2214       vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2215       vFrom.size = strlen(appData.lowTimeWarningColor);
2216       XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2217       if (vTo.addr == NULL)
2218                 appData.monoMode = True;
2219       else
2220                 lowTimeWarningColor = *(Pixel *) vTo.addr;
2221     }
2222
2223     if (appData.monoMode && appData.debugMode) {
2224         fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2225                 (unsigned long) XWhitePixel(xDisplay, xScreen),
2226                 (unsigned long) XBlackPixel(xDisplay, xScreen));
2227     }
2228
2229     ParseIcsTextColors();
2230     textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2231     textColors[ColorNone].attr = 0;
2232
2233     XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2234
2235     /*
2236      * widget hierarchy
2237      */
2238     if (tinyLayout) {
2239         layoutName = "tinyLayout";
2240     } else if (smallLayout) {
2241         layoutName = "smallLayout";
2242     } else {
2243         layoutName = "normalLayout";
2244     }
2245     /* Outer layoutWidget is there only to provide a name for use in
2246        resources that depend on the layout style */
2247     layoutWidget =
2248       XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2249                             layoutArgs, XtNumber(layoutArgs));
2250     formWidget =
2251       XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2252                             formArgs, XtNumber(formArgs));
2253     XtSetArg(args[0], XtNdefaultDistance, &sep);
2254     XtGetValues(formWidget, args, 1);
2255
2256     j = 0;
2257     widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2258     XtSetArg(args[0], XtNtop,    XtChainTop);
2259     XtSetArg(args[1], XtNbottom, XtChainTop);
2260     XtSetArg(args[2], XtNright,  XtChainLeft);
2261     XtSetValues(menuBarWidget, args, 3);
2262
2263     widgetList[j++] = whiteTimerWidget =
2264       XtCreateWidget("whiteTime", labelWidgetClass,
2265                      formWidget, timerArgs, XtNumber(timerArgs));
2266 #if ENABLE_NLS
2267     XtSetArg(args[0], XtNfontSet, clockFontSet);
2268 #else
2269     XtSetArg(args[0], XtNfont, clockFontStruct);
2270 #endif
2271     XtSetArg(args[1], XtNtop,    XtChainTop);
2272     XtSetArg(args[2], XtNbottom, XtChainTop);
2273     XtSetValues(whiteTimerWidget, args, 3);
2274
2275     widgetList[j++] = blackTimerWidget =
2276       XtCreateWidget("blackTime", labelWidgetClass,
2277                      formWidget, timerArgs, XtNumber(timerArgs));
2278 #if ENABLE_NLS
2279     XtSetArg(args[0], XtNfontSet, clockFontSet);
2280 #else
2281     XtSetArg(args[0], XtNfont, clockFontStruct);
2282 #endif
2283     XtSetArg(args[1], XtNtop,    XtChainTop);
2284     XtSetArg(args[2], XtNbottom, XtChainTop);
2285     XtSetValues(blackTimerWidget, args, 3);
2286
2287     if (appData.titleInWindow) {
2288         widgetList[j++] = titleWidget =
2289           XtCreateWidget("title", labelWidgetClass, formWidget,
2290                          titleArgs, XtNumber(titleArgs));
2291         XtSetArg(args[0], XtNtop,    XtChainTop);
2292         XtSetArg(args[1], XtNbottom, XtChainTop);
2293         XtSetValues(titleWidget, args, 2);
2294     }
2295
2296     if (appData.showButtonBar) {
2297       widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2298       XtSetArg(args[0], XtNleft,  XtChainRight); // [HGM] glue to right window edge
2299       XtSetArg(args[1], XtNright, XtChainRight); //       for good run-time sizing
2300       XtSetArg(args[2], XtNtop,    XtChainTop);
2301       XtSetArg(args[3], XtNbottom, XtChainTop);
2302       XtSetValues(buttonBarWidget, args, 4);
2303     }
2304
2305     widgetList[j++] = messageWidget =
2306       XtCreateWidget("message", labelWidgetClass, formWidget,
2307                      messageArgs, XtNumber(messageArgs));
2308     XtSetArg(args[0], XtNtop,    XtChainTop);
2309     XtSetArg(args[1], XtNbottom, XtChainTop);
2310     XtSetValues(messageWidget, args, 2);
2311
2312     widgetList[j++] = boardWidget =
2313       XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2314                      XtNumber(boardArgs));
2315
2316     XtManageChildren(widgetList, j);
2317
2318     timerWidth = (boardWidth - sep) / 2;
2319     XtSetArg(args[0], XtNwidth, timerWidth);
2320     XtSetValues(whiteTimerWidget, args, 1);
2321     XtSetValues(blackTimerWidget, args, 1);
2322
2323     XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2324     XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2325     XtGetValues(whiteTimerWidget, args, 2);
2326
2327     if (appData.showButtonBar) {
2328       XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2329       XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2330       XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2331     }
2332
2333     /*
2334      * formWidget uses these constraints but they are stored
2335      * in the children.
2336      */
2337     i = 0;
2338     XtSetArg(args[i], XtNfromHoriz, 0); i++;
2339     XtSetValues(menuBarWidget, args, i);
2340     if (appData.titleInWindow) {
2341         if (smallLayout) {
2342             i = 0;
2343             XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2344             XtSetValues(whiteTimerWidget, args, i);
2345             i = 0;
2346             XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2347             XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2348             XtSetValues(blackTimerWidget, args, i);
2349             i = 0;
2350             XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2351             XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2352             XtSetValues(titleWidget, args, i);
2353             i = 0;
2354             XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2355             XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2356             XtSetValues(messageWidget, args, i);
2357             if (appData.showButtonBar) {
2358               i = 0;
2359               XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2360               XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2361               XtSetValues(buttonBarWidget, args, i);
2362             }
2363         } else {
2364             i = 0;
2365             XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2366             XtSetValues(whiteTimerWidget, args, i);
2367             i = 0;
2368             XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2369             XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2370             XtSetValues(blackTimerWidget, args, i);
2371             i = 0;
2372             XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2373             XtSetValues(titleWidget, args, i);
2374             i = 0;
2375             XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2376             XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2377             XtSetValues(messageWidget, args, i);
2378             if (appData.showButtonBar) {
2379               i = 0;
2380               XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2381               XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2382               XtSetValues(buttonBarWidget, args, i);
2383             }
2384         }
2385     } else {
2386         i = 0;
2387         XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2388         XtSetValues(whiteTimerWidget, args, i);
2389         i = 0;
2390         XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2391         XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2392         XtSetValues(blackTimerWidget, args, i);
2393         i = 0;
2394         XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2395         XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2396         XtSetValues(messageWidget, args, i);
2397         if (appData.showButtonBar) {
2398           i = 0;
2399           XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2400           XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2401           XtSetValues(buttonBarWidget, args, i);
2402         }
2403     }
2404     i = 0;
2405     XtSetArg(args[0], XtNfromVert, messageWidget);
2406     XtSetArg(args[1], XtNtop,    XtChainTop);
2407     XtSetArg(args[2], XtNbottom, XtChainBottom);
2408     XtSetArg(args[3], XtNleft,   XtChainLeft);
2409     XtSetArg(args[4], XtNright,  XtChainRight);
2410     XtSetValues(boardWidget, args, 5);
2411
2412     XtRealizeWidget(shellWidget);
2413
2414     if(wpMain.x > 0) {
2415       XtSetArg(args[0], XtNx, wpMain.x);
2416       XtSetArg(args[1], XtNy, wpMain.y);
2417       XtSetValues(shellWidget, args, 2);
2418     }
2419
2420     /*
2421      * Correct the width of the message and title widgets.
2422      * It is not known why some systems need the extra fudge term.
2423      * The value "2" is probably larger than needed.
2424      */
2425     XawFormDoLayout(formWidget, False);
2426
2427 #define WIDTH_FUDGE 2
2428     i = 0;
2429     XtSetArg(args[i], XtNborderWidth, &bor);  i++;
2430     XtSetArg(args[i], XtNheight, &h);  i++;
2431     XtGetValues(messageWidget, args, i);
2432     if (appData.showButtonBar) {
2433       i = 0;
2434       XtSetArg(args[i], XtNwidth, &w);  i++;
2435       XtGetValues(buttonBarWidget, args, i);
2436       w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2437     } else {
2438       w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2439     }
2440
2441     gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2442     if (gres != XtGeometryYes && appData.debugMode) {
2443       fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2444               programName, gres, w, h, wr, hr);
2445     }
2446
2447     /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2448     /* The size used for the child widget in layout lags one resize behind
2449        its true size, so we resize a second time, 1 pixel smaller.  Yeech! */
2450     w--;
2451     gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2452     if (gres != XtGeometryYes && appData.debugMode) {
2453       fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2454               programName, gres, w, h, wr, hr);
2455     }
2456     /* !! end hack */
2457     XtSetArg(args[0], XtNleft,  XtChainLeft);  // [HGM] glue ends for good run-time sizing
2458     XtSetArg(args[1], XtNright, XtChainRight);
2459     XtSetValues(messageWidget, args, 2);
2460
2461     if (appData.titleInWindow) {
2462         i = 0;
2463         XtSetArg(args[i], XtNborderWidth, &bor); i++;
2464         XtSetArg(args[i], XtNheight, &h);  i++;
2465         XtGetValues(titleWidget, args, i);
2466         if (smallLayout) {
2467             w = boardWidth - 2*bor;
2468         } else {
2469             XtSetArg(args[0], XtNwidth, &w);
2470             XtGetValues(menuBarWidget, args, 1);
2471             w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2472         }
2473
2474         gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2475         if (gres != XtGeometryYes && appData.debugMode) {
2476             fprintf(stderr,
2477                     _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2478                     programName, gres, w, h, wr, hr);
2479         }
2480     }
2481     XawFormDoLayout(formWidget, True);
2482
2483     xBoardWindow = XtWindow(boardWidget);
2484
2485     // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2486     //       not need to go into InitDrawingSizes().
2487 #endif
2488
2489     /*
2490      * Create X checkmark bitmap and initialize option menu checks.
2491      */
2492     ReadBitmap(&xMarkPixmap, "checkmark.bm",
2493                checkmark_bits, checkmark_width, checkmark_height);
2494     XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2495 #ifndef OPTIONSDIALOG
2496     if (appData.alwaysPromoteToQueen) {
2497         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2498                     args, 1);
2499     }
2500     if (appData.animateDragging) {
2501         XtSetValues(XtNameToWidget(menuBarWidget,
2502                                    "menuOptions.Animate Dragging"),
2503                     args, 1);
2504     }
2505     if (appData.animate) {
2506         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2507                     args, 1);
2508     }
2509     if (appData.autoCallFlag) {
2510         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2511                     args, 1);
2512     }
2513     if (appData.autoFlipView) {
2514         XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2515                     args, 1);
2516     }
2517     if (appData.blindfold) {
2518         XtSetValues(XtNameToWidget(menuBarWidget,
2519                                    "menuOptions.Blindfold"), args, 1);
2520     }
2521     if (appData.flashCount > 0) {
2522         XtSetValues(XtNameToWidget(menuBarWidget,
2523                                    "menuOptions.Flash Moves"),
2524                     args, 1);
2525     }
2526 #if HIGHDRAG
2527     if (appData.highlightDragging) {
2528         XtSetValues(XtNameToWidget(menuBarWidget,
2529                                    "menuOptions.Highlight Dragging"),
2530                     args, 1);
2531     }
2532 #endif
2533     if (appData.highlightLastMove) {
2534         XtSetValues(XtNameToWidget(menuBarWidget,
2535                                    "menuOptions.Highlight Last Move"),
2536                     args, 1);
2537     }
2538     if (appData.highlightMoveWithArrow) {
2539         XtSetValues(XtNameToWidget(menuBarWidget,
2540                                    "menuOptions.Arrow"),
2541                     args, 1);
2542     }
2543 //    if (appData.icsAlarm) {
2544 //      XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2545 //                  args, 1);
2546 //    }
2547     if (appData.ringBellAfterMoves) {
2548         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2549                     args, 1);
2550     }
2551     if (appData.oneClick) {
2552         XtSetValues(XtNameToWidget(menuBarWidget,
2553                                    "menuOptions.OneClick"), args, 1);
2554     }
2555     if (appData.periodicUpdates) {
2556         XtSetValues(XtNameToWidget(menuBarWidget,
2557                                    "menuOptions.Periodic Updates"), args, 1);
2558     }
2559     if (appData.ponderNextMove) {
2560         XtSetValues(XtNameToWidget(menuBarWidget,
2561                                    "menuOptions.Ponder Next Move"), args, 1);
2562     }
2563     if (appData.popupExitMessage) {
2564         XtSetValues(XtNameToWidget(menuBarWidget,
2565                                    "menuOptions.Popup Exit Message"), args, 1);
2566     }
2567     if (appData.popupMoveErrors) {
2568         XtSetValues(XtNameToWidget(menuBarWidget,
2569                                    "menuOptions.Popup Move Errors"), args, 1);
2570     }
2571 //    if (appData.premove) {
2572 //      XtSetValues(XtNameToWidget(menuBarWidget,
2573 //                                 "menuOptions.Premove"), args, 1);
2574 //    }
2575     if (appData.showCoords) {
2576         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2577                     args, 1);
2578     }
2579     if (appData.hideThinkingFromHuman) {
2580         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2581                     args, 1);
2582     }
2583     if (appData.testLegality) {
2584         XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2585                     args, 1);
2586     }
2587 #endif
2588     if (saveSettingsOnExit) {
2589         XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2590                     args, 1);
2591     }
2592
2593     /*
2594      * Create an icon.
2595      */
2596     ReadBitmap(&wIconPixmap, "icon_white.bm",
2597                icon_white_bits, icon_white_width, icon_white_height);
2598     ReadBitmap(&bIconPixmap, "icon_black.bm",
2599                icon_black_bits, icon_black_width, icon_black_height);
2600     iconPixmap = wIconPixmap;
2601     i = 0;
2602     XtSetArg(args[i], XtNiconPixmap, iconPixmap);  i++;
2603     XtSetValues(shellWidget, args, i);
2604
2605     /*
2606      * Create a cursor for the board widget.
2607      */
2608     window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2609     XChangeWindowAttributes(xDisplay, xBoardWindow,
2610                             CWCursor, &window_attributes);
2611
2612     /*
2613      * Inhibit shell resizing.
2614      */
2615     shellArgs[0].value = (XtArgVal) &w;
2616     shellArgs[1].value = (XtArgVal) &h;
2617     XtGetValues(shellWidget, shellArgs, 2);
2618     shellArgs[4].value = shellArgs[2].value = w;
2619     shellArgs[5].value = shellArgs[3].value = h;
2620     XtSetValues(shellWidget, &shellArgs[2], 4);
2621     marginW =  w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2622     marginH =  h - boardHeight;
2623
2624     CatchDeleteWindow(shellWidget, "QuitProc");
2625
2626     CreateGCs(False);
2627     CreateGrid();
2628     CreateAnyPieces();
2629
2630     CreatePieceMenus();
2631
2632     if (appData.animate || appData.animateDragging)
2633       CreateAnimVars();
2634
2635     XtAugmentTranslations(formWidget,
2636                           XtParseTranslationTable(globalTranslations));
2637     XtAugmentTranslations(boardWidget,
2638                           XtParseTranslationTable(boardTranslations));
2639     XtAugmentTranslations(whiteTimerWidget,
2640                           XtParseTranslationTable(whiteTranslations));
2641     XtAugmentTranslations(blackTimerWidget,
2642                           XtParseTranslationTable(blackTranslations));
2643
2644     /* Why is the following needed on some versions of X instead
2645      * of a translation? */
2646     XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2647                       (XtEventHandler) EventProc, NULL);
2648     /* end why */
2649     XtAddEventHandler(formWidget, KeyPressMask, False,
2650                       (XtEventHandler) MoveTypeInProc, NULL);
2651
2652     /* [AS] Restore layout */
2653     if( wpMoveHistory.visible ) {
2654       HistoryPopUp();
2655     }
2656
2657     if( wpEvalGraph.visible )
2658       {
2659         EvalGraphPopUp();
2660       };
2661
2662     if( wpEngineOutput.visible ) {
2663       EngineOutputPopUp();
2664     }
2665
2666     InitBackEnd2();
2667
2668     if (errorExitStatus == -1) {
2669         if (appData.icsActive) {
2670             /* We now wait until we see "login:" from the ICS before
2671                sending the logon script (problems with timestamp otherwise) */
2672             /*ICSInitScript();*/
2673             if (appData.icsInputBox) ICSInputBoxPopUp();
2674         }
2675
2676     #ifdef SIGWINCH
2677     signal(SIGWINCH, TermSizeSigHandler);
2678     #endif
2679         signal(SIGINT, IntSigHandler);
2680         signal(SIGTERM, IntSigHandler);
2681         if (*appData.cmailGameName != NULLCHAR) {
2682             signal(SIGUSR1, CmailSigHandler);
2683         }
2684     }
2685     gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2686     InitPosition(TRUE);
2687 //    XtSetKeyboardFocus(shellWidget, formWidget);
2688     XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
2689
2690     XtAppMainLoop(appContext);
2691     if (appData.debugMode) fclose(debugFP); // [DM] debug
2692     return 0;
2693 }
2694
2695 void
2696 ShutDownFrontEnd()
2697 {
2698     if (appData.icsActive && oldICSInteractionTitle != NULL) {
2699         DisplayIcsInteractionTitle(oldICSInteractionTitle);
2700     }
2701     if (saveSettingsOnExit) SaveSettings(settingsFileName);
2702     unlink(gameCopyFilename);
2703     unlink(gamePasteFilename);
2704 }
2705
2706 RETSIGTYPE TermSizeSigHandler(int sig)
2707 {
2708     update_ics_width();
2709 }
2710
2711 RETSIGTYPE
2712 IntSigHandler(sig)
2713      int sig;
2714 {
2715     ExitEvent(sig);
2716 }
2717
2718 RETSIGTYPE
2719 CmailSigHandler(sig)
2720      int sig;
2721 {
2722     int dummy = 0;
2723     int error;
2724
2725     signal(SIGUSR1, SIG_IGN);   /* suspend handler     */
2726
2727     /* Activate call-back function CmailSigHandlerCallBack()             */
2728     OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2729
2730     signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2731 }
2732
2733 void
2734 CmailSigHandlerCallBack(isr, closure, message, count, error)
2735      InputSourceRef isr;
2736      VOIDSTAR closure;
2737      char *message;
2738      int count;
2739      int error;
2740 {
2741     BoardToTop();
2742     ReloadCmailMsgEvent(TRUE);  /* Reload cmail msg  */
2743 }
2744 /**** end signal code ****/
2745
2746
2747 void
2748 ICSInitScript()
2749 {
2750   /* try to open the icsLogon script, either in the location given
2751    * or in the users HOME directory
2752    */
2753
2754   FILE *f;
2755   char buf[MSG_SIZ];
2756   char *homedir;
2757
2758   f = fopen(appData.icsLogon, "r");
2759   if (f == NULL)
2760     {
2761       homedir = getenv("HOME");
2762       if (homedir != NULL)
2763         {
2764           safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2765           strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2766           strncat(buf, appData.icsLogon,  MSG_SIZ - strlen(buf) - 1);
2767           f = fopen(buf, "r");
2768         }
2769     }
2770
2771   if (f != NULL)
2772     ProcessICSInitScript(f);
2773   else
2774     printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2775
2776   return;
2777 }
2778
2779 void
2780 ResetFrontEnd()
2781 {
2782     CommentPopDown();
2783     TagsPopDown();
2784     return;
2785 }
2786
2787 typedef struct {
2788     char *name;
2789     Boolean value;
2790 } Enables;
2791
2792 void
2793 GreyRevert(grey)
2794      Boolean grey;
2795 {
2796     Widget w;
2797     if (!menuBarWidget) return;
2798     w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2799     if (w == NULL) {
2800       DisplayError("menuEdit.Revert", 0);
2801     } else {
2802       XtSetSensitive(w, !grey);
2803     }
2804     w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2805     if (w == NULL) {
2806       DisplayError("menuEdit.Annotate", 0);
2807     } else {
2808       XtSetSensitive(w, !grey);
2809     }
2810 }
2811
2812 void
2813 SetMenuEnables(enab)
2814      Enables *enab;
2815 {
2816   Widget w;
2817   if (!menuBarWidget) return;
2818   while (enab->name != NULL) {
2819     w = XtNameToWidget(menuBarWidget, enab->name);
2820     if (w == NULL) {
2821       DisplayError(enab->name, 0);
2822     } else {
2823       XtSetSensitive(w, enab->value);
2824     }
2825     enab++;
2826   }
2827 }
2828
2829 Enables icsEnables[] = {
2830     { "menuFile.Mail Move", False },
2831     { "menuFile.Reload CMail Message", False },
2832     { "menuMode.Machine Black", False },
2833     { "menuMode.Machine White", False },
2834     { "menuMode.Analysis Mode", False },
2835     { "menuMode.Analyze File", False },
2836     { "menuMode.Two Machines", False },
2837     { "menuMode.Machine Match", False },
2838 #ifndef ZIPPY
2839     { "menuEngine.Hint", False },
2840     { "menuEngine.Book", False },
2841     { "menuEngine.Move Now", False },
2842 #ifndef OPTIONSDIALOG
2843     { "menuOptions.Periodic Updates", False },
2844     { "menuOptions.Hide Thinking", False },
2845     { "menuOptions.Ponder Next Move", False },
2846 #endif
2847 #endif
2848     { "menuEngine.Engine #1 Settings", False },
2849     { "menuEngine.Engine #2 Settings", False },
2850     { "menuEngine.Load Engine", False },
2851     { "menuEdit.Annotate", False },
2852     { "menuOptions.Match", False },
2853     { NULL, False }
2854 };
2855
2856 Enables ncpEnables[] = {
2857     { "menuFile.Mail Move", False },
2858     { "menuFile.Reload CMail Message", False },
2859     { "menuMode.Machine White", False },
2860     { "menuMode.Machine Black", False },
2861     { "menuMode.Analysis Mode", False },
2862     { "menuMode.Analyze File", False },
2863     { "menuMode.Two Machines", False },
2864     { "menuMode.Machine Match", False },
2865     { "menuMode.ICS Client", False },
2866     { "menuView.ICStex", False },
2867     { "menuView.ICS Input Box", False },
2868     { "Action", False },
2869     { "menuEdit.Revert", False },
2870     { "menuEdit.Annotate", False },
2871     { "menuEngine.Engine #1 Settings", False },
2872     { "menuEngine.Engine #2 Settings", False },
2873     { "menuEngine.Move Now", False },
2874     { "menuEngine.Retract Move", False },
2875     { "menuOptions.ICS", False },
2876 #ifndef OPTIONSDIALOG
2877     { "menuOptions.Auto Flag", False },
2878     { "menuOptions.Auto Flip View", False },
2879 //    { "menuOptions.ICS Alarm", False },
2880     { "menuOptions.Move Sound", False },
2881     { "menuOptions.Hide Thinking", False },
2882     { "menuOptions.Periodic Updates", False },
2883     { "menuOptions.Ponder Next Move", False },
2884 #endif
2885     { "menuEngine.Hint", False },
2886     { "menuEngine.Book", False },
2887     { NULL, False }
2888 };
2889
2890 Enables gnuEnables[] = {
2891     { "menuMode.ICS Client", False },
2892     { "menuView.ICStex", False },
2893     { "menuView.ICS Input Box", False },
2894     { "menuAction.Accept", False },
2895     { "menuAction.Decline", False },
2896     { "menuAction.Rematch", False },
2897     { "menuAction.Adjourn", False },
2898     { "menuAction.Stop Examining", False },
2899     { "menuAction.Stop Observing", False },
2900     { "menuAction.Upload to Examine", False },
2901     { "menuEdit.Revert", False },
2902     { "menuEdit.Annotate", False },
2903     { "menuOptions.ICS", False },
2904
2905     /* The next two options rely on SetCmailMode being called *after*    */
2906     /* SetGNUMode so that when GNU is being used to give hints these     */
2907     /* menu options are still available                                  */
2908
2909     { "menuFile.Mail Move", False },
2910     { "menuFile.Reload CMail Message", False },
2911     // [HGM] The following have been added to make a switch from ncp to GNU mode possible
2912     { "menuMode.Machine White", True },
2913     { "menuMode.Machine Black", True },
2914     { "menuMode.Analysis Mode", True },
2915     { "menuMode.Analyze File", True },
2916     { "menuMode.Two Machines", True },
2917     { "menuMode.Machine Match", True },
2918     { "menuEngine.Engine #1 Settings", True },
2919     { "menuEngine.Engine #2 Settings", True },
2920     { "menuEngine.Hint", True },
2921     { "menuEngine.Book", True },
2922     { "menuEngine.Move Now", True },
2923     { "menuEngine.Retract Move", True },
2924     { "Action", True },
2925     { NULL, False }
2926 };
2927
2928 Enables cmailEnables[] = {
2929     { "Action", True },
2930     { "menuAction.Call Flag", False },
2931     { "menuAction.Draw", True },
2932     { "menuAction.Adjourn", False },
2933     { "menuAction.Abort", False },
2934     { "menuAction.Stop Observing", False },
2935     { "menuAction.Stop Examining", False },
2936     { "menuFile.Mail Move", True },
2937     { "menuFile.Reload CMail Message", True },
2938     { NULL, False }
2939 };
2940
2941 Enables trainingOnEnables[] = {
2942   { "menuMode.Edit Comment", False },
2943   { "menuMode.Pause", False },
2944   { "menuEdit.Forward", False },
2945   { "menuEdit.Backward", False },
2946   { "menuEdit.Forward to End", False },
2947   { "menuEdit.Back to Start", False },
2948   { "menuEngine.Move Now", False },
2949   { "menuEdit.Truncate Game", False },
2950   { NULL, False }
2951 };
2952
2953 Enables trainingOffEnables[] = {
2954   { "menuMode.Edit Comment", True },
2955   { "menuMode.Pause", True },
2956   { "menuEdit.Forward", True },
2957   { "menuEdit.Backward", True },
2958   { "menuEdit.Forward to End", True },
2959   { "menuEdit.Back to Start", True },
2960   { "menuEngine.Move Now", True },
2961   { "menuEdit.Truncate Game", True },
2962   { NULL, False }
2963 };
2964
2965 Enables machineThinkingEnables[] = {
2966   { "menuFile.Load Game", False },
2967 //  { "menuFile.Load Next Game", False },
2968 //  { "menuFile.Load Previous Game", False },
2969 //  { "menuFile.Reload Same Game", False },
2970   { "menuEdit.Paste Game", False },
2971   { "menuFile.Load Position", False },
2972 //  { "menuFile.Load Next Position", False },
2973 //  { "menuFile.Load Previous Position", False },
2974 //  { "menuFile.Reload Same Position", False },
2975   { "menuEdit.Paste Position", False },
2976   { "menuMode.Machine White", False },
2977   { "menuMode.Machine Black", False },
2978   { "menuMode.Two Machines", False },
2979 //  { "menuMode.Machine Match", False },
2980   { "menuEngine.Retract Move", False },
2981   { NULL, False }
2982 };
2983
2984 Enables userThinkingEnables[] = {
2985   { "menuFile.Load Game", True },
2986 //  { "menuFile.Load Next Game", True },
2987 //  { "menuFile.Load Previous Game", True },
2988 //  { "menuFile.Reload Same Game", True },
2989   { "menuEdit.Paste Game", True },
2990   { "menuFile.Load Position", True },
2991 //  { "menuFile.Load Next Position", True },
2992 //  { "menuFile.Load Previous Position", True },
2993 //  { "menuFile.Reload Same Position", True },
2994   { "menuEdit.Paste Position", True },
2995   { "menuMode.Machine White", True },
2996   { "menuMode.Machine Black", True },
2997   { "menuMode.Two Machines", True },
2998 //  { "menuMode.Machine Match", True },
2999   { "menuEngine.Retract Move", True },
3000   { NULL, False }
3001 };
3002
3003 void SetICSMode()
3004 {
3005   SetMenuEnables(icsEnables);
3006
3007 #if ZIPPY
3008   if (appData.zippyPlay && !appData.noChessProgram) { /* [DM] icsEngineAnalyze */
3009      XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
3010      XtSetSensitive(XtNameToWidget(menuBarWidget, "menuEngine.Engine #1 Settings"), True);
3011   }
3012 #endif
3013 }
3014
3015 void
3016 SetNCPMode()
3017 {
3018   SetMenuEnables(ncpEnables);
3019 }
3020
3021 void
3022 SetGNUMode()
3023 {
3024   SetMenuEnables(gnuEnables);
3025 }
3026
3027 void
3028 SetCmailMode()
3029 {
3030   SetMenuEnables(cmailEnables);
3031 }
3032
3033 void
3034 SetTrainingModeOn()
3035 {
3036   SetMenuEnables(trainingOnEnables);
3037   if (appData.showButtonBar) {
3038     XtSetSensitive(buttonBarWidget, False);
3039   }
3040   CommentPopDown();
3041 }
3042
3043 void
3044 SetTrainingModeOff()
3045 {
3046   SetMenuEnables(trainingOffEnables);
3047   if (appData.showButtonBar) {
3048     XtSetSensitive(buttonBarWidget, True);
3049   }
3050 }
3051
3052 void
3053 SetUserThinkingEnables()
3054 {
3055   if (appData.noChessProgram) return;
3056   SetMenuEnables(userThinkingEnables);
3057 }
3058
3059 void
3060 SetMachineThinkingEnables()
3061 {
3062   if (appData.noChessProgram) return;
3063   SetMenuEnables(machineThinkingEnables);
3064   switch (gameMode) {
3065   case MachinePlaysBlack:
3066   case MachinePlaysWhite:
3067   case TwoMachinesPlay:
3068     XtSetSensitive(XtNameToWidget(menuBarWidget,
3069                                   ModeToWidgetName(gameMode)), True);
3070     break;
3071   default:
3072     break;
3073   }
3074 }
3075
3076 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
3077 #define HISTORY_SIZE 64
3078 static char *history[HISTORY_SIZE];
3079 int histIn = 0, histP = 0;
3080
3081 void
3082 SaveInHistory(char *cmd)
3083 {
3084   if (history[histIn] != NULL) {
3085     free(history[histIn]);
3086     history[histIn] = NULL;
3087   }
3088   if (*cmd == NULLCHAR) return;
3089   history[histIn] = StrSave(cmd);
3090   histIn = (histIn + 1) % HISTORY_SIZE;
3091   if (history[histIn] != NULL) {
3092     free(history[histIn]);
3093     history[histIn] = NULL;
3094   }
3095   histP = histIn;
3096 }
3097
3098 char *
3099 PrevInHistory(char *cmd)
3100 {
3101   int newhp;
3102   if (histP == histIn) {
3103     if (history[histIn] != NULL) free(history[histIn]);
3104     history[histIn] = StrSave(cmd);
3105   }
3106   newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
3107   if (newhp == histIn || history[newhp] == NULL) return NULL;
3108   histP = newhp;
3109   return history[histP];
3110 }
3111
3112 char *
3113 NextInHistory()
3114 {
3115   if (histP == histIn) return NULL;
3116   histP = (histP + 1) % HISTORY_SIZE;
3117   return history[histP];   
3118 }
3119 // end of borrowed code
3120
3121 #define Abs(n) ((n)<0 ? -(n) : (n))
3122
3123 #ifdef ENABLE_NLS
3124 char *
3125 InsertPxlSize(pattern, targetPxlSize)
3126      char *pattern;
3127      int targetPxlSize;
3128 {
3129     char *base_fnt_lst, strInt[12], *p, *q;
3130     int alternatives, i, len, strIntLen;
3131
3132     /*
3133      * Replace the "*" (if present) in the pixel-size slot of each
3134      * alternative with the targetPxlSize.
3135      */
3136     p = pattern;
3137     alternatives = 1;
3138     while ((p = strchr(p, ',')) != NULL) {
3139       alternatives++;
3140       p++;
3141     }
3142     snprintf(strInt, sizeof(strInt), "%d", targetPxlSize);
3143     strIntLen = strlen(strInt);
3144     base_fnt_lst = calloc(1, strlen(pattern) + strIntLen * alternatives + 1);
3145
3146     p = pattern;
3147     q = base_fnt_lst;
3148     while (alternatives--) {
3149       char *comma = strchr(p, ',');
3150       for (i=0; i<14; i++) {
3151         char *hyphen = strchr(p, '-');
3152         if (!hyphen) break;
3153         if (comma && hyphen > comma) break;
3154         len = hyphen + 1 - p;
3155         if (i == 7 && *p == '*' && len == 2) {
3156           p += len;
3157           memcpy(q, strInt, strIntLen);
3158           q += strIntLen;
3159           *q++ = '-';
3160         } else {
3161           memcpy(q, p, len);
3162           p += len;
3163           q += len;
3164         }
3165       }
3166       if (!comma) break;
3167       len = comma + 1 - p;
3168       memcpy(q, p, len);
3169       p += len;
3170       q += len;
3171     }
3172     strcpy(q, p);
3173
3174     return base_fnt_lst;
3175 }
3176
3177 XFontSet
3178 CreateFontSet(base_fnt_lst)
3179      char *base_fnt_lst;
3180 {
3181     XFontSet fntSet;
3182     char **missing_list;
3183     int missing_count;
3184     char *def_string;
3185
3186     fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
3187                             &missing_list, &missing_count, &def_string);
3188     if (appData.debugMode) {
3189       int i, count;
3190       XFontStruct **font_struct_list;
3191       char **font_name_list;
3192       fprintf(debugFP, "Requested font set for list %s\n", base_fnt_lst);
3193       if (fntSet) {
3194         fprintf(debugFP, " got list %s, locale %s\n",
3195                 XBaseFontNameListOfFontSet(fntSet),
3196                 XLocaleOfFontSet(fntSet));
3197         count = XFontsOfFontSet(fntSet, &font_struct_list, &font_name_list);
3198         for (i = 0; i < count; i++) {
3199           fprintf(debugFP, " got charset %s\n", font_name_list[i]);
3200         }
3201       }
3202       for (i = 0; i < missing_count; i++) {
3203         fprintf(debugFP, " missing charset %s\n", missing_list[i]);
3204       }
3205     }
3206     if (fntSet == NULL) {
3207       fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
3208       exit(2);
3209     }
3210     return fntSet;
3211 }
3212 #else // not ENABLE_NLS
3213 /*
3214  * Find a font that matches "pattern" that is as close as
3215  * possible to the targetPxlSize.  Prefer fonts that are k
3216  * pixels smaller to fonts that are k pixels larger.  The
3217  * pattern must be in the X Consortium standard format,
3218  * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3219  * The return value should be freed with XtFree when no
3220  * longer needed.
3221  */
3222 char *
3223 FindFont(pattern, targetPxlSize)
3224      char *pattern;
3225      int targetPxlSize;
3226 {
3227     char **fonts, *p, *best, *scalable, *scalableTail;
3228     int i, j, nfonts, minerr, err, pxlSize;
3229
3230     fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3231     if (nfonts < 1) {
3232         fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3233                 programName, pattern);
3234         exit(2);
3235     }
3236
3237     best = fonts[0];
3238     scalable = NULL;
3239     minerr = 999999;
3240     for (i=0; i<nfonts; i++) {
3241         j = 0;
3242         p = fonts[i];
3243         if (*p != '-') continue;
3244         while (j < 7) {
3245             if (*p == NULLCHAR) break;
3246             if (*p++ == '-') j++;
3247         }
3248         if (j < 7) continue;
3249         pxlSize = atoi(p);
3250         if (pxlSize == 0) {
3251             scalable = fonts[i];
3252             scalableTail = p;
3253         } else {
3254             err = pxlSize - targetPxlSize;
3255             if (Abs(err) < Abs(minerr) ||
3256                 (minerr > 0 && err < 0 && -err == minerr)) {
3257                 best = fonts[i];
3258                 minerr = err;
3259             }
3260         }
3261     }
3262     if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3263         /* If the error is too big and there is a scalable font,
3264            use the scalable font. */
3265         int headlen = scalableTail - scalable;
3266         p = (char *) XtMalloc(strlen(scalable) + 10);
3267         while (isdigit(*scalableTail)) scalableTail++;
3268         sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3269     } else {
3270         p = (char *) XtMalloc(strlen(best) + 2);
3271         safeStrCpy(p, best, strlen(best)+1 );
3272     }
3273     if (appData.debugMode) {
3274         fprintf(debugFP, _("resolved %s at pixel size %d\n  to %s\n"),
3275                 pattern, targetPxlSize, p);
3276     }
3277     XFreeFontNames(fonts);
3278     return p;
3279 }
3280 #endif
3281
3282 void DeleteGCs()
3283 {   // [HGM] deletes GCs that are to be remade, to prevent resource leak;
3284     // must be called before all non-first callse to CreateGCs()
3285     XtReleaseGC(shellWidget, highlineGC);
3286     XtReleaseGC(shellWidget, lightSquareGC);
3287     XtReleaseGC(shellWidget, darkSquareGC);
3288     XtReleaseGC(shellWidget, lineGC);
3289     if (appData.monoMode) {
3290         if (DefaultDepth(xDisplay, xScreen) == 1) {
3291             XtReleaseGC(shellWidget, wbPieceGC);
3292         } else {
3293             XtReleaseGC(shellWidget, bwPieceGC);
3294         }
3295     } else {
3296         XtReleaseGC(shellWidget, prelineGC);
3297         XtReleaseGC(shellWidget, jailSquareGC);
3298         XtReleaseGC(shellWidget, wdPieceGC);
3299         XtReleaseGC(shellWidget, wlPieceGC);
3300         XtReleaseGC(shellWidget, wjPieceGC);
3301         XtReleaseGC(shellWidget, bdPieceGC);
3302         XtReleaseGC(shellWidget, blPieceGC);
3303         XtReleaseGC(shellWidget, bjPieceGC);
3304     }
3305 }
3306
3307 void CreateGCs(int redo)
3308 {
3309     XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3310       | GCBackground | GCFunction | GCPlaneMask;
3311     XGCValues gc_values;
3312     GC copyInvertedGC;
3313
3314     gc_values.plane_mask = AllPlanes;
3315     gc_values.line_width = lineGap;
3316     gc_values.line_style = LineSolid;
3317     gc_values.function = GXcopy;
3318
3319   if(redo) {
3320     DeleteGCs(); // called a second time; clean up old GCs first
3321   } else { // [HGM] grid and font GCs created on first call only
3322     gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3323     gc_values.background = XWhitePixel(xDisplay, xScreen);
3324     coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3325     XSetFont(xDisplay, coordGC, coordFontID);
3326
3327     // [HGM] make font for holdings counts (white on black)
3328     gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3329     gc_values.background = XBlackPixel(xDisplay, xScreen);
3330     countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3331     XSetFont(xDisplay, countGC, countFontID);
3332   }
3333     gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3334     gc_values.background = XBlackPixel(xDisplay, xScreen);
3335     lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3336
3337     if (appData.monoMode) {
3338         gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3339         gc_values.background = XWhitePixel(xDisplay, xScreen);
3340         highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3341
3342         gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3343         gc_values.background = XBlackPixel(xDisplay, xScreen);
3344         lightSquareGC = wbPieceGC
3345           = XtGetGC(shellWidget, value_mask, &gc_values);
3346
3347         gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3348         gc_values.background = XWhitePixel(xDisplay, xScreen);
3349         darkSquareGC = bwPieceGC
3350           = XtGetGC(shellWidget, value_mask, &gc_values);
3351
3352         if (DefaultDepth(xDisplay, xScreen) == 1) {
3353             /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3354             gc_values.function = GXcopyInverted;
3355             copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3356             gc_values.function = GXcopy;
3357             if (XBlackPixel(xDisplay, xScreen) == 1) {
3358                 bwPieceGC = darkSquareGC;
3359                 wbPieceGC = copyInvertedGC;
3360             } else {
3361                 bwPieceGC = copyInvertedGC;
3362                 wbPieceGC = lightSquareGC;
3363             }
3364         }
3365     } else {
3366         gc_values.foreground = highlightSquareColor;
3367         gc_values.background = highlightSquareColor;
3368         highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3369
3370         gc_values.foreground = premoveHighlightColor;
3371         gc_values.background = premoveHighlightColor;
3372         prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3373
3374         gc_values.foreground = lightSquareColor;
3375         gc_values.background = darkSquareColor;
3376         lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3377
3378         gc_values.foreground = darkSquareColor;
3379         gc_values.background = lightSquareColor;
3380         darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3381
3382         gc_values.foreground = jailSquareColor;
3383         gc_values.background = jailSquareColor;
3384         jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3385
3386         gc_values.foreground = whitePieceColor;
3387         gc_values.background = darkSquareColor;
3388         wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3389
3390         gc_values.foreground = whitePieceColor;
3391         gc_values.background = lightSquareColor;
3392         wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3393
3394         gc_values.foreground = whitePieceColor;
3395         gc_values.background = jailSquareColor;
3396         wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3397
3398         gc_values.foreground = blackPieceColor;
3399         gc_values.background = darkSquareColor;
3400         bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3401
3402         gc_values.foreground = blackPieceColor;
3403         gc_values.background = lightSquareColor;
3404         blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3405
3406         gc_values.foreground = blackPieceColor;
3407         gc_values.background = jailSquareColor;
3408         bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3409     }
3410 }
3411
3412 void loadXIM(xim, xmask, filename, dest, mask)
3413      XImage *xim;
3414      XImage *xmask;
3415      char *filename;
3416      Pixmap *dest;
3417      Pixmap *mask;
3418 {
3419     int x, y, w, h, p;
3420     FILE *fp;
3421     Pixmap temp;
3422     XGCValues   values;
3423     GC maskGC;
3424
3425     fp = fopen(filename, "rb");
3426     if (!fp) {
3427         fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3428         exit(1);
3429     }
3430
3431     w = fgetc(fp);
3432     h = fgetc(fp);
3433
3434     for (y=0; y<h; ++y) {
3435         for (x=0; x<h; ++x) {
3436             p = fgetc(fp);
3437
3438             switch (p) {
3439               case 0:
3440                 XPutPixel(xim, x, y, blackPieceColor);
3441                 if (xmask)
3442                   XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3443                 break;
3444               case 1:
3445                 XPutPixel(xim, x, y, darkSquareColor);
3446                 if (xmask)
3447                   XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3448                 break;
3449               case 2:
3450                 XPutPixel(xim, x, y, whitePieceColor);
3451                 if (xmask)
3452                   XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3453                 break;
3454               case 3:
3455                 XPutPixel(xim, x, y, lightSquareColor);
3456                 if (xmask)
3457                   XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3458                 break;
3459             }
3460         }
3461     }
3462
3463     fclose(fp);
3464
3465     /* create Pixmap of piece */
3466     *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3467                           w, h, xim->depth);
3468     XPutImage(xDisplay, *dest, lightSquareGC, xim,
3469               0, 0, 0, 0, w, h);
3470
3471     /* create Pixmap of clipmask
3472        Note: We assume the white/black pieces have the same
3473              outline, so we make only 6 masks. This is okay
3474              since the XPM clipmask routines do the same. */
3475     if (xmask) {
3476       temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3477                             w, h, xim->depth);
3478       XPutImage(xDisplay, temp, lightSquareGC, xmask,
3479               0, 0, 0, 0, w, h);
3480
3481       /* now create the 1-bit version */
3482       *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3483                           w, h, 1);
3484
3485       values.foreground = 1;
3486       values.background = 0;
3487
3488       /* Don't use XtGetGC, not read only */
3489       maskGC = XCreateGC(xDisplay, *mask,
3490                     GCForeground | GCBackground, &values);
3491       XCopyPlane(xDisplay, temp, *mask, maskGC,
3492                   0, 0, squareSize, squareSize, 0, 0, 1);
3493       XFreePixmap(xDisplay, temp);
3494     }
3495 }
3496
3497
3498 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3499
3500 void CreateXIMPieces()
3501 {
3502     int piece, kind;
3503     char buf[MSG_SIZ];
3504     u_int ss;
3505     static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3506     XImage *ximtemp;
3507
3508     ss = squareSize;
3509
3510     /* The XSynchronize calls were copied from CreatePieces.
3511        Not sure if needed, but can't hurt */
3512     XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3513                                      buffering bug */
3514
3515     /* temp needed by loadXIM() */
3516     ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3517                  0, 0, ss, ss, AllPlanes, XYPixmap);
3518
3519     if (strlen(appData.pixmapDirectory) == 0) {
3520       useImages = 0;
3521     } else {
3522         useImages = 1;
3523         if (appData.monoMode) {
3524           DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3525                             0, 2);
3526           ExitEvent(2);
3527         }
3528         fprintf(stderr, _("\nLoading XIMs...\n"));
3529         /* Load pieces */
3530         for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3531             fprintf(stderr, "%d", piece+1);
3532             for (kind=0; kind<4; kind++) {
3533                 fprintf(stderr, ".");
3534                 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3535                         ExpandPathName(appData.pixmapDirectory),
3536                         piece <= (int) WhiteKing ? "" : "w",
3537                         pieceBitmapNames[piece],
3538                         ximkind[kind], ss);
3539                 ximPieceBitmap[kind][piece] =
3540                   XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3541                             0, 0, ss, ss, AllPlanes, XYPixmap);
3542                 if (appData.debugMode)
3543                   fprintf(stderr, _("(File:%s:) "), buf);
3544                 loadXIM(ximPieceBitmap[kind][piece],
3545                         ximtemp, buf,
3546                         &(xpmPieceBitmap2[kind][piece]),
3547                         &(ximMaskPm2[piece]));
3548                 if(piece <= (int)WhiteKing)
3549                     xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3550             }
3551             fprintf(stderr," ");
3552         }
3553         /* Load light and dark squares */
3554         /* If the LSQ and DSQ pieces don't exist, we will
3555            draw them with solid squares. */
3556         snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3557         if (access(buf, 0) != 0) {
3558             useImageSqs = 0;
3559         } else {
3560             useImageSqs = 1;
3561             fprintf(stderr, _("light square "));
3562             ximLightSquare=
3563               XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3564                         0, 0, ss, ss, AllPlanes, XYPixmap);
3565             if (appData.debugMode)
3566               fprintf(stderr, _("(File:%s:) "), buf);
3567
3568             loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3569             fprintf(stderr, _("dark square "));
3570             snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3571                     ExpandPathName(appData.pixmapDirectory), ss);
3572             if (appData.debugMode)
3573               fprintf(stderr, _("(File:%s:) "), buf);
3574             ximDarkSquare=
3575               XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3576                         0, 0, ss, ss, AllPlanes, XYPixmap);
3577             loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3578             xpmJailSquare = xpmLightSquare;
3579         }
3580         fprintf(stderr, _("Done.\n"));
3581     }
3582     XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3583 }
3584
3585 static VariantClass oldVariant = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
3586
3587 #if HAVE_LIBXPM
3588 void CreateXPMBoard(char *s, int kind)
3589 {
3590     XpmAttributes attr;
3591     attr.valuemask = 0;
3592     if(s == NULL || *s == 0 || *s == '*') { useTexture &= ~(kind+1); return; }
3593     if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3594         useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3595     }
3596 }
3597
3598 void FreeXPMPieces()
3599 {   // [HGM] to prevent resoucre leak on calling CreaeXPMPieces() a second time,
3600     // thisroutine has to be called t free the old piece pixmaps
3601     int piece, kind;
3602     for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++)
3603         for (kind=0; kind<4; kind++) XFreePixmap(xDisplay, xpmPieceBitmap2[kind][piece]);
3604     if(useImageSqs) {
3605         XFreePixmap(xDisplay, xpmLightSquare);
3606         XFreePixmap(xDisplay, xpmDarkSquare);
3607     }
3608 }
3609
3610 void CreateXPMPieces()
3611 {
3612     int piece, kind, r;
3613     char buf[MSG_SIZ];
3614     u_int ss = squareSize;
3615     XpmAttributes attr;
3616     static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3617     XpmColorSymbol symbols[4];
3618     static int redo = False;
3619
3620     if(redo) FreeXPMPieces(); else redo = 1;
3621
3622     /* The XSynchronize calls were copied from CreatePieces.
3623        Not sure if needed, but can't hurt */
3624     XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3625
3626     /* Setup translations so piece colors match square colors */
3627     symbols[0].name = "light_piece";
3628     symbols[0].value = appData.whitePieceColor;
3629     symbols[1].name = "dark_piece";
3630     symbols[1].value = appData.blackPieceColor;
3631     symbols[2].name = "light_square";
3632     symbols[2].value = appData.lightSquareColor;
3633     symbols[3].name = "dark_square";
3634     symbols[3].value = appData.darkSquareColor;
3635
3636     attr.valuemask = XpmColorSymbols;
3637     attr.colorsymbols = symbols;
3638     attr.numsymbols = 4;
3639
3640     if (appData.monoMode) {
3641       DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3642                         0, 2);
3643       ExitEvent(2);
3644     }
3645     if (strlen(appData.pixmapDirectory) == 0) {
3646         XpmPieces* pieces = builtInXpms;
3647         useImages = 1;
3648         /* Load pieces */
3649         while (pieces->size != squareSize && pieces->size) pieces++;
3650         if (!pieces->size) {
3651           fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3652           exit(1);
3653         }