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