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