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