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