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