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