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