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