Add board dialog XBoard
[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 BoardOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
458 void LoadOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
459 void SaveOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
460 void GameListOptionsPopDown P(());
461 void ShufflePopDown P(());
462 void EnginePopDown P(());
463 void UciPopDown P(());
464 void TimeControlPopDown P(());
465 void NewVariantPopDown P(());
466 void SettingsPopDown P(());
467 void update_ics_width P(());
468 int get_term_width P(());
469 int CopyMemoProc P(());
470 void DrawArrowHighlight P((int fromX, int fromY, int toX,int toY));
471 Boolean IsDrawArrowEnabled P(());
472
473 /*
474 * XBoard depends on Xt R4 or higher
475 */
476 int xtVersion = XtSpecificationRelease;
477
478 int xScreen;
479 Display *xDisplay;
480 Window xBoardWindow;
481 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
482   jailSquareColor, highlightSquareColor, premoveHighlightColor;
483 Pixel lowTimeWarningColor;
484 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
485   bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
486   wjPieceGC, bjPieceGC, prelineGC, countGC;
487 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
488 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
489   whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
490   commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
491   menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
492   ICSInputShell, fileNameShell, askQuestionShell;
493 Widget historyShell, evalGraphShell, gameListShell;
494 int hOffset; // [HGM] dual
495 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
496 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
497 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
498 Font clockFontID, coordFontID, countFontID;
499 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
500 XtAppContext appContext;
501 char *layoutName;
502 char *oldICSInteractionTitle;
503
504 FileProc fileProc;
505 char *fileOpenMode;
506 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
507
508 Position commentX = -1, commentY = -1;
509 Dimension commentW, commentH;
510 typedef unsigned int BoardSize;
511 BoardSize boardSize;
512 Boolean chessProgram;
513
514 int  minX, minY; // [HGM] placement: volatile limits on upper-left corner
515 int squareSize, smallLayout = 0, tinyLayout = 0,
516   marginW, marginH, // [HGM] for run-time resizing
517   fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
518   ICSInputBoxUp = False, askQuestionUp = False,
519   filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
520   editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
521 Pixel timerForegroundPixel, timerBackgroundPixel;
522 Pixel buttonForegroundPixel, buttonBackgroundPixel;
523 char *chessDir, *programName, *programVersion,
524   *gameCopyFilename, *gamePasteFilename;
525 Boolean alwaysOnTop = False;
526 Boolean saveSettingsOnExit;
527 char *settingsFileName;
528 char *icsTextMenuString;
529 char *icsNames;
530 char *firstChessProgramNames;
531 char *secondChessProgramNames;
532
533 WindowPlacement wpMain;
534 WindowPlacement wpConsole;
535 WindowPlacement wpComment;
536 WindowPlacement wpMoveHistory;
537 WindowPlacement wpEvalGraph;
538 WindowPlacement wpEngineOutput;
539 WindowPlacement wpGameList;
540 WindowPlacement wpTags;
541
542 #define SOLID 0
543 #define OUTLINE 1
544 Pixmap pieceBitmap[2][(int)BlackPawn];
545 Pixmap pieceBitmap2[2][(int)BlackPawn+4];       /* [HGM] pieces */
546 Pixmap xpmPieceBitmap[4][(int)BlackPawn];       /* LL, LD, DL, DD actually used*/
547 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4];    /* LL, LD, DL, DD set to select from */
548 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
549 Pixmap xpmBoardBitmap[2];
550 int useImages, useImageSqs, useTexture, textureW[2], textureH[2];
551 XImage *ximPieceBitmap[4][(int)BlackPawn+4];    /* LL, LD, DL, DD */
552 Pixmap ximMaskPm[(int)BlackPawn];               /* clipmasks, used for XIM pieces */
553 Pixmap ximMaskPm2[(int)BlackPawn+4];            /* clipmasks, used for XIM pieces */
554 XImage *ximLightSquare, *ximDarkSquare;
555 XImage *xim_Cross;
556
557 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
558 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
559
560 #define White(piece) ((int)(piece) < (int)BlackPawn)
561
562 /* Variables for doing smooth animation. This whole thing
563    would be much easier if the board was double-buffered,
564    but that would require a fairly major rewrite.       */
565
566 typedef struct {
567         Pixmap  saveBuf;
568         Pixmap  newBuf;
569         GC      blitGC, pieceGC, outlineGC;
570         XPoint  startSquare, prevFrame, mouseDelta;
571         int     startColor;
572         int     dragPiece;
573         Boolean dragActive;
574         int     startBoardX, startBoardY;
575     } AnimState;
576
577 /* There can be two pieces being animated at once: a player
578    can begin dragging a piece before the remote opponent has moved. */
579
580 static AnimState game, player;
581
582 /* Bitmaps for use as masks when drawing XPM pieces.
583    Need one for each black and white piece.             */
584 static Pixmap xpmMask[BlackKing + 1];
585
586 /* This magic number is the number of intermediate frames used
587    in each half of the animation. For short moves it's reduced
588    by 1. The total number of frames will be factor * 2 + 1.  */
589 #define kFactor    4
590
591 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
592
593 MenuItem fileMenu[] = {
594     {N_("New Game        Ctrl+N"),        "New Game", ResetProc},
595     {N_("New Shuffle Game ..."),          "New Shuffle Game", ShuffleMenuProc},
596     {N_("New Variant ...   Alt+Shift+V"), "New Variant", NewVariantProc},      // [HGM] variant: not functional yet
597     {"----", NULL, NothingProc},
598     {N_("Load Game       Ctrl+O"),        "Load Game", LoadGameProc},
599     {N_("Load Position    Ctrl+Shift+O"), "Load Position", LoadPositionProc},
600 //    {N_("Load Next Game"), "Load Next Game", LoadNextGameProc},
601 //    {N_("Load Previous Game"), "Load Previous Game", LoadPrevGameProc},
602 //    {N_("Reload Same Game"), "Reload Same Game", ReloadGameProc},
603     {N_("Next Position     Shift+PgDn"), "Load Next Position", LoadNextPositionProc},
604     {N_("Prev Position     Shift+PgUp"), "Load Previous Position", LoadPrevPositionProc},
605     {"----", NULL, NothingProc},
606 //    {N_("Reload Same Position"), "Reload Same Position", ReloadPositionProc},
607     {N_("Save Game       Ctrl+S"),        "Save Game", SaveGameProc},
608     {N_("Save Position    Ctrl+Shift+S"), "Save Position", SavePositionProc},
609     {"----", NULL, NothingProc},
610     {N_("Mail Move"),            "Mail Move", MailMoveProc},
611     {N_("Reload CMail Message"), "Reload CMail Message", ReloadCmailMsgProc},
612     {"----", NULL, NothingProc},
613     {N_("Quit                 Ctr+Q"), "Exit", QuitProc},
614     {NULL, NULL, NULL}
615 };
616
617 MenuItem editMenu[] = {
618     {N_("Copy Game    Ctrl+C"),        "Copy Game", CopyGameProc},
619     {N_("Copy Position Ctrl+Shift+C"), "Copy Position", CopyPositionProc},
620     {"----", NULL, NothingProc},
621     {N_("Paste Game    Ctrl+V"),        "Paste Game", PasteGameProc},
622     {N_("Paste Position Ctrl+Shift+V"), "Paste Position", PastePositionProc},
623     {"----", NULL, NothingProc},
624     {N_("Edit Game      Ctrl+E"),        "Edit Game", EditGameProc},
625     {N_("Edit Position   Ctrl+Shift+E"), "Edit Position", EditPositionProc},
626     {N_("Edit Tags"),                    "Edit Tags", EditTagsProc},
627     {N_("Edit Comment"),                 "Edit Comment", EditCommentProc},
628     {"----", NULL, NothingProc},
629     {N_("Revert              Home"), "Revert", RevertProc},
630     {N_("Annotate"),                 "Annotate", AnnotateProc},
631     {N_("Truncate Game  End"),       "Truncate Game", TruncateGameProc},
632     {"----", NULL, NothingProc},
633     {N_("Backward         Alt+Left"),   "Backward", BackwardProc},
634     {N_("Forward           Alt+Right"), "Forward", ForwardProc},
635     {N_("Back to Start     Alt+Home"),  "Back to Start", ToStartProc},
636     {N_("Forward to End Alt+End"),      "Forward to End", ToEndProc},
637     {NULL, NULL, NULL}
638 };
639
640 MenuItem viewMenu[] = {
641     {N_("Flip View             F2"),         "Flip View", FlipViewProc},
642     {"----", NULL, NothingProc},
643     {N_("Engine Output      Alt+Shift+O"),   "Show Engine Output", EngineOutputProc},
644     {N_("Move History       Alt+Shift+H"),   "Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
645     {N_("Evaluation Graph  Alt+Shift+E"),    "Show Evaluation Graph", EvalGraphProc},
646     {N_("Game List            Alt+Shift+G"), "Show Game List", ShowGameListProc},
647     {"----", NULL, NothingProc},
648     {N_("Tags"),             "Show Tags", EditTagsProc},
649     {N_("Comments"),         "Show Comments", EditCommentProc},
650     {N_("ICS Input Box"),    "ICS Input Box", IcsInputBoxProc},
651     {"----", NULL, NothingProc},
652     {N_("Board..."),          "Board Options", BoardOptionsProc},
653     {N_("Game List Tags..."), "Game List", GameListOptionsPopUp},
654     {NULL, NULL, NULL}
655 };
656
657 MenuItem modeMenu[] = {
658     {N_("Machine White  Ctrl+W"), "Machine White", MachineWhiteProc},
659     {N_("Machine Black  Ctrl+B"), "Machine Black", MachineBlackProc},
660     {N_("Two Machines   Ctrl+T"), "Two Machines", TwoMachinesProc},
661     {N_("Analysis Mode  Ctrl+A"), "Analysis Mode", AnalyzeModeProc},
662     {N_("Analyze File      Ctrl+F"), "Analyze File", AnalyzeFileProc },
663     {N_("Edit Game         Ctrl+E"), "Edit Game", EditGameProc},
664     {N_("Edit Position      Ctrl+Shift+E"), "Edit Position", EditPositionProc},
665     {N_("Training"),      "Training", TrainingProc},
666     {N_("ICS Client"),    "ICS Client", IcsClientProc},
667     {"----", NULL, NothingProc},
668     {N_("Pause               Pause"),         "Pause", PauseProc},
669     {NULL, NULL, NULL}
670 };
671
672 MenuItem actionMenu[] = {
673     {N_("Accept             F3"), "Accept", AcceptProc},
674     {N_("Decline            F4"), "Decline", DeclineProc},
675     {N_("Rematch           F12"), "Rematch", RematchProc},
676     {"----", NULL, NothingProc},
677     {N_("Call Flag          F5"), "Call Flag", CallFlagProc},
678     {N_("Draw                F6"), "Draw", DrawProc},
679     {N_("Adjourn            F7"),  "Adjourn", AdjournProc},
680     {N_("Abort                F8"),"Abort", AbortProc},
681     {N_("Resign              F9"), "Resign", ResignProc},
682     {"----", NULL, NothingProc},
683     {N_("Stop Observing  F10"), "Stop Observing", StopObservingProc},
684     {N_("Stop Examining  F11"), "Stop Examining", StopExaminingProc},
685     {N_("Upload to Examine"),   "Upload to Examine", UploadProc},
686     {"----", NULL, NothingProc},
687     {N_("Adjudicate to White"), "Adjudicate to White", AdjuWhiteProc},
688     {N_("Adjudicate to Black"), "Adjudicate to Black", AdjuBlackProc},
689     {N_("Adjudicate Draw"),     "Adjudicate Draw", AdjuDrawProc},
690     {NULL, NULL, NULL}
691 };
692
693 MenuItem engineMenu[] = {
694     {N_("Engine #1 Settings ..."), "Engine #1 Settings", FirstSettingsProc},
695     {N_("Engine #2 Settings ..."), "Engine #2 Settings", SecondSettingsProc},
696     {"----", NULL, NothingProc},
697     {N_("Hint"), "Hint", HintProc},
698     {N_("Book"), "Book", BookProc},
699     {"----", NULL, NothingProc},
700     {N_("Move Now     Ctrl+M"),     "Move Now", MoveNowProc},
701     {N_("Retract Move  Ctrl+X"), "Retract Move", RetractMoveProc},
702     {NULL, NULL, NULL}
703 };
704
705 MenuItem optionsMenu[] = {
706     {N_("Time Control ...       Alt+Shift+T"), "Time Control", TimeControlProc},
707     {N_("Common Engine ...  Alt+Shift+U"),     "Common Engine", UciMenuProc},
708     {N_("Adjudications ...      Alt+Shift+J"), "Adjudications", EngineMenuProc},
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     {"----", NULL, NothingProc},
714     {N_("Always Queen        Ctrl+Shift+Q"),   "Always Queen", AlwaysQueenProc},
715     {N_("Animate Dragging"), "Animate Dragging", AnimateDraggingProc},
716     {N_("Animate Moving      Ctrl+Shift+A"),   "Animate Moving", AnimateMovingProc},
717     {N_("Auto Flag               Ctrl+Shift+F"), "Auto Flag", AutoflagProc},
718     {N_("Auto Flip View"),   "Auto Flip View", AutoflipProc},
719     {N_("Blindfold"),        "Blindfold", BlindfoldProc},
720     {N_("Flash Moves"),      "Flash Moves", FlashMovesProc},
721 #if HIGHDRAG
722     {N_("Highlight Dragging"),    "Highlight Dragging", HighlightDraggingProc},
723 #endif
724     {N_("Highlight Last Move"),   "Highlight Last Move", HighlightLastMoveProc},
725     {N_("Highlight With Arrow"),  "Arrow", HighlightArrowProc},
726     {N_("Move Sound"),            "Move Sound", MoveSoundProc},
727 //    {N_("ICS Alarm"),             "ICS Alarm", IcsAlarmProc},
728     {N_("One-Click Moving"),      "OneClick", OneClickProc},
729     {N_("Periodic Updates"),      "Periodic Updates", PeriodicUpdatesProc},
730     {N_("Ponder Next Move  Ctrl+Shift+P"), "Ponder Next Move", PonderNextMoveProc},
731     {N_("Popup Exit Message"),    "Popup Exit Message", PopupExitMessageProc},
732     {N_("Popup Move Errors"),     "Popup Move Errors", PopupMoveErrorsProc},
733 //    {N_("Premove"),               "Premove", PremoveProc},
734     {N_("Show Coords"),           "Show Coords", ShowCoordsProc},
735     {N_("Hide Thinking        Ctrl+Shift+H"),   "Hide Thinking", HideThinkingProc},
736     {N_("Test Legality          Ctrl+Shift+L"), "Test Legality", TestLegalityProc},
737     {"----", NULL, NothingProc},
738     {N_("Save Settings Now"),     "Save Settings Now", SaveSettingsProc},
739     {N_("Save Settings on Exit"), "Save Settings on Exit", SaveOnExitProc},
740     {NULL, NULL, NULL}
741 };
742
743 MenuItem helpMenu[] = {
744     {N_("Info XBoard"),     "Info XBoard", InfoProc},
745     {N_("Man XBoard   F1"), "Man XBoard", ManProc},
746     {"----", NULL, NothingProc},
747     {N_("About XBoard"), "About XBoard", AboutProc},
748     {NULL, NULL, NULL}
749 };
750
751 Menu menuBar[] = {
752     {N_("File"),    "File", fileMenu},
753     {N_("Edit"),    "Edit", editMenu},
754     {N_("View"),    "View", viewMenu},
755     {N_("Mode"),    "Mode", modeMenu},
756     {N_("Action"),  "Action", actionMenu},
757     {N_("Engine"),  "Engine", engineMenu},
758     {N_("Options"), "Options", optionsMenu},
759     {N_("Help"),    "Help", helpMenu},
760     {NULL, NULL, NULL}
761 };
762
763 #define PAUSE_BUTTON "P"
764 MenuItem buttonBar[] = {
765     {"<<", "<<", ToStartProc},
766     {"<", "<", BackwardProc},
767     {PAUSE_BUTTON, PAUSE_BUTTON, PauseProc},
768     {">", ">", ForwardProc},
769     {">>", ">>", ToEndProc},
770     {NULL, NULL, NULL}
771 };
772
773 #define PIECE_MENU_SIZE 18
774 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
775     { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
776       N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
777       N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
778       N_("Empty square"), N_("Clear board") },
779     { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
780       N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
781       N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
782       N_("Empty square"), N_("Clear board") }
783 };
784 /* must be in same order as PieceMenuStrings! */
785 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
786     { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
787         WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
788         WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
789         PromotePiece, DemotePiece, EmptySquare, ClearBoard },
790     { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
791         BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
792         BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
793         PromotePiece, DemotePiece, EmptySquare, ClearBoard },
794 };
795
796 #define DROP_MENU_SIZE 6
797 String dropMenuStrings[DROP_MENU_SIZE] = {
798     "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
799   };
800 /* must be in same order as PieceMenuStrings! */
801 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
802     (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
803     WhiteRook, WhiteQueen
804 };
805
806 typedef struct {
807     char piece;
808     char* widget;
809 } DropMenuEnables;
810
811 DropMenuEnables dmEnables[] = {
812     { 'P', "Pawn" },
813     { 'N', "Knight" },
814     { 'B', "Bishop" },
815     { 'R', "Rook" },
816     { 'Q', "Queen" }
817 };
818
819 Arg shellArgs[] = {
820     { XtNwidth, 0 },
821     { XtNheight, 0 },
822     { XtNminWidth, 0 },
823     { XtNminHeight, 0 },
824     { XtNmaxWidth, 0 },
825     { XtNmaxHeight, 0 }
826 };
827
828 Arg layoutArgs[] = {
829     { XtNborderWidth, 0 },
830     { XtNdefaultDistance, 0 },
831 };
832
833 Arg formArgs[] = {
834     { XtNborderWidth, 0 },
835     { XtNresizable, (XtArgVal) True },
836 };
837
838 Arg boardArgs[] = {
839     { XtNborderWidth, 0 },
840     { XtNwidth, 0 },
841     { XtNheight, 0 }
842 };
843
844 Arg titleArgs[] = {
845     { XtNjustify, (XtArgVal) XtJustifyRight },
846     { XtNlabel, (XtArgVal) "..." },
847     { XtNresizable, (XtArgVal) True },
848     { XtNresize, (XtArgVal) False }
849 };
850
851 Arg messageArgs[] = {
852     { XtNjustify, (XtArgVal) XtJustifyLeft },
853     { XtNlabel, (XtArgVal) "..." },
854     { XtNresizable, (XtArgVal) True },
855     { XtNresize, (XtArgVal) False }
856 };
857
858 Arg timerArgs[] = {
859     { XtNborderWidth, 0 },
860     { XtNjustify, (XtArgVal) XtJustifyLeft }
861 };
862
863 XtResource clientResources[] = {
864     { "flashCount", "flashCount", XtRInt, sizeof(int),
865         XtOffset(AppDataPtr, flashCount), XtRImmediate,
866         (XtPointer) FLASH_COUNT  },
867 };
868
869 XrmOptionDescRec shellOptions[] = {
870     { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
871     { "-flash", "flashCount", XrmoptionNoArg, "3" },
872     { "-xflash", "flashCount", XrmoptionNoArg, "0" },
873 };
874
875 XtActionsRec boardActions[] = {
876     { "DrawPosition", DrawPositionProc },
877     { "HandleUserMove", HandleUserMove },
878     { "AnimateUserMove", AnimateUserMove },
879     { "HandlePV", HandlePV },
880     { "SelectPV", SelectPV },
881     { "StopPV", StopPV },
882     { "FileNameAction", FileNameAction },
883     { "AskQuestionProc", AskQuestionProc },
884     { "AskQuestionReplyAction", AskQuestionReplyAction },
885     { "PieceMenuPopup", PieceMenuPopup },
886     { "WhiteClock", WhiteClock },
887     { "BlackClock", BlackClock },
888     { "Iconify", Iconify },
889     { "ResetProc", ResetProc },
890     { "NewVariantProc", NewVariantProc },
891     { "LoadGameProc", LoadGameProc },
892     { "LoadNextGameProc", LoadNextGameProc },
893     { "LoadPrevGameProc", LoadPrevGameProc },
894     { "LoadSelectedProc", LoadSelectedProc },
895     { "SetFilterProc", SetFilterProc },
896     { "ReloadGameProc", ReloadGameProc },
897     { "LoadPositionProc", LoadPositionProc },
898     { "LoadNextPositionProc", LoadNextPositionProc },
899     { "LoadPrevPositionProc", LoadPrevPositionProc },
900     { "ReloadPositionProc", ReloadPositionProc },
901     { "CopyPositionProc", CopyPositionProc },
902     { "PastePositionProc", PastePositionProc },
903     { "CopyGameProc", CopyGameProc },
904     { "PasteGameProc", PasteGameProc },
905     { "SaveGameProc", SaveGameProc },
906     { "SavePositionProc", SavePositionProc },
907     { "MailMoveProc", MailMoveProc },
908     { "ReloadCmailMsgProc", ReloadCmailMsgProc },
909     { "QuitProc", QuitProc },
910     { "MachineWhiteProc", MachineWhiteProc },
911     { "MachineBlackProc", MachineBlackProc },
912     { "AnalysisModeProc", AnalyzeModeProc },
913     { "AnalyzeFileProc", AnalyzeFileProc },
914     { "TwoMachinesProc", TwoMachinesProc },
915     { "IcsClientProc", IcsClientProc },
916     { "EditGameProc", EditGameProc },
917     { "EditPositionProc", EditPositionProc },
918     { "TrainingProc", EditPositionProc },
919     { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
920     { "EvalGraphProc", EvalGraphProc},       // [HGM] Winboard_x avaluation graph window
921     { "ShowGameListProc", ShowGameListProc },
922     { "ShowMoveListProc", HistoryShowProc},
923     { "EditTagsProc", EditCommentProc },
924     { "EditCommentProc", EditCommentProc },
925     { "IcsInputBoxProc", IcsInputBoxProc },
926     { "PauseProc", PauseProc },
927     { "AcceptProc", AcceptProc },
928     { "DeclineProc", DeclineProc },
929     { "RematchProc", RematchProc },
930     { "CallFlagProc", CallFlagProc },
931     { "DrawProc", DrawProc },
932     { "AdjournProc", AdjournProc },
933     { "AbortProc", AbortProc },
934     { "ResignProc", ResignProc },
935     { "AdjuWhiteProc", AdjuWhiteProc },
936     { "AdjuBlackProc", AdjuBlackProc },
937     { "AdjuDrawProc", AdjuDrawProc },
938     { "EnterKeyProc", EnterKeyProc },
939     { "UpKeyProc", UpKeyProc },
940     { "DownKeyProc", DownKeyProc },
941     { "StopObservingProc", StopObservingProc },
942     { "StopExaminingProc", StopExaminingProc },
943     { "UploadProc", UploadProc },
944     { "BackwardProc", BackwardProc },
945     { "ForwardProc", ForwardProc },
946     { "ToStartProc", ToStartProc },
947     { "ToEndProc", ToEndProc },
948     { "RevertProc", RevertProc },
949     { "AnnotateProc", AnnotateProc },
950     { "TruncateGameProc", TruncateGameProc },
951     { "MoveNowProc", MoveNowProc },
952     { "RetractMoveProc", RetractMoveProc },
953     { "EngineMenuProc", (XtActionProc) EngineMenuProc },
954     { "UciMenuProc", (XtActionProc) UciMenuProc },
955     { "TimeControlProc", (XtActionProc) TimeControlProc },
956     { "AlwaysQueenProc", AlwaysQueenProc },
957     { "AnimateDraggingProc", AnimateDraggingProc },
958     { "AnimateMovingProc", AnimateMovingProc },
959     { "AutoflagProc", AutoflagProc },
960     { "AutoflipProc", AutoflipProc },
961     { "BlindfoldProc", BlindfoldProc },
962     { "FlashMovesProc", FlashMovesProc },
963     { "FlipViewProc", FlipViewProc },
964 #if HIGHDRAG
965     { "HighlightDraggingProc", HighlightDraggingProc },
966 #endif
967     { "HighlightLastMoveProc", HighlightLastMoveProc },
968 //    { "IcsAlarmProc", IcsAlarmProc },
969     { "MoveSoundProc", MoveSoundProc },
970     { "PeriodicUpdatesProc", PeriodicUpdatesProc },
971     { "PonderNextMoveProc", PonderNextMoveProc },
972     { "PopupExitMessageProc", PopupExitMessageProc },
973     { "PopupMoveErrorsProc", PopupMoveErrorsProc },
974 //    { "PremoveProc", PremoveProc },
975     { "ShowCoordsProc", ShowCoordsProc },
976     { "ShowThinkingProc", ShowThinkingProc },
977     { "HideThinkingProc", HideThinkingProc },
978     { "TestLegalityProc", TestLegalityProc },
979     { "SaveSettingsProc", SaveSettingsProc },
980     { "SaveOnExitProc", SaveOnExitProc },
981     { "InfoProc", InfoProc },
982     { "ManProc", ManProc },
983     { "HintProc", HintProc },
984     { "BookProc", BookProc },
985     { "AboutGameProc", AboutGameProc },
986     { "AboutProc", AboutProc },
987     { "DebugProc", DebugProc },
988     { "NothingProc", NothingProc },
989     { "CommentClick", (XtActionProc) CommentClick },
990     { "CommentPopDown", (XtActionProc) CommentPopDown },
991     { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
992     { "TagsPopDown", (XtActionProc) TagsPopDown },
993     { "ErrorPopDown", (XtActionProc) ErrorPopDown },
994     { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
995     { "FileNamePopDown", (XtActionProc) FileNamePopDown },
996     { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
997     { "GameListPopDown", (XtActionProc) GameListPopDown },
998     { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
999     { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1000     { "HistoryPopDown", (XtActionProc) HistoryPopDown },
1001     { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1002     { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1003     { "ShufflePopDown", (XtActionProc) ShufflePopDown },
1004     { "EnginePopDown", (XtActionProc) EnginePopDown },
1005     { "UciPopDown", (XtActionProc) UciPopDown },
1006     { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
1007     { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
1008     { "SettingsPopDown", (XtActionProc) SettingsPopDown },
1009     { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1010 };
1011
1012 char globalTranslations[] =
1013   ":<Key>F9: ResignProc() \n \
1014    :Ctrl<Key>n: ResetProc() \n \
1015    :Meta<Key>V: NewVariantProc() \n \
1016    :Ctrl<Key>o: LoadGameProc() \n \
1017    :Meta<Key>Next: LoadNextGameProc() \n \
1018    :Meta<Key>Prior: LoadPrevGameProc() \n \
1019    :Ctrl<Key>s: SaveGameProc() \n \
1020    :Ctrl<Key>c: CopyGameProc() \n \
1021    :Ctrl<Key>v: PasteGameProc() \n \
1022    :Ctrl<Key>O: LoadPositionProc() \n \
1023    :Shift<Key>Next: LoadNextPositionProc() \n \
1024    :Shift<Key>Prior: LoadPrevPositionProc() \n \
1025    :Ctrl<Key>S: SavePositionProc() \n \
1026    :Ctrl<Key>C: CopyPositionProc() \n \
1027    :Ctrl<Key>V: PastePositionProc() \n \
1028    :Ctrl<Key>q: QuitProc() \n \
1029    :Ctrl<Key>w: MachineWhiteProc() \n \
1030    :Ctrl<Key>b: MachineBlackProc() \n \
1031    :Ctrl<Key>t: TwoMachinesProc() \n \
1032    :Ctrl<Key>a: AnalysisModeProc() \n \
1033    :Ctrl<Key>f: AnalyzeFileProc() \n \
1034    :Ctrl<Key>e: EditGameProc() \n \
1035    :Ctrl<Key>E: EditPositionProc() \n \
1036    :Meta<Key>O: EngineOutputProc() \n \
1037    :Meta<Key>E: EvalGraphProc() \n \
1038    :Meta<Key>G: ShowGameListProc() \n \
1039    :Meta<Key>H: ShowMoveListProc() \n \
1040    :<Key>Pause: PauseProc() \n \
1041    :<Key>F3: AcceptProc() \n \
1042    :<Key>F4: DeclineProc() \n \
1043    :<Key>F12: RematchProc() \n \
1044    :<Key>F5: CallFlagProc() \n \
1045    :<Key>F6: DrawProc() \n \
1046    :<Key>F7: AdjournProc() \n \
1047    :<Key>F8: AbortProc() \n \
1048    :<Key>F10: StopObservingProc() \n \
1049    :<Key>F11: StopExaminingProc() \n \
1050    :Meta Ctrl<Key>F12: DebugProc() \n \
1051    :Meta<Key>End: ToEndProc() \n \
1052    :Meta<Key>Right: ForwardProc() \n \
1053    :Meta<Key>Home: ToStartProc() \n \
1054    :Meta<Key>Left: BackwardProc() \n \
1055    :<Key>Home: RevertProc() \n \
1056    :<Key>End: TruncateGameProc() \n \
1057    :Ctrl<Key>m: MoveNowProc() \n \
1058    :Ctrl<Key>x: RetractMoveProc() \n \
1059    :Meta<Key>J: EngineMenuProc() \n \
1060    :Meta<Key>U: UciMenuProc() \n \
1061    :Meta<Key>T: TimeControlProc() \n \
1062    :Ctrl<Key>Q: AlwaysQueenProc() \n \
1063    :Ctrl<Key>F: AutoflagProc() \n \
1064    :Ctrl<Key>A: AnimateMovingProc() \n \
1065    :Ctrl<Key>P: PonderNextMoveProc() \n \
1066    :Ctrl<Key>L: TestLegalityProc() \n \
1067    :Ctrl<Key>H: HideThinkingProc() \n \
1068    :<Key>-: Iconify() \n \
1069    :<Key>F1: ManProc() \n \
1070    :<Key>F2: FlipViewProc() \n \
1071    <KeyDown>.: BackwardProc() \n \
1072    <KeyUp>.: ForwardProc() \n \
1073    Shift<Key>1: AskQuestionProc(\"Direct command\",\
1074                                 \"Send to chess program:\",,1) \n \
1075    Shift<Key>2: AskQuestionProc(\"Direct command\",\
1076                                 \"Send to second chess program:\",,2) \n";
1077
1078 char boardTranslations[] =
1079    "<Btn1Down>: HandleUserMove(0) \n \
1080    Shift<Btn1Up>: HandleUserMove(1) \n \
1081    <Btn1Up>: HandleUserMove(0) \n \
1082    <Btn1Motion>: AnimateUserMove() \n \
1083    <Btn3Motion>: HandlePV() \n \
1084    <Btn3Up>: PieceMenuPopup(menuB) \n \
1085    Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1086                  PieceMenuPopup(menuB) \n \
1087    Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1088                  PieceMenuPopup(menuW) \n \
1089    Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1090                  PieceMenuPopup(menuW) \n \
1091    Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1092                  PieceMenuPopup(menuB) \n";
1093
1094 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1095 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1096
1097 char ICSInputTranslations[] =
1098     "<Key>Up: UpKeyProc() \n "
1099     "<Key>Down: DownKeyProc() \n "
1100     "<Key>Return: EnterKeyProc() \n";
1101
1102 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1103 //             as the widget is destroyed before the up-click can call extend-end
1104 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1105
1106 String xboardResources[] = {
1107     "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1108     "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1109     "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1110     NULL
1111   };
1112
1113
1114 /* Max possible square size */
1115 #define MAXSQSIZE 256
1116
1117 static int xpm_avail[MAXSQSIZE];
1118
1119 #ifdef HAVE_DIR_STRUCT
1120
1121 /* Extract piece size from filename */
1122 static int
1123 xpm_getsize(name, len, ext)
1124      char *name;
1125      int len;
1126      char *ext;
1127 {
1128     char *p, *d;
1129     char buf[10];
1130
1131     if (len < 4)
1132       return 0;
1133
1134     if ((p=strchr(name, '.')) == NULL ||
1135         StrCaseCmp(p+1, ext) != 0)
1136       return 0;
1137
1138     p = name + 3;
1139     d = buf;
1140
1141     while (*p && isdigit(*p))
1142       *(d++) = *(p++);
1143
1144     *d = 0;
1145     return atoi(buf);
1146 }
1147
1148 /* Setup xpm_avail */
1149 static int
1150 xpm_getavail(dirname, ext)
1151      char *dirname;
1152      char *ext;
1153 {
1154     DIR *dir;
1155     struct dirent *ent;
1156     int  i;
1157
1158     for (i=0; i<MAXSQSIZE; ++i)
1159       xpm_avail[i] = 0;
1160
1161     if (appData.debugMode)
1162       fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1163
1164     dir = opendir(dirname);
1165     if (!dir)
1166       {
1167           fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1168                   programName, dirname);
1169           exit(1);
1170       }
1171
1172     while ((ent=readdir(dir)) != NULL) {
1173         i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1174         if (i > 0 && i < MAXSQSIZE)
1175           xpm_avail[i] = 1;
1176     }
1177
1178     closedir(dir);
1179
1180     return 0;
1181 }
1182
1183 void
1184 xpm_print_avail(fp, ext)
1185      FILE *fp;
1186      char *ext;
1187 {
1188     int i;
1189
1190     fprintf(fp, _("Available `%s' sizes:\n"), ext);
1191     for (i=1; i<MAXSQSIZE; ++i) {
1192         if (xpm_avail[i])
1193           printf("%d\n", i);
1194     }
1195 }
1196
1197 /* Return XPM piecesize closest to size */
1198 int
1199 xpm_closest_to(dirname, size, ext)
1200      char *dirname;
1201      int size;
1202      char *ext;
1203 {
1204     int i;
1205     int sm_diff = MAXSQSIZE;
1206     int sm_index = 0;
1207     int diff;
1208
1209     xpm_getavail(dirname, ext);
1210
1211     if (appData.debugMode)
1212       xpm_print_avail(stderr, ext);
1213
1214     for (i=1; i<MAXSQSIZE; ++i) {
1215         if (xpm_avail[i]) {
1216             diff = size - i;
1217             diff = (diff<0) ? -diff : diff;
1218             if (diff < sm_diff) {
1219                 sm_diff = diff;
1220                 sm_index = i;
1221             }
1222         }
1223     }
1224
1225     if (!sm_index) {
1226         fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1227         exit(1);
1228     }
1229
1230     return sm_index;
1231 }
1232 #else   /* !HAVE_DIR_STRUCT */
1233 /* If we are on a system without a DIR struct, we can't
1234    read the directory, so we can't collect a list of
1235    filenames, etc., so we can't do any size-fitting. */
1236 int
1237 xpm_closest_to(dirname, size, ext)
1238      char *dirname;
1239      int size;
1240      char *ext;
1241 {
1242     fprintf(stderr, _("\
1243 Warning: No DIR structure found on this system --\n\
1244          Unable to autosize for XPM/XIM pieces.\n\
1245    Please report this error to frankm@hiwaay.net.\n\
1246    Include system type & operating system in message.\n"));
1247     return size;
1248 }
1249 #endif /* HAVE_DIR_STRUCT */
1250
1251 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1252                              "magenta", "cyan", "white" };
1253 typedef struct {
1254     int attr, bg, fg;
1255 } TextColors;
1256 TextColors textColors[(int)NColorClasses];
1257
1258 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1259 static int
1260 parse_color(str, which)
1261      char *str;
1262      int which;
1263 {
1264     char *p, buf[100], *d;
1265     int i;
1266
1267     if (strlen(str) > 99)       /* watch bounds on buf */
1268       return -1;
1269
1270     p = str;
1271     d = buf;
1272     for (i=0; i<which; ++i) {
1273         p = strchr(p, ',');
1274         if (!p)
1275           return -1;
1276         ++p;
1277     }
1278
1279     /* Could be looking at something like:
1280        black, , 1
1281        .. in which case we want to stop on a comma also */
1282     while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1283       ++p;
1284
1285     if (*p == ',') {
1286         return -1;              /* Use default for empty field */
1287     }
1288
1289     if (which == 2 || isdigit(*p))
1290       return atoi(p);
1291
1292     while (*p && isalpha(*p))
1293       *(d++) = *(p++);
1294
1295     *d = 0;
1296
1297     for (i=0; i<8; ++i) {
1298         if (!StrCaseCmp(buf, cnames[i]))
1299           return which? (i+40) : (i+30);
1300     }
1301     if (!StrCaseCmp(buf, "default")) return -1;
1302
1303     fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1304     return -2;
1305 }
1306
1307 static int
1308 parse_cpair(cc, str)
1309      ColorClass cc;
1310      char *str;
1311 {
1312     if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1313         fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1314                 programName, str);
1315         return -1;
1316     }
1317
1318     /* bg and attr are optional */
1319     textColors[(int)cc].bg = parse_color(str, 1);
1320     if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1321         textColors[(int)cc].attr = 0;
1322     }
1323     return 0;
1324 }
1325
1326
1327 /* Arrange to catch delete-window events */
1328 Atom wm_delete_window;
1329 void
1330 CatchDeleteWindow(Widget w, String procname)
1331 {
1332   char buf[MSG_SIZ];
1333   XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1334   snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1335   XtAugmentTranslations(w, XtParseTranslationTable(buf));
1336 }
1337
1338 void
1339 BoardToTop()
1340 {
1341   Arg args[16];
1342   XtSetArg(args[0], XtNiconic, False);
1343   XtSetValues(shellWidget, args, 1);
1344
1345   XtPopup(shellWidget, XtGrabNone); /* Raise if lowered  */
1346 }
1347
1348 //---------------------------------------------------------------------------------------------------------
1349 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1350 #define XBOARD True
1351 #define JAWS_ARGS
1352 #define CW_USEDEFAULT (1<<31)
1353 #define ICS_TEXT_MENU_SIZE 90
1354 #define DEBUG_FILE "xboard.debug"
1355 #define SetCurrentDirectory chdir
1356 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1357 #define OPTCHAR "-"
1358 #define SEPCHAR " "
1359
1360 // these two must some day move to frontend.h, when they are implemented
1361 Boolean GameListIsUp();
1362
1363 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1364 #include "args.h"
1365
1366 // front-end part of option handling
1367
1368 // [HGM] This platform-dependent table provides the location for storing the color info
1369 extern char *crWhite, * crBlack;
1370
1371 void *
1372 colorVariable[] = {
1373   &appData.whitePieceColor,
1374   &appData.blackPieceColor,
1375   &appData.lightSquareColor,
1376   &appData.darkSquareColor,
1377   &appData.highlightSquareColor,
1378   &appData.premoveHighlightColor,
1379   &appData.lowTimeWarningColor,
1380   NULL,
1381   NULL,
1382   NULL,
1383   NULL,
1384   NULL,
1385   &crWhite,
1386   &crBlack,
1387   NULL
1388 };
1389
1390 // [HGM] font: keep a font for each square size, even non-stndard ones
1391 #define NUM_SIZES 18
1392 #define MAX_SIZE 130
1393 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1394 char *fontTable[NUM_FONTS][MAX_SIZE];
1395
1396 void
1397 ParseFont(char *name, int number)
1398 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1399   int size;
1400   if(sscanf(name, "size%d:", &size)) {
1401     // [HGM] font: font is meant for specific boardSize (likely from settings file);
1402     //       defer processing it until we know if it matches our board size
1403     if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1404         fontTable[number][size] = strdup(strchr(name, ':')+1);
1405         fontValid[number][size] = True;
1406     }
1407     return;
1408   }
1409   switch(number) {
1410     case 0: // CLOCK_FONT
1411         appData.clockFont = strdup(name);
1412       break;
1413     case 1: // MESSAGE_FONT
1414         appData.font = strdup(name);
1415       break;
1416     case 2: // COORD_FONT
1417         appData.coordFont = strdup(name);
1418       break;
1419     default:
1420       return;
1421   }
1422   fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1423 }
1424
1425 void
1426 SetFontDefaults()
1427 { // only 2 fonts currently
1428   appData.clockFont = CLOCK_FONT_NAME;
1429   appData.coordFont = COORD_FONT_NAME;
1430   appData.font  =   DEFAULT_FONT_NAME;
1431 }
1432
1433 void
1434 CreateFonts()
1435 { // no-op, until we identify the code for this already in XBoard and move it here
1436 }
1437
1438 void
1439 ParseColor(int n, char *name)
1440 { // in XBoard, just copy the color-name string
1441   if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1442 }
1443
1444 void
1445 ParseTextAttribs(ColorClass cc, char *s)
1446 {
1447     (&appData.colorShout)[cc] = strdup(s);
1448 }
1449
1450 void
1451 ParseBoardSize(void *addr, char *name)
1452 {
1453     appData.boardSize = strdup(name);
1454 }
1455
1456 void
1457 LoadAllSounds()
1458 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1459 }
1460
1461 void
1462 SetCommPortDefaults()
1463 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1464 }
1465
1466 // [HGM] args: these three cases taken out to stay in front-end
1467 void
1468 SaveFontArg(FILE *f, ArgDescriptor *ad)
1469 {
1470   char *name;
1471   int i, n = (int)(intptr_t)ad->argLoc;
1472   switch(n) {
1473     case 0: // CLOCK_FONT
1474         name = appData.clockFont;
1475       break;
1476     case 1: // MESSAGE_FONT
1477         name = appData.font;
1478       break;
1479     case 2: // COORD_FONT
1480         name = appData.coordFont;
1481       break;
1482     default:
1483       return;
1484   }
1485   for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1486     if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1487         fontTable[n][squareSize] = strdup(name);
1488         fontValid[n][squareSize] = True;
1489         break;
1490   }
1491   for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1492     fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1493 }
1494
1495 void
1496 ExportSounds()
1497 { // nothing to do, as the sounds are at all times represented by their text-string names already
1498 }
1499
1500 void
1501 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1502 {       // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1503         fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
1504 }
1505
1506 void
1507 SaveColor(FILE *f, ArgDescriptor *ad)
1508 {       // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1509         if(colorVariable[(int)(intptr_t)ad->argLoc])
1510         fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
1511 }
1512
1513 void
1514 SaveBoardSize(FILE *f, char *name, void *addr)
1515 { // wrapper to shield back-end from BoardSize & sizeInfo
1516   fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1517 }
1518
1519 void
1520 ParseCommPortSettings(char *s)
1521 { // no such option in XBoard (yet)
1522 }
1523
1524 extern Widget engineOutputShell;
1525 extern Widget tagsShell, editTagsShell;
1526 void
1527 GetActualPlacement(Widget wg, WindowPlacement *wp)
1528 {
1529   Arg args[16];
1530   Dimension w, h;
1531   Position x, y;
1532   int i;
1533
1534   if(!wg) return;
1535
1536     i = 0;
1537     XtSetArg(args[i], XtNx, &x); i++;
1538     XtSetArg(args[i], XtNy, &y); i++;
1539     XtSetArg(args[i], XtNwidth, &w); i++;
1540     XtSetArg(args[i], XtNheight, &h); i++;
1541     XtGetValues(wg, args, i);
1542     wp->x = x - 4;
1543     wp->y = y - 23;
1544     wp->height = h;
1545     wp->width = w;
1546 }
1547
1548 void
1549 GetWindowCoords()
1550 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1551   // In XBoard this will have to wait until awareness of window parameters is implemented
1552   GetActualPlacement(shellWidget, &wpMain);
1553   if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1554   if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1555   if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1556   if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1557   if(commentShell) GetActualPlacement(commentShell, &wpComment);
1558   else             GetActualPlacement(editShell,    &wpComment);
1559   if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1560   else      GetActualPlacement(editTagsShell, &wpTags);
1561 }
1562
1563 void
1564 PrintCommPortSettings(FILE *f, char *name)
1565 { // This option does not exist in XBoard
1566 }
1567
1568 int
1569 MySearchPath(char *installDir, char *name, char *fullname)
1570 { // just append installDir and name. Perhaps ExpandPath should be used here?
1571   name = ExpandPathName(name);
1572   if(name && name[0] == '/')
1573     safeStrCpy(fullname, name, MSG_SIZ );
1574   else {
1575     sprintf(fullname, "%s%c%s", installDir, '/', name);
1576   }
1577   return 1;
1578 }
1579
1580 int
1581 MyGetFullPathName(char *name, char *fullname)
1582 { // should use ExpandPath?
1583   name = ExpandPathName(name);
1584   safeStrCpy(fullname, name, MSG_SIZ );
1585   return 1;
1586 }
1587
1588 void
1589 EnsureOnScreen(int *x, int *y, int minX, int minY)
1590 {
1591   return;
1592 }
1593
1594 int
1595 MainWindowUp()
1596 { // [HGM] args: allows testing if main window is realized from back-end
1597   return xBoardWindow != 0;
1598 }
1599
1600 void
1601 PopUpStartupDialog()
1602 {  // start menu not implemented in XBoard
1603 }
1604
1605 char *
1606 ConvertToLine(int argc, char **argv)
1607 {
1608   static char line[128*1024], buf[1024];
1609   int i;
1610
1611   line[0] = NULLCHAR;
1612   for(i=1; i<argc; i++)
1613     {
1614       if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1615           && argv[i][0] != '{' )
1616         snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1617       else
1618         snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1619       strncat(line, buf, 128*1024 - strlen(line) - 1 );
1620     }
1621
1622   line[strlen(line)-1] = NULLCHAR;
1623   return line;
1624 }
1625
1626 //--------------------------------------------------------------------------------------------
1627
1628 extern Boolean twoBoards, partnerUp;
1629
1630 #ifdef IDSIZES
1631   // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1632 #else
1633 #define BoardSize int
1634 void InitDrawingSizes(BoardSize boardSize, int flags)
1635 {   // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1636     Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1637     Arg args[16];
1638     XtGeometryResult gres;
1639     int i;
1640
1641     if(!formWidget) return;
1642
1643     /*
1644      * Enable shell resizing.
1645      */
1646     shellArgs[0].value = (XtArgVal) &w;
1647     shellArgs[1].value = (XtArgVal) &h;
1648     XtGetValues(shellWidget, shellArgs, 2);
1649
1650     shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1651     shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1652     XtSetValues(shellWidget, &shellArgs[2], 4);
1653
1654     XtSetArg(args[0], XtNdefaultDistance, &sep);
1655     XtGetValues(formWidget, args, 1);
1656
1657     if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1658     boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1659     boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1660     CreateGrid();
1661     hOffset = boardWidth + 10;
1662     for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1663         secondSegments[i] = gridSegments[i];
1664         secondSegments[i].x1 += hOffset;
1665         secondSegments[i].x2 += hOffset;
1666     }
1667
1668     XtSetArg(args[0], XtNwidth, boardWidth);
1669     XtSetArg(args[1], XtNheight, boardHeight);
1670     XtSetValues(boardWidget, args, 2);
1671
1672     timerWidth = (boardWidth - sep) / 2;
1673     XtSetArg(args[0], XtNwidth, timerWidth);
1674     XtSetValues(whiteTimerWidget, args, 1);
1675     XtSetValues(blackTimerWidget, args, 1);
1676
1677     XawFormDoLayout(formWidget, False);
1678
1679     if (appData.titleInWindow) {
1680         i = 0;
1681         XtSetArg(args[i], XtNborderWidth, &bor); i++;
1682         XtSetArg(args[i], XtNheight, &h);  i++;
1683         XtGetValues(titleWidget, args, i);
1684         if (smallLayout) {
1685             w = boardWidth - 2*bor;
1686         } else {
1687             XtSetArg(args[0], XtNwidth, &w);
1688             XtGetValues(menuBarWidget, args, 1);
1689             w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1690         }
1691
1692         gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1693         if (gres != XtGeometryYes && appData.debugMode) {
1694             fprintf(stderr,
1695                     _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1696                     programName, gres, w, h, wr, hr);
1697         }
1698     }
1699
1700     XawFormDoLayout(formWidget, True);
1701
1702     /*
1703      * Inhibit shell resizing.
1704      */
1705     shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1706     shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1707     shellArgs[4].value = shellArgs[2].value = w;
1708     shellArgs[5].value = shellArgs[3].value = h;
1709     XtSetValues(shellWidget, &shellArgs[0], 6);
1710
1711     // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1712     // (only for xpm)
1713     if(useImages) {
1714       for(i=0; i<4; i++) {
1715         int p;
1716         for(p=0; p<=(int)WhiteKing; p++)
1717            xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1718         if(gameInfo.variant == VariantShogi) {
1719            xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1720            xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1721            xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1722            xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1723            xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1724         }
1725 #ifdef GOTHIC
1726         if(gameInfo.variant == VariantGothic) {
1727            xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1728         }
1729 #endif
1730         if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1731            xpmPieceBitmap[i][(int)WhiteAngel]    = xpmPieceBitmap2[i][(int)WhiteFalcon];
1732            xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1733         }
1734 #if !HAVE_LIBXPM
1735         // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1736         for(p=0; p<=(int)WhiteKing; p++)
1737            ximMaskPm[p] = ximMaskPm2[p]; // defaults
1738         if(gameInfo.variant == VariantShogi) {
1739            ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1740            ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1741            ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1742            ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1743            ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1744         }
1745 #ifdef GOTHIC
1746         if(gameInfo.variant == VariantGothic) {
1747            ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1748         }
1749 #endif
1750         if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1751            ximMaskPm[(int)WhiteAngel]    = ximMaskPm2[(int)WhiteFalcon];
1752            ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1753         }
1754 #endif
1755       }
1756     } else {
1757       for(i=0; i<2; i++) {
1758         int p;
1759         for(p=0; p<=(int)WhiteKing; p++)
1760            pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1761         if(gameInfo.variant == VariantShogi) {
1762            pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1763            pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1764            pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1765            pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1766            pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1767         }
1768 #ifdef GOTHIC
1769         if(gameInfo.variant == VariantGothic) {
1770            pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1771         }
1772 #endif
1773         if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1774            pieceBitmap[i][(int)WhiteAngel]    = pieceBitmap2[i][(int)WhiteFalcon];
1775            pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1776         }
1777       }
1778     }
1779 #if HAVE_LIBXPM
1780     CreateAnimVars();
1781 #endif
1782 }
1783 #endif
1784
1785 void ParseIcsTextColors()
1786 {   // [HGM] tken out of main(), so it can be called from ICS-Options dialog
1787     if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1788         parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1789         parse_cpair(ColorChannel1, appData.colorChannel1) < 0  ||
1790         parse_cpair(ColorChannel, appData.colorChannel) < 0  ||
1791         parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1792         parse_cpair(ColorTell, appData.colorTell) < 0 ||
1793         parse_cpair(ColorChallenge, appData.colorChallenge) < 0  ||
1794         parse_cpair(ColorRequest, appData.colorRequest) < 0  ||
1795         parse_cpair(ColorSeek, appData.colorSeek) < 0  ||
1796         parse_cpair(ColorNormal, appData.colorNormal) < 0)
1797       {
1798           if (appData.colorize) {
1799               fprintf(stderr,
1800                       _("%s: can't parse color names; disabling colorization\n"),
1801                       programName);
1802           }
1803           appData.colorize = FALSE;
1804       }
1805 }
1806
1807 int MakeColors()
1808 {   // [HGM] taken out of main(), so it can be called from BoardOptions dialog
1809     XrmValue vFrom, vTo;
1810     int forceMono = False;
1811
1812     if (!appData.monoMode) {
1813         vFrom.addr = (caddr_t) appData.lightSquareColor;
1814         vFrom.size = strlen(appData.lightSquareColor);
1815         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1816         if (vTo.addr == NULL) {
1817           appData.monoMode = True;
1818           forceMono = True;
1819         } else {
1820           lightSquareColor = *(Pixel *) vTo.addr;
1821         }
1822     }
1823     if (!appData.monoMode) {
1824         vFrom.addr = (caddr_t) appData.darkSquareColor;
1825         vFrom.size = strlen(appData.darkSquareColor);
1826         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1827         if (vTo.addr == NULL) {
1828           appData.monoMode = True;
1829           forceMono = True;
1830         } else {
1831           darkSquareColor = *(Pixel *) vTo.addr;
1832         }
1833     }
1834     if (!appData.monoMode) {
1835         vFrom.addr = (caddr_t) appData.whitePieceColor;
1836         vFrom.size = strlen(appData.whitePieceColor);
1837         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1838         if (vTo.addr == NULL) {
1839           appData.monoMode = True;
1840           forceMono = True;
1841         } else {
1842           whitePieceColor = *(Pixel *) vTo.addr;
1843         }
1844     }
1845     if (!appData.monoMode) {
1846         vFrom.addr = (caddr_t) appData.blackPieceColor;
1847         vFrom.size = strlen(appData.blackPieceColor);
1848         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1849         if (vTo.addr == NULL) {
1850           appData.monoMode = True;
1851           forceMono = True;
1852         } else {
1853           blackPieceColor = *(Pixel *) vTo.addr;
1854         }
1855     }
1856
1857     if (!appData.monoMode) {
1858         vFrom.addr = (caddr_t) appData.highlightSquareColor;
1859         vFrom.size = strlen(appData.highlightSquareColor);
1860         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1861         if (vTo.addr == NULL) {
1862           appData.monoMode = True;
1863           forceMono = True;
1864         } else {
1865           highlightSquareColor = *(Pixel *) vTo.addr;
1866         }
1867     }
1868
1869     if (!appData.monoMode) {
1870         vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1871         vFrom.size = strlen(appData.premoveHighlightColor);
1872         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1873         if (vTo.addr == NULL) {
1874           appData.monoMode = True;
1875           forceMono = True;
1876         } else {
1877           premoveHighlightColor = *(Pixel *) vTo.addr;
1878         }
1879     }
1880     return forceMono;
1881 }
1882
1883 int
1884 main(argc, argv)
1885      int argc;
1886      char **argv;
1887 {
1888     int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1889     XSetWindowAttributes window_attributes;
1890     Arg args[16];
1891     Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1892     XrmValue vFrom, vTo;
1893     XtGeometryResult gres;
1894     char *p;
1895     XrmDatabase xdb;
1896     int forceMono = False;
1897
1898     srandom(time(0)); // [HGM] book: make random truly random
1899
1900     setbuf(stdout, NULL);
1901     setbuf(stderr, NULL);
1902     debugFP = stderr;
1903
1904     if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1905         printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1906         exit(0);
1907     }
1908
1909     programName = strrchr(argv[0], '/');
1910     if (programName == NULL)
1911       programName = argv[0];
1912     else
1913       programName++;
1914
1915 #ifdef ENABLE_NLS
1916     XtSetLanguageProc(NULL, NULL, NULL);
1917     bindtextdomain(PACKAGE, LOCALEDIR);
1918     textdomain(PACKAGE);
1919 #endif
1920
1921     shellWidget =
1922       XtAppInitialize(&appContext, "XBoard", shellOptions,
1923                       XtNumber(shellOptions),
1924                       &argc, argv, xboardResources, NULL, 0);
1925     appData.boardSize = "";
1926     InitAppData(ConvertToLine(argc, argv));
1927     p = getenv("HOME");
1928     if (p == NULL) p = "/tmp";
1929     i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1930     gameCopyFilename = (char*) malloc(i);
1931     gamePasteFilename = (char*) malloc(i);
1932     snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1933     snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1934
1935     XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1936                               clientResources, XtNumber(clientResources),
1937                               NULL, 0);
1938
1939     { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1940         static char buf[MSG_SIZ];
1941         EscapeExpand(buf, appData.initString);
1942         appData.initString = strdup(buf);
1943         EscapeExpand(buf, appData.secondInitString);
1944         appData.secondInitString = strdup(buf);
1945         EscapeExpand(buf, appData.firstComputerString);
1946         appData.firstComputerString = strdup(buf);
1947         EscapeExpand(buf, appData.secondComputerString);
1948         appData.secondComputerString = strdup(buf);
1949     }
1950
1951     if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1952         chessDir = ".";
1953     } else {
1954         if (chdir(chessDir) != 0) {
1955             fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1956             perror(chessDir);
1957             exit(1);
1958         }
1959     }
1960
1961     if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1962         /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1963         if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL)  {
1964            printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1965            exit(errno);
1966         }
1967         setbuf(debugFP, NULL);
1968     }
1969
1970     /* [HGM,HR] make sure board size is acceptable */
1971     if(appData.NrFiles > BOARD_FILES ||
1972        appData.NrRanks > BOARD_RANKS   )
1973          DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1974
1975 #if !HIGHDRAG
1976     /* This feature does not work; animation needs a rewrite */
1977     appData.highlightDragging = FALSE;
1978 #endif
1979     InitBackEnd1();
1980
1981     xDisplay = XtDisplay(shellWidget);
1982     xScreen = DefaultScreen(xDisplay);
1983     wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1984
1985         gameInfo.variant = StringToVariant(appData.variant);
1986         InitPosition(FALSE);
1987
1988 #ifdef IDSIZE
1989     InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1990 #else
1991     if (isdigit(appData.boardSize[0])) {
1992         i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1993                    &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1994                    &fontPxlSize, &smallLayout, &tinyLayout);
1995         if (i == 0) {
1996             fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1997                     programName, appData.boardSize);
1998             exit(2);
1999         }
2000         if (i < 7) {
2001             /* Find some defaults; use the nearest known size */
2002             SizeDefaults *szd, *nearest;
2003             int distance = 99999;
2004             nearest = szd = sizeDefaults;
2005             while (szd->name != NULL) {
2006                 if (abs(szd->squareSize - squareSize) < distance) {
2007                     nearest = szd;
2008                     distance = abs(szd->squareSize - squareSize);
2009                     if (distance == 0) break;
2010                 }
2011                 szd++;
2012             }
2013             if (i < 2) lineGap = nearest->lineGap;
2014             if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
2015             if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
2016             if (i < 5) fontPxlSize = nearest->fontPxlSize;
2017             if (i < 6) smallLayout = nearest->smallLayout;
2018             if (i < 7) tinyLayout = nearest->tinyLayout;
2019         }
2020     } else {
2021         SizeDefaults *szd = sizeDefaults;
2022         if (*appData.boardSize == NULLCHAR) {
2023             while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
2024                    DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
2025               szd++;
2026             }
2027             if (szd->name == NULL) szd--;
2028             appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
2029         } else {
2030             while (szd->name != NULL &&
2031                    StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
2032             if (szd->name == NULL) {
2033                 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
2034                         programName, appData.boardSize);
2035                 exit(2);
2036             }
2037         }
2038         squareSize = szd->squareSize;
2039         lineGap = szd->lineGap;
2040         clockFontPxlSize = szd->clockFontPxlSize;
2041         coordFontPxlSize = szd->coordFontPxlSize;
2042         fontPxlSize = szd->fontPxlSize;
2043         smallLayout = szd->smallLayout;
2044         tinyLayout = szd->tinyLayout;
2045         // [HGM] font: use defaults from settings file if available and not overruled
2046     }
2047     if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
2048         appData.clockFont = fontTable[CLOCK_FONT][squareSize];
2049     if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
2050         appData.font = fontTable[MESSAGE_FONT][squareSize];
2051     if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
2052         appData.coordFont = fontTable[COORD_FONT][squareSize];
2053
2054     /* Now, using squareSize as a hint, find a good XPM/XIM set size */
2055     if (strlen(appData.pixmapDirectory) > 0) {
2056         p = ExpandPathName(appData.pixmapDirectory);
2057         if (!p) {
2058             fprintf(stderr, _("Error expanding path name \"%s\"\n"),
2059                    appData.pixmapDirectory);
2060             exit(1);
2061         }
2062         if (appData.debugMode) {
2063           fprintf(stderr, _("\
2064 XBoard square size (hint): %d\n\
2065 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
2066         }
2067         squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
2068         if (appData.debugMode) {
2069             fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
2070         }
2071     }
2072     if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
2073
2074     /* [HR] height treated separately (hacked) */
2075     boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
2076     boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
2077     if (appData.showJail == 1) {
2078         /* Jail on top and bottom */
2079         XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2080         XtSetArg(boardArgs[2], XtNheight,
2081                  boardHeight + 2*(lineGap + squareSize));
2082     } else if (appData.showJail == 2) {
2083         /* Jail on sides */
2084         XtSetArg(boardArgs[1], XtNwidth,
2085                  boardWidth + 2*(lineGap + squareSize));
2086         XtSetArg(boardArgs[2], XtNheight, boardHeight);
2087     } else {
2088         /* No jail */
2089         XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2090         XtSetArg(boardArgs[2], XtNheight, boardHeight);
2091     }
2092
2093     /*
2094      * Determine what fonts to use.
2095      */
2096     appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2097     clockFontID = XLoadFont(xDisplay, appData.clockFont);
2098     clockFontStruct = XQueryFont(xDisplay, clockFontID);
2099     appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2100     coordFontID = XLoadFont(xDisplay, appData.coordFont);
2101     coordFontStruct = XQueryFont(xDisplay, coordFontID);
2102     appData.font = FindFont(appData.font, fontPxlSize);
2103     countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
2104     countFontStruct = XQueryFont(xDisplay, countFontID);
2105 //    appData.font = FindFont(appData.font, fontPxlSize);
2106
2107     xdb = XtDatabase(xDisplay);
2108     XrmPutStringResource(&xdb, "*font", appData.font);
2109
2110     /*
2111      * Detect if there are not enough colors available and adapt.
2112      */
2113     if (DefaultDepth(xDisplay, xScreen) <= 2) {
2114       appData.monoMode = True;
2115     }
2116
2117     forceMono = MakeColors();
2118
2119     if (forceMono) {
2120       fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2121               programName);
2122
2123       if (appData.bitmapDirectory == NULL ||
2124               appData.bitmapDirectory[0] == NULLCHAR)
2125             appData.bitmapDirectory = DEF_BITMAP_DIR;
2126     }
2127
2128     if (appData.lowTimeWarning && !appData.monoMode) {
2129       vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2130       vFrom.size = strlen(appData.lowTimeWarningColor);
2131       XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2132       if (vTo.addr == NULL)
2133                 appData.monoMode = True;
2134       else
2135                 lowTimeWarningColor = *(Pixel *) vTo.addr;
2136     }
2137
2138     if (appData.monoMode && appData.debugMode) {
2139         fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2140                 (unsigned long) XWhitePixel(xDisplay, xScreen),
2141                 (unsigned long) XBlackPixel(xDisplay, xScreen));
2142     }
2143
2144     ParseIcsTextColors();
2145     textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2146     textColors[ColorNone].attr = 0;
2147
2148     XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2149
2150     /*
2151      * widget hierarchy
2152      */
2153     if (tinyLayout) {
2154         layoutName = "tinyLayout";
2155     } else if (smallLayout) {
2156         layoutName = "smallLayout";
2157     } else {
2158         layoutName = "normalLayout";
2159     }
2160     /* Outer layoutWidget is there only to provide a name for use in
2161        resources that depend on the layout style */
2162     layoutWidget =
2163       XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2164                             layoutArgs, XtNumber(layoutArgs));
2165     formWidget =
2166       XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2167                             formArgs, XtNumber(formArgs));
2168     XtSetArg(args[0], XtNdefaultDistance, &sep);
2169     XtGetValues(formWidget, args, 1);
2170
2171     j = 0;
2172     widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2173     XtSetArg(args[0], XtNtop,    XtChainTop);
2174     XtSetArg(args[1], XtNbottom, XtChainTop);
2175     XtSetArg(args[2], XtNright,  XtChainLeft);
2176     XtSetValues(menuBarWidget, args, 3);
2177
2178     widgetList[j++] = whiteTimerWidget =
2179       XtCreateWidget("whiteTime", labelWidgetClass,
2180                      formWidget, timerArgs, XtNumber(timerArgs));
2181     XtSetArg(args[0], XtNfont, clockFontStruct);
2182     XtSetArg(args[1], XtNtop,    XtChainTop);
2183     XtSetArg(args[2], XtNbottom, XtChainTop);
2184     XtSetValues(whiteTimerWidget, args, 3);
2185
2186     widgetList[j++] = blackTimerWidget =
2187       XtCreateWidget("blackTime", labelWidgetClass,
2188                      formWidget, timerArgs, XtNumber(timerArgs));
2189     XtSetArg(args[0], XtNfont, clockFontStruct);
2190     XtSetArg(args[1], XtNtop,    XtChainTop);
2191     XtSetArg(args[2], XtNbottom, XtChainTop);
2192     XtSetValues(blackTimerWidget, args, 3);
2193
2194     if (appData.titleInWindow) {
2195         widgetList[j++] = titleWidget =
2196           XtCreateWidget("title", labelWidgetClass, formWidget,
2197                          titleArgs, XtNumber(titleArgs));
2198         XtSetArg(args[0], XtNtop,    XtChainTop);
2199         XtSetArg(args[1], XtNbottom, XtChainTop);
2200         XtSetValues(titleWidget, args, 2);
2201     }
2202
2203     if (appData.showButtonBar) {
2204       widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2205       XtSetArg(args[0], XtNleft,  XtChainRight); // [HGM] glue to right window edge
2206       XtSetArg(args[1], XtNright, XtChainRight); //       for good run-time sizing
2207       XtSetArg(args[2], XtNtop,    XtChainTop);
2208       XtSetArg(args[3], XtNbottom, XtChainTop);
2209       XtSetValues(buttonBarWidget, args, 4);
2210     }
2211
2212     widgetList[j++] = messageWidget =
2213       XtCreateWidget("message", labelWidgetClass, formWidget,
2214                      messageArgs, XtNumber(messageArgs));
2215     XtSetArg(args[0], XtNtop,    XtChainTop);
2216     XtSetArg(args[1], XtNbottom, XtChainTop);
2217     XtSetValues(messageWidget, args, 2);
2218
2219     widgetList[j++] = boardWidget =
2220       XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2221                      XtNumber(boardArgs));
2222
2223     XtManageChildren(widgetList, j);
2224
2225     timerWidth = (boardWidth - sep) / 2;
2226     XtSetArg(args[0], XtNwidth, timerWidth);
2227     XtSetValues(whiteTimerWidget, args, 1);
2228     XtSetValues(blackTimerWidget, args, 1);
2229
2230     XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2231     XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2232     XtGetValues(whiteTimerWidget, args, 2);
2233
2234     if (appData.showButtonBar) {
2235       XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2236       XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2237       XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2238     }
2239
2240     /*
2241      * formWidget uses these constraints but they are stored
2242      * in the children.
2243      */
2244     i = 0;
2245     XtSetArg(args[i], XtNfromHoriz, 0); i++;
2246     XtSetValues(menuBarWidget, args, i);
2247     if (appData.titleInWindow) {
2248         if (smallLayout) {
2249             i = 0;
2250             XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2251             XtSetValues(whiteTimerWidget, args, i);
2252             i = 0;
2253             XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2254             XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2255             XtSetValues(blackTimerWidget, args, i);
2256             i = 0;
2257             XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2258             XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2259             XtSetValues(titleWidget, args, i);
2260             i = 0;
2261             XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2262             XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2263             XtSetValues(messageWidget, args, i);
2264             if (appData.showButtonBar) {
2265               i = 0;
2266               XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2267               XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2268               XtSetValues(buttonBarWidget, args, i);
2269             }
2270         } else {
2271             i = 0;
2272             XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2273             XtSetValues(whiteTimerWidget, args, i);
2274             i = 0;
2275             XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2276             XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2277             XtSetValues(blackTimerWidget, args, i);
2278             i = 0;
2279             XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2280             XtSetValues(titleWidget, args, i);
2281             i = 0;
2282             XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2283             XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2284             XtSetValues(messageWidget, args, i);
2285             if (appData.showButtonBar) {
2286               i = 0;
2287               XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2288               XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2289               XtSetValues(buttonBarWidget, args, i);
2290             }
2291         }
2292     } else {
2293         i = 0;
2294         XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2295         XtSetValues(whiteTimerWidget, args, i);
2296         i = 0;
2297         XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2298         XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2299         XtSetValues(blackTimerWidget, args, i);
2300         i = 0;
2301         XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2302         XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2303         XtSetValues(messageWidget, args, i);
2304         if (appData.showButtonBar) {
2305           i = 0;
2306           XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2307           XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2308           XtSetValues(buttonBarWidget, args, i);
2309         }
2310     }
2311     i = 0;
2312     XtSetArg(args[0], XtNfromVert, messageWidget);
2313     XtSetArg(args[1], XtNtop,    XtChainTop);
2314     XtSetArg(args[2], XtNbottom, XtChainBottom);
2315     XtSetArg(args[3], XtNleft,   XtChainLeft);
2316     XtSetArg(args[4], XtNright,  XtChainRight);
2317     XtSetValues(boardWidget, args, 5);
2318
2319     XtRealizeWidget(shellWidget);
2320
2321     if(wpMain.x > 0) {
2322       XtSetArg(args[0], XtNx, wpMain.x);
2323       XtSetArg(args[1], XtNy, wpMain.y);
2324       XtSetValues(shellWidget, args, 2);
2325     }
2326
2327     /*
2328      * Correct the width of the message and title widgets.
2329      * It is not known why some systems need the extra fudge term.
2330      * The value "2" is probably larger than needed.
2331      */
2332     XawFormDoLayout(formWidget, False);
2333
2334 #define WIDTH_FUDGE 2
2335     i = 0;
2336     XtSetArg(args[i], XtNborderWidth, &bor);  i++;
2337     XtSetArg(args[i], XtNheight, &h);  i++;
2338     XtGetValues(messageWidget, args, i);
2339     if (appData.showButtonBar) {
2340       i = 0;
2341       XtSetArg(args[i], XtNwidth, &w);  i++;
2342       XtGetValues(buttonBarWidget, args, i);
2343       w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2344     } else {
2345       w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2346     }
2347
2348     gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2349     if (gres != XtGeometryYes && appData.debugMode) {
2350       fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2351               programName, gres, w, h, wr, hr);
2352     }
2353
2354     /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2355     /* The size used for the child widget in layout lags one resize behind
2356        its true size, so we resize a second time, 1 pixel smaller.  Yeech! */
2357     w--;
2358     gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2359     if (gres != XtGeometryYes && appData.debugMode) {
2360       fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2361               programName, gres, w, h, wr, hr);
2362     }
2363     /* !! end hack */
2364     XtSetArg(args[0], XtNleft,  XtChainLeft);  // [HGM] glue ends for good run-time sizing
2365     XtSetArg(args[1], XtNright, XtChainRight);
2366     XtSetValues(messageWidget, args, 2);
2367
2368     if (appData.titleInWindow) {
2369         i = 0;
2370         XtSetArg(args[i], XtNborderWidth, &bor); i++;
2371         XtSetArg(args[i], XtNheight, &h);  i++;
2372         XtGetValues(titleWidget, args, i);
2373         if (smallLayout) {
2374             w = boardWidth - 2*bor;
2375         } else {
2376             XtSetArg(args[0], XtNwidth, &w);
2377             XtGetValues(menuBarWidget, args, 1);
2378             w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2379         }
2380
2381         gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2382         if (gres != XtGeometryYes && appData.debugMode) {
2383             fprintf(stderr,
2384                     _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2385                     programName, gres, w, h, wr, hr);
2386         }
2387     }
2388     XawFormDoLayout(formWidget, True);
2389
2390     xBoardWindow = XtWindow(boardWidget);
2391
2392     // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2393     //       not need to go into InitDrawingSizes().
2394 #endif
2395
2396     /*
2397      * Create X checkmark bitmap and initialize option menu checks.
2398      */
2399     ReadBitmap(&xMarkPixmap, "checkmark.bm",
2400                checkmark_bits, checkmark_width, checkmark_height);
2401     XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2402     if (appData.alwaysPromoteToQueen) {
2403         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2404                     args, 1);
2405     }
2406     if (appData.animateDragging) {
2407         XtSetValues(XtNameToWidget(menuBarWidget,
2408                                    "menuOptions.Animate Dragging"),
2409                     args, 1);
2410     }
2411     if (appData.animate) {
2412         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2413                     args, 1);
2414     }
2415     if (appData.autoCallFlag) {
2416         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2417                     args, 1);
2418     }
2419     if (appData.autoFlipView) {
2420         XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2421                     args, 1);
2422     }
2423     if (appData.blindfold) {
2424         XtSetValues(XtNameToWidget(menuBarWidget,
2425                                    "menuOptions.Blindfold"), args, 1);
2426     }
2427     if (appData.flashCount > 0) {
2428         XtSetValues(XtNameToWidget(menuBarWidget,
2429                                    "menuOptions.Flash Moves"),
2430                     args, 1);
2431     }
2432 #if HIGHDRAG
2433     if (appData.highlightDragging) {
2434         XtSetValues(XtNameToWidget(menuBarWidget,
2435                                    "menuOptions.Highlight Dragging"),
2436                     args, 1);
2437     }
2438 #endif
2439     if (appData.highlightLastMove) {
2440         XtSetValues(XtNameToWidget(menuBarWidget,
2441                                    "menuOptions.Highlight Last Move"),
2442                     args, 1);
2443     }
2444     if (appData.highlightMoveWithArrow) {
2445         XtSetValues(XtNameToWidget(menuBarWidget,
2446                                    "menuOptions.Arrow"),
2447                     args, 1);
2448     }
2449 //    if (appData.icsAlarm) {
2450 //      XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2451 //                  args, 1);
2452 //    }
2453     if (appData.ringBellAfterMoves) {
2454         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2455                     args, 1);
2456     }
2457     if (appData.oneClick) {
2458         XtSetValues(XtNameToWidget(menuBarWidget,
2459                                    "menuOptions.OneClick"), args, 1);
2460     }
2461     if (appData.periodicUpdates) {
2462         XtSetValues(XtNameToWidget(menuBarWidget,
2463                                    "menuOptions.Periodic Updates"), args, 1);
2464     }
2465     if (appData.ponderNextMove) {
2466         XtSetValues(XtNameToWidget(menuBarWidget,
2467                                    "menuOptions.Ponder Next Move"), args, 1);
2468     }
2469     if (appData.popupExitMessage) {
2470         XtSetValues(XtNameToWidget(menuBarWidget,
2471                                    "menuOptions.Popup Exit Message"), args, 1);
2472     }
2473     if (appData.popupMoveErrors) {
2474         XtSetValues(XtNameToWidget(menuBarWidget,
2475                                    "menuOptions.Popup Move Errors"), args, 1);
2476     }
2477 //    if (appData.premove) {
2478 //      XtSetValues(XtNameToWidget(menuBarWidget,
2479 //                                 "menuOptions.Premove"), args, 1);
2480 //    }
2481     if (appData.showCoords) {
2482         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2483                     args, 1);
2484     }
2485     if (appData.hideThinkingFromHuman) {
2486         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2487                     args, 1);
2488     }
2489     if (appData.testLegality) {
2490         XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2491                     args, 1);
2492     }
2493     if (saveSettingsOnExit) {
2494         XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2495                     args, 1);
2496     }
2497
2498     /*
2499      * Create an icon.
2500      */
2501     ReadBitmap(&wIconPixmap, "icon_white.bm",
2502                icon_white_bits, icon_white_width, icon_white_height);
2503     ReadBitmap(&bIconPixmap, "icon_black.bm",
2504                icon_black_bits, icon_black_width, icon_black_height);
2505     iconPixmap = wIconPixmap;
2506     i = 0;
2507     XtSetArg(args[i], XtNiconPixmap, iconPixmap);  i++;
2508     XtSetValues(shellWidget, args, i);
2509
2510     /*
2511      * Create a cursor for the board widget.
2512      */
2513     window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2514     XChangeWindowAttributes(xDisplay, xBoardWindow,
2515                             CWCursor, &window_attributes);
2516
2517     /*
2518      * Inhibit shell resizing.
2519      */
2520     shellArgs[0].value = (XtArgVal) &w;
2521     shellArgs[1].value = (XtArgVal) &h;
2522     XtGetValues(shellWidget, shellArgs, 2);
2523     shellArgs[4].value = shellArgs[2].value = w;
2524     shellArgs[5].value = shellArgs[3].value = h;
2525     XtSetValues(shellWidget, &shellArgs[2], 4);
2526     marginW =  w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2527     marginH =  h - boardHeight;
2528
2529     CatchDeleteWindow(shellWidget, "QuitProc");
2530
2531     CreateGCs(False);
2532     CreateGrid();
2533 #if HAVE_LIBXPM
2534     if (appData.bitmapDirectory[0] != NULLCHAR) {
2535       CreatePieces();
2536     } else {
2537       CreateXPMPieces();
2538       CreateXPMBoard(appData.liteBackTextureFile, 1);
2539       CreateXPMBoard(appData.darkBackTextureFile, 0);
2540     }
2541 #else
2542     CreateXIMPieces();
2543     /* Create regular pieces */
2544     if (!useImages) CreatePieces();
2545 #endif
2546
2547     CreatePieceMenus();
2548
2549     if (appData.animate || appData.animateDragging)
2550       CreateAnimVars();
2551
2552     XtAugmentTranslations(formWidget,
2553                           XtParseTranslationTable(globalTranslations));
2554     XtAugmentTranslations(boardWidget,
2555                           XtParseTranslationTable(boardTranslations));
2556     XtAugmentTranslations(whiteTimerWidget,
2557                           XtParseTranslationTable(whiteTranslations));
2558     XtAugmentTranslations(blackTimerWidget,
2559                           XtParseTranslationTable(blackTranslations));
2560
2561     /* Why is the following needed on some versions of X instead
2562      * of a translation? */
2563     XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2564                       (XtEventHandler) EventProc, NULL);
2565     /* end why */
2566
2567     /* [AS] Restore layout */
2568     if( wpMoveHistory.visible ) {
2569       HistoryPopUp();
2570     }
2571
2572     if( wpEvalGraph.visible )
2573       {
2574         EvalGraphPopUp();
2575       };
2576
2577     if( wpEngineOutput.visible ) {
2578       EngineOutputPopUp();
2579     }
2580
2581     InitBackEnd2();
2582
2583     if (errorExitStatus == -1) {
2584         if (appData.icsActive) {
2585             /* We now wait until we see "login:" from the ICS before
2586                sending the logon script (problems with timestamp otherwise) */
2587             /*ICSInitScript();*/
2588             if (appData.icsInputBox) ICSInputBoxPopUp();
2589         }
2590
2591     #ifdef SIGWINCH
2592     signal(SIGWINCH, TermSizeSigHandler);
2593     #endif
2594         signal(SIGINT, IntSigHandler);
2595         signal(SIGTERM, IntSigHandler);
2596         if (*appData.cmailGameName != NULLCHAR) {
2597             signal(SIGUSR1, CmailSigHandler);
2598         }
2599     }
2600     gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2601     InitPosition(TRUE);
2602     XtSetKeyboardFocus(shellWidget, formWidget);
2603
2604     XtAppMainLoop(appContext);
2605     if (appData.debugMode) fclose(debugFP); // [DM] debug
2606     return 0;
2607 }
2608
2609 void
2610 ShutDownFrontEnd()
2611 {
2612     if (appData.icsActive && oldICSInteractionTitle != NULL) {
2613         DisplayIcsInteractionTitle(oldICSInteractionTitle);
2614     }
2615     if (saveSettingsOnExit) SaveSettings(settingsFileName);
2616     unlink(gameCopyFilename);
2617     unlink(gamePasteFilename);
2618 }
2619
2620 RETSIGTYPE TermSizeSigHandler(int sig)
2621 {
2622     update_ics_width();
2623 }
2624
2625 RETSIGTYPE
2626 IntSigHandler(sig)
2627      int sig;
2628 {
2629     ExitEvent(sig);
2630 }
2631
2632 RETSIGTYPE
2633 CmailSigHandler(sig)
2634      int sig;
2635 {
2636     int dummy = 0;
2637     int error;
2638
2639     signal(SIGUSR1, SIG_IGN);   /* suspend handler     */
2640
2641     /* Activate call-back function CmailSigHandlerCallBack()             */
2642     OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2643
2644     signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2645 }
2646
2647 void
2648 CmailSigHandlerCallBack(isr, closure, message, count, error)
2649      InputSourceRef isr;
2650      VOIDSTAR closure;
2651      char *message;
2652      int count;
2653      int error;
2654 {
2655     BoardToTop();
2656     ReloadCmailMsgEvent(TRUE);  /* Reload cmail msg  */
2657 }
2658 /**** end signal code ****/
2659
2660
2661 void
2662 ICSInitScript()
2663 {
2664   /* try to open the icsLogon script, either in the location given
2665    * or in the users HOME directory
2666    */
2667
2668   FILE *f;
2669   char buf[MSG_SIZ];
2670   char *homedir;
2671
2672   f = fopen(appData.icsLogon, "r");
2673   if (f == NULL)
2674     {
2675       homedir = getenv("HOME");
2676       if (homedir != NULL)
2677         {
2678           safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2679           strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2680           strncat(buf, appData.icsLogon,  MSG_SIZ - strlen(buf) - 1);
2681           f = fopen(buf, "r");
2682         }
2683     }
2684
2685   if (f != NULL)
2686     ProcessICSInitScript(f);
2687   else
2688     printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2689
2690   return;
2691 }
2692
2693 void
2694 ResetFrontEnd()
2695 {
2696     CommentPopDown();
2697     EditCommentPopDown();
2698     TagsPopDown();
2699     return;
2700 }
2701
2702 typedef struct {
2703     char *name;
2704     Boolean value;
2705 } Enables;
2706
2707 void
2708 GreyRevert(grey)
2709      Boolean grey;
2710 {
2711     Widget w;
2712     if (!menuBarWidget) return;
2713     w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2714     if (w == NULL) {
2715       DisplayError("menuEdit.Revert", 0);
2716     } else {
2717       XtSetSensitive(w, !grey);
2718     }
2719     w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2720     if (w == NULL) {
2721       DisplayError("menuEdit.Annotate", 0);
2722     } else {
2723       XtSetSensitive(w, !grey);
2724     }
2725 }
2726
2727 void
2728 SetMenuEnables(enab)
2729      Enables *enab;
2730 {
2731   Widget w;
2732   if (!menuBarWidget) return;
2733   while (enab->name != NULL) {
2734     w = XtNameToWidget(menuBarWidget, enab->name);
2735     if (w == NULL) {
2736       DisplayError(enab->name, 0);
2737     } else {
2738       XtSetSensitive(w, enab->value);
2739     }
2740     enab++;
2741   }
2742 }
2743
2744 Enables icsEnables[] = {
2745     { "menuFile.Mail Move", False },
2746     { "menuFile.Reload CMail Message", False },
2747     { "menuMode.Machine Black", False },
2748     { "menuMode.Machine White", False },
2749     { "menuMode.Analysis Mode", False },
2750     { "menuMode.Analyze File", False },
2751     { "menuMode.Two Machines", False },
2752 #ifndef ZIPPY
2753     { "menuEngine.Hint", False },
2754     { "menuEngine.Book", False },
2755     { "menuEngine.Move Now", False },
2756     { "menuOptions.Periodic Updates", False },
2757     { "menuOptions.Hide Thinking", False },
2758     { "menuOptions.Ponder Next Move", False },
2759     { "menuEngine.Engine #1 Settings", False },
2760 #endif
2761     { "menuEngine.Engine #2 Settings", False },
2762     { "menuEdit.Annotate", False },
2763     { NULL, False }
2764 };
2765
2766 Enables ncpEnables[] = {
2767     { "menuFile.Mail Move", False },
2768     { "menuFile.Reload CMail Message", False },
2769     { "menuMode.Machine White", False },
2770     { "menuMode.Machine Black", False },
2771     { "menuMode.Analysis Mode", False },
2772     { "menuMode.Analyze File", False },
2773     { "menuMode.Two Machines", False },
2774     { "menuMode.ICS Client", False },
2775     { "menuView.ICS Input Box", False },
2776     { "Action", False },
2777     { "menuEdit.Revert", False },
2778     { "menuEdit.Annotate", False },
2779     { "menuEngine.Engine #1 Settings", False },
2780     { "menuEngine.Engine #2 Settings", False },
2781     { "menuEngine.Move Now", False },
2782     { "menuEngine.Retract Move", False },
2783     { "menuOptions.Auto Flag", False },
2784     { "menuOptions.Auto Flip View", False },
2785 //    { "menuOptions.ICS Alarm", False },
2786     { "menuOptions.Move Sound", False },
2787     { "menuOptions.Hide Thinking", False },
2788     { "menuOptions.Periodic Updates", False },
2789     { "menuOptions.Ponder Next Move", False },
2790     { "menuEngine.Hint", False },
2791     { "menuEngine.Book", False },
2792     { NULL, False }
2793 };
2794
2795 Enables gnuEnables[] = {
2796     { "menuMode.ICS Client", False },
2797     { "menuView.ICS Input Box", False },
2798     { "menuAction.Accept", False },
2799     { "menuAction.Decline", False },
2800     { "menuAction.Rematch", False },
2801     { "menuAction.Adjourn", False },
2802     { "menuAction.Stop Examining", False },
2803     { "menuAction.Stop Observing", False },
2804     { "menuAction.Upload to Examine", False },
2805     { "menuEdit.Revert", False },
2806     { "menuEdit.Annotate", 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