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