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