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