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