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