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