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