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