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