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