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