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