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