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