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