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