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