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