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