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