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