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