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