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