changes from H.G. Muller; version 4.3.15
[xboard.git] / xboard.c
1 /*\r
2  * xboard.c -- X front end for XBoard\r
3  * $Id: xboard.c,v 2.2 2003/11/06 07:22:14 mann Exp $\r
4  *\r
5  * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts.\r
6  * Enhancements Copyright 1992-2001 Free Software Foundation, Inc.\r
7  *\r
8  * The following terms apply to Digital Equipment Corporation's copyright\r
9  * interest in XBoard:\r
10  * ------------------------------------------------------------------------\r
11  * All Rights Reserved\r
12  *\r
13  * Permission to use, copy, modify, and distribute this software and its\r
14  * documentation for any purpose and without fee is hereby granted,\r
15  * provided that the above copyright notice appear in all copies and that\r
16  * both that copyright notice and this permission notice appear in\r
17  * supporting documentation, and that the name of Digital not be\r
18  * used in advertising or publicity pertaining to distribution of the\r
19  * software without specific, written prior permission.\r
20  *\r
21  * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING\r
22  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL\r
23  * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR\r
24  * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,\r
25  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,\r
26  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS\r
27  * SOFTWARE.\r
28  * ------------------------------------------------------------------------\r
29  *\r
30  * The following terms apply to the enhanced version of XBoard distributed\r
31  * by the Free Software Foundation:\r
32  * ------------------------------------------------------------------------\r
33  * This program is free software; you can redistribute it and/or modify\r
34  * it under the terms of the GNU General Public License as published by\r
35  * the Free Software Foundation; either version 2 of the License, or\r
36  * (at your option) any later version.\r
37  *\r
38  * This program is distributed in the hope that it will be useful,\r
39  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
40  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
41  * GNU General Public License for more details.\r
42  *\r
43  * You should have received a copy of the GNU General Public License\r
44  * along with this program; if not, write to the Free Software\r
45  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\r
46  * ------------------------------------------------------------------------\r
47  *\r
48  * See the file ChangeLog for a revision history.\r
49  */\r
50 \r
51 #include "config.h"\r
52 \r
53 #include <stdio.h>\r
54 #include <ctype.h>\r
55 #include <signal.h>\r
56 #include <errno.h>\r
57 #include <sys/types.h>\r
58 #include <sys/stat.h>\r
59 #include <pwd.h>\r
60 \r
61 #if !OMIT_SOCKETS\r
62 # if HAVE_SYS_SOCKET_H\r
63 #  include <sys/socket.h>\r
64 #  include <netinet/in.h>\r
65 #  include <netdb.h>\r
66 # else /* not HAVE_SYS_SOCKET_H */\r
67 #  if HAVE_LAN_SOCKET_H\r
68 #   include <lan/socket.h>\r
69 #   include <lan/in.h>\r
70 #   include <lan/netdb.h>\r
71 #  else /* not HAVE_LAN_SOCKET_H */\r
72 #   define OMIT_SOCKETS 1\r
73 #  endif /* not HAVE_LAN_SOCKET_H */\r
74 # endif /* not HAVE_SYS_SOCKET_H */\r
75 #endif /* !OMIT_SOCKETS */\r
76 \r
77 #if STDC_HEADERS\r
78 # include <stdlib.h>\r
79 # include <string.h>\r
80 #else /* not STDC_HEADERS */\r
81 extern char *getenv();\r
82 # if HAVE_STRING_H\r
83 #  include <string.h>\r
84 # else /* not HAVE_STRING_H */\r
85 #  include <strings.h>\r
86 # endif /* not HAVE_STRING_H */\r
87 #endif /* not STDC_HEADERS */\r
88 \r
89 #if HAVE_SYS_FCNTL_H\r
90 # include <sys/fcntl.h>\r
91 #else /* not HAVE_SYS_FCNTL_H */\r
92 # if HAVE_FCNTL_H\r
93 #  include <fcntl.h>\r
94 # endif /* HAVE_FCNTL_H */\r
95 #endif /* not HAVE_SYS_FCNTL_H */\r
96 \r
97 #if HAVE_SYS_SYSTEMINFO_H\r
98 # include <sys/systeminfo.h>\r
99 #endif /* HAVE_SYS_SYSTEMINFO_H */\r
100 \r
101 #if TIME_WITH_SYS_TIME\r
102 # include <sys/time.h>\r
103 # include <time.h>\r
104 #else\r
105 # if HAVE_SYS_TIME_H\r
106 #  include <sys/time.h>\r
107 # else\r
108 #  include <time.h>\r
109 # endif\r
110 #endif\r
111 \r
112 #if HAVE_UNISTD_H\r
113 # include <unistd.h>\r
114 #endif\r
115 \r
116 #if HAVE_SYS_WAIT_H\r
117 # include <sys/wait.h>\r
118 #endif\r
119 \r
120 #if HAVE_DIRENT_H\r
121 # include <dirent.h>\r
122 # define NAMLEN(dirent) strlen((dirent)->d_name)\r
123 # define HAVE_DIR_STRUCT\r
124 #else\r
125 # define dirent direct\r
126 # define NAMLEN(dirent) (dirent)->d_namlen\r
127 # if HAVE_SYS_NDIR_H\r
128 #  include <sys/ndir.h>\r
129 #  define HAVE_DIR_STRUCT\r
130 # endif\r
131 # if HAVE_SYS_DIR_H\r
132 #  include <sys/dir.h>\r
133 #  define HAVE_DIR_STRUCT\r
134 # endif\r
135 # if HAVE_NDIR_H\r
136 #  include <ndir.h>\r
137 #  define HAVE_DIR_STRUCT\r
138 # endif\r
139 #endif\r
140 \r
141 #include <X11/Intrinsic.h>\r
142 #include <X11/StringDefs.h>\r
143 #include <X11/Shell.h>\r
144 #include <X11/cursorfont.h>\r
145 #include <X11/Xatom.h>\r
146 #if USE_XAW3D\r
147 #include <X11/Xaw3d/Dialog.h>\r
148 #include <X11/Xaw3d/Form.h>\r
149 #include <X11/Xaw3d/List.h>\r
150 #include <X11/Xaw3d/Label.h>\r
151 #include <X11/Xaw3d/SimpleMenu.h>\r
152 #include <X11/Xaw3d/SmeBSB.h>\r
153 #include <X11/Xaw3d/SmeLine.h>\r
154 #include <X11/Xaw3d/Box.h>\r
155 #include <X11/Xaw3d/MenuButton.h>\r
156 #include <X11/Xaw3d/Text.h>\r
157 #include <X11/Xaw3d/AsciiText.h>\r
158 #else\r
159 #include <X11/Xaw/Dialog.h>\r
160 #include <X11/Xaw/Form.h>\r
161 #include <X11/Xaw/List.h>\r
162 #include <X11/Xaw/Label.h>\r
163 #include <X11/Xaw/SimpleMenu.h>\r
164 #include <X11/Xaw/SmeBSB.h>\r
165 #include <X11/Xaw/SmeLine.h>\r
166 #include <X11/Xaw/Box.h>\r
167 #include <X11/Xaw/MenuButton.h>\r
168 #include <X11/Xaw/Text.h>\r
169 #include <X11/Xaw/AsciiText.h>\r
170 #endif\r
171 \r
172 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.\r
173 #include "common.h"\r
174 \r
175 #if HAVE_LIBXPM\r
176 #include <X11/xpm.h>\r
177 #include "pixmaps/pixmaps.h"\r
178 #define IMAGE_EXT "xpm"\r
179 #else\r
180 #define IMAGE_EXT "xim"\r
181 #include "bitmaps/bitmaps.h"\r
182 #endif\r
183 \r
184 #include "bitmaps/icon_white.bm"\r
185 #include "bitmaps/icon_black.bm"\r
186 #include "bitmaps/checkmark.bm"\r
187 \r
188 #include "frontend.h"\r
189 #include "backend.h"\r
190 #include "moves.h"\r
191 #include "xboard.h"\r
192 #include "childio.h"\r
193 #include "xgamelist.h"\r
194 #include "xhistory.h"\r
195 #include "xedittags.h"
196
197 // must be moved to xengineoutput.h
198 void EngineOutputProc P((Widget w, XEvent *event,
199                         String *prms, Cardinal *nprms));
200 void EngineOutputPopDown();\r
201 \r
202 \r
203 #ifdef __EMX__\r
204 #ifndef HAVE_USLEEP\r
205 #define HAVE_USLEEP\r
206 #endif\r
207 #define usleep(t)   _sleep2(((t)+500)/1000)\r
208 #endif\r
209 \r
210 typedef struct {\r
211     String string;\r
212     XtActionProc proc;\r
213 } MenuItem;\r
214 \r
215 typedef struct {\r
216     String name;\r
217     MenuItem *mi;\r
218 } Menu;\r
219 \r
220 int main P((int argc, char **argv));\r
221 RETSIGTYPE CmailSigHandler P((int sig));\r
222 RETSIGTYPE IntSigHandler P((int sig));\r
223 void CreateGCs P((void));\r
224 void CreateXIMPieces P((void));\r
225 void CreateXPMPieces P((void));\r
226 void CreatePieces P((void));\r
227 void CreatePieceMenus P((void));\r
228 Widget CreateMenuBar P((Menu *mb));\r
229 Widget CreateButtonBar P ((MenuItem *mi));\r
230 char *FindFont P((char *pattern, int targetPxlSize));\r
231 void PieceMenuPopup P((Widget w, XEvent *event,\r
232                        String *params, Cardinal *num_params));\r
233 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));\r
234 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));\r
235 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],\r
236                    u_int wreq, u_int hreq));\r
237 void CreateGrid P((void));\r
238 int EventToSquare P((int x, int limit));\r
239 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));\r
240 void EventProc P((Widget widget, caddr_t unused, XEvent *event));\r
241 void HandleUserMove P((Widget w, XEvent *event,\r
242                      String *prms, Cardinal *nprms));\r
243 void AnimateUserMove P((Widget w, XEvent * event,\r
244                      String * params, Cardinal * nParams));\r
245 void WhiteClock P((Widget w, XEvent *event,\r
246                    String *prms, Cardinal *nprms));\r
247 void BlackClock P((Widget w, XEvent *event,\r
248                    String *prms, Cardinal *nprms));\r
249 void DrawPositionProc P((Widget w, XEvent *event,\r
250                      String *prms, Cardinal *nprms));\r
251 void XDrawPosition P((Widget w, /*Boolean*/int repaint, \r
252                      Board board));\r
253 void CommentPopUp P((char *title, char *label));\r
254 void CommentPopDown P((void));\r
255 void CommentCallback P((Widget w, XtPointer client_data,\r
256                         XtPointer call_data));\r
257 void ICSInputBoxPopUp P((void));\r
258 void ICSInputBoxPopDown P((void));\r
259 void FileNamePopUp P((char *label, char *def,\r
260                       FileProc proc, char *openMode));\r
261 void FileNamePopDown P((void));\r
262 void FileNameCallback P((Widget w, XtPointer client_data,\r
263                          XtPointer call_data));\r
264 void FileNameAction P((Widget w, XEvent *event,\r
265                        String *prms, Cardinal *nprms));\r
266 void AskQuestionReplyAction P((Widget w, XEvent *event,\r
267                           String *prms, Cardinal *nprms));\r
268 void AskQuestionProc P((Widget w, XEvent *event,\r
269                           String *prms, Cardinal *nprms));\r
270 void AskQuestionPopDown P((void));\r
271 void PromotionPopUp P((void));\r
272 void PromotionPopDown P((void));\r
273 void PromotionCallback P((Widget w, XtPointer client_data,\r
274                           XtPointer call_data));\r
275 void EditCommentPopDown P((void));\r
276 void EditCommentCallback P((Widget w, XtPointer client_data,\r
277                             XtPointer call_data));\r
278 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));\r
279 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
280 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
281 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,\r
282                          Cardinal *nprms));\r
283 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,\r
284                          Cardinal *nprms));\r
285 void ReloadGameProc P((Widget w, XEvent *event, String *prms,\r
286                        Cardinal *nprms));\r
287 void LoadPositionProc P((Widget w, XEvent *event,\r
288                          String *prms, Cardinal *nprms));\r
289 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,\r
290                          Cardinal *nprms));\r
291 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,\r
292                          Cardinal *nprms));\r
293 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,\r
294                        Cardinal *nprms));\r
295 void CopyPositionProc P((Widget w, XEvent *event, String *prms,\r
296                          Cardinal *nprms));\r
297 void PastePositionProc P((Widget w, XEvent *event, String *prms,\r
298                           Cardinal *nprms));\r
299 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
300 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
301 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
302 void SavePositionProc P((Widget w, XEvent *event,\r
303                          String *prms, Cardinal *nprms));\r
304 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
305 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,\r
306                             Cardinal *nprms));\r
307 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
308 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
309 void MachineBlackProc P((Widget w, XEvent *event, String *prms,\r
310                          Cardinal *nprms));\r
311 void MachineWhiteProc P((Widget w, XEvent *event,\r
312                          String *prms, Cardinal *nprms));\r
313 void AnalyzeModeProc P((Widget w, XEvent *event,\r
314                          String *prms, Cardinal *nprms));\r
315 void AnalyzeFileProc P((Widget w, XEvent *event,\r
316                          String *prms, Cardinal *nprms));\r
317 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,\r
318                         Cardinal *nprms));\r
319 void IcsClientProc P((Widget w, XEvent *event, String *prms,\r
320                       Cardinal *nprms));\r
321 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
322 void EditPositionProc P((Widget w, XEvent *event,\r
323                          String *prms, Cardinal *nprms));\r
324 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
325 void EditCommentProc P((Widget w, XEvent *event,\r
326                         String *prms, Cardinal *nprms));\r
327 void IcsInputBoxProc P((Widget w, XEvent *event,\r
328                         String *prms, Cardinal *nprms));\r
329 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
330 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
331 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
332 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
333 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
334 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
335 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
336 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
337 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
338 void StopObservingProc P((Widget w, XEvent *event, String *prms,\r
339                           Cardinal *nprms));\r
340 void StopExaminingProc P((Widget w, XEvent *event, String *prms,\r
341                           Cardinal *nprms));\r
342 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
343 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
344 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
345 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
346 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
347 void TruncateGameProc P((Widget w, XEvent *event, String *prms,\r
348                          Cardinal *nprms));\r
349 void RetractMoveProc P((Widget w, XEvent *event, String *prms,\r
350                         Cardinal *nprms));\r
351 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
352 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,\r
353                         Cardinal *nprms));\r
354 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,\r
355                          Cardinal *nprms));\r
356 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,\r
357                          Cardinal *nprms));\r
358 void AutocommProc P((Widget w, XEvent *event, String *prms,\r
359                      Cardinal *nprms));\r
360 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
361 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
362 void AutobsProc P((Widget w, XEvent *event, String *prms,\r
363                         Cardinal *nprms));\r
364 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
365 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
366 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
367 void FlashMovesProc P((Widget w, XEvent *event, String *prms,\r
368                        Cardinal *nprms));\r
369 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
370 void GetMoveListProc P((Widget w, XEvent *event, String *prms,\r
371                         Cardinal *nprms));\r
372 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,\r
373                               Cardinal *nprms));\r
374 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,\r
375                               Cardinal *nprms));\r
376 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
377 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
378 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,\r
379                          Cardinal *nprms));\r
380 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,\r
381                          Cardinal *nprms));\r
382 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,\r
383                            Cardinal *nprms));\r
384 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,\r
385                         Cardinal *nprms));\r
386 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,\r
387                              Cardinal *nprms));\r
388 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
389 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
390 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,\r
391                        Cardinal *nprms));\r
392 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,\r
393                          Cardinal *nprms));\r
394 void HideThinkingProc P((Widget w, XEvent *event, String *prms,\r
395                          Cardinal *nprms));\r
396 void TestLegalityProc P((Widget w, XEvent *event, String *prms,\r
397                           Cardinal *nprms));\r
398 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
399 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
400 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
401 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
402 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
403 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
404 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
405 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
406 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
407 void DisplayMove P((int moveNumber));\r
408 void DisplayTitle P((char *title));\r
409 void ICSInitScript P((void));\r
410 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));\r
411 void ErrorPopUp P((char *title, char *text, int modal));\r
412 void ErrorPopDown P((void));\r
413 static char *ExpandPathName P((char *path));\r
414 static void CreateAnimVars P((void));\r
415 static void DragPieceBegin P((int x, int y));\r
416 static void DragPieceMove P((int x, int y));\r
417 static void DragPieceEnd P((int x, int y));\r
418 static void DrawDragPiece P((void));\r
419 char *ModeToWidgetName P((GameMode mode));\r
420 void EngineOutputUpdate( FrontEndProgramStats * stats );\r
421 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
422 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
423 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
424 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
425 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));\r
426 void ShufflePopDown P(());\r
427 void EnginePopDown P(());\r
428 void UciPopDown P(());\r
429 void TimeControlPopDown P(());\r
430 void NewVariantPopDown P(());\r
431 /*\r
432 * XBoard depends on Xt R4 or higher\r
433 */\r
434 int xtVersion = XtSpecificationRelease;\r
435 \r
436 int xScreen;\r
437 Display *xDisplay;\r
438 Window xBoardWindow;\r
439 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,\r
440   jailSquareColor, highlightSquareColor, premoveHighlightColor;\r
441 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,\r
442   bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,\r
443   wjPieceGC, bjPieceGC, prelineGC, countGC;\r
444 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;\r
445 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget, \r
446   whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16], \r
447   commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,\r
448   menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,\r
449   ICSInputShell, fileNameShell, askQuestionShell;\r
450 XSegment gridSegments[(BOARD_SIZE + 1) * 2];\r
451 XSegment jailGridSegments[(BOARD_SIZE + 3) * 2];\r
452 Font clockFontID, coordFontID, countFontID;\r
453 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;\r
454 XtAppContext appContext;\r
455 char *layoutName;\r
456 char *oldICSInteractionTitle;\r
457 \r
458 FileProc fileProc;\r
459 char *fileOpenMode;
460 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion\r
461 \r
462 Position commentX = -1, commentY = -1;\r
463 Dimension commentW, commentH;\r
464 \r
465 int squareSize, smallLayout = 0, tinyLayout = 0,
466   marginW, marginH, // [HGM] for run-time resizing\r
467   fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,\r
468   ICSInputBoxUp = False, askQuestionUp = False,\r
469   filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,\r
470   editUp = False, errorUp = False, errorExitStatus = -1, lineGap;\r
471 Pixel timerForegroundPixel, timerBackgroundPixel;\r
472 Pixel buttonForegroundPixel, buttonBackgroundPixel;\r
473 char *chessDir, *programName, *programVersion,\r
474   *gameCopyFilename, *gamePasteFilename;\r
475 \r
476 #define SOLID 0\r
477 #define OUTLINE 1\r
478 Pixmap pieceBitmap[2][(int)BlackPawn];\r
479 Pixmap xpmPieceBitmap[4][(int)BlackPawn];       /* LL, LD, DL, DD */\r
480 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;\r
481 int useImages, useImageSqs;\r
482 XImage *ximPieceBitmap[4][(int)BlackPawn];      /* LL, LD, DL, DD */\r
483 Pixmap ximMaskPm[(int)BlackPawn];            /* clipmasks, used for XIM pieces */\r
484 XImage *ximLightSquare, *ximDarkSquare;\r
485 XImage *xim_Cross;\r
486 \r
487 #define pieceToSolid(piece) &pieceBitmap[SOLID][((int)(piece)) % (int)BlackPawn]\r
488 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][((int)(piece)) % (int)BlackPawn]\r
489 \r
490 #define White(piece) ((int)(piece) < (int)BlackPawn)\r
491 \r
492 /* Variables for doing smooth animation. This whole thing\r
493    would be much easier if the board was double-buffered,\r
494    but that would require a fairly major rewrite.       */\r
495 \r
496 typedef struct {\r
497         Pixmap  saveBuf;\r
498         Pixmap  newBuf;\r
499         GC      blitGC, pieceGC, outlineGC;\r
500         XPoint  startSquare, prevFrame, mouseDelta;\r
501         int     startColor;\r
502         int     dragPiece;\r
503         Boolean dragActive;\r
504         int     startBoardX, startBoardY;\r
505     } AnimState;\r
506 \r
507 /* There can be two pieces being animated at once: a player\r
508    can begin dragging a piece before the remote opponent has moved. */\r
509 \r
510 static AnimState game, player;\r
511 \r
512 /* Bitmaps for use as masks when drawing XPM pieces.\r
513    Need one for each black and white piece.             */\r
514 static Pixmap xpmMask[BlackKing + 1];\r
515 \r
516 /* This magic number is the number of intermediate frames used\r
517    in each half of the animation. For short moves it's reduced\r
518    by 1. The total number of frames will be factor * 2 + 1.  */\r
519 #define kFactor    4\r
520 \r
521 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;\r
522 \r
523 MenuItem fileMenu[] = {\r
524     {"New Game", ResetProc},\r
525     {"New Shuffle Game ...", ShuffleMenuProc},\r
526     {"New Variant ...", NewVariantProc},      // [HGM] variant: not functional yet\r
527     {"----", NothingProc},\r
528     {"Load Game", LoadGameProc},\r
529     {"Load Next Game", LoadNextGameProc},\r
530     {"Load Previous Game", LoadPrevGameProc},\r
531     {"Reload Same Game", ReloadGameProc},\r
532     {"Save Game", SaveGameProc},\r
533     {"----", NothingProc},\r
534     {"Copy Game", CopyGameProc},\r
535     {"Paste Game", PasteGameProc},\r
536     {"----", NothingProc},\r
537     {"Load Position", LoadPositionProc},\r
538     {"Load Next Position", LoadNextPositionProc},\r
539     {"Load Previous Position", LoadPrevPositionProc},\r
540     {"Reload Same Position", ReloadPositionProc},\r
541     {"Save Position", SavePositionProc},\r
542     {"----", NothingProc},\r
543     {"Copy Position", CopyPositionProc},\r
544     {"Paste Position", PastePositionProc},\r
545     {"----", NothingProc},\r
546     {"Mail Move", MailMoveProc},\r
547     {"Reload CMail Message", ReloadCmailMsgProc},\r
548     {"----", NothingProc},\r
549     {"Exit", QuitProc},\r
550     {NULL, NULL}\r
551 };\r
552 \r
553 MenuItem modeMenu[] = {\r
554     {"Machine White", MachineWhiteProc},\r
555     {"Machine Black", MachineBlackProc},\r
556     {"Two Machines", TwoMachinesProc},\r
557     {"Analysis Mode", AnalyzeModeProc},\r
558     {"Analyze File", AnalyzeFileProc },\r
559     {"ICS Client", IcsClientProc},\r
560     {"Edit Game", EditGameProc},\r
561     {"Edit Position", EditPositionProc},\r
562     {"Training", TrainingProc},\r
563     {"----", NothingProc},\r
564     {"Show Engine Output", EngineOutputProc},\r
565     {"Show Evaluation Graph", NothingProc}, // [HGM] evalgr: not functional yet\r
566     {"Show Game List", ShowGameListProc},\r
567     {"Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code\r
568     {"----", NothingProc},\r
569     {"Edit Tags", EditTagsProc},\r
570     {"Edit Comment", EditCommentProc},\r
571     {"ICS Input Box", IcsInputBoxProc},\r
572     {"Pause", PauseProc},\r
573     {NULL, NULL}\r
574 };\r
575 \r
576 MenuItem actionMenu[] = {\r
577     {"Accept", AcceptProc},\r
578     {"Decline", DeclineProc},\r
579     {"Rematch", RematchProc},\r
580     {"----", NothingProc},    \r
581     {"Call Flag", CallFlagProc},\r
582     {"Draw", DrawProc},\r
583     {"Adjourn", AdjournProc},\r
584     {"Abort", AbortProc},\r
585     {"Resign", ResignProc},\r
586     {"----", NothingProc},    \r
587     {"Stop Observing", StopObservingProc},\r
588     {"Stop Examining", StopExaminingProc},\r
589     {NULL, NULL}\r
590 };\r
591 \r
592 MenuItem stepMenu[] = {\r
593     {"Backward", BackwardProc},\r
594     {"Forward", ForwardProc},\r
595     {"Back to Start", ToStartProc},\r
596     {"Forward to End", ToEndProc},\r
597     {"Revert", RevertProc},\r
598     {"Truncate Game", TruncateGameProc},\r
599     {"----", NothingProc},    \r
600     {"Move Now", MoveNowProc},\r
601     {"Retract Move", RetractMoveProc},\r
602     {NULL, NULL}\r
603 };    \r
604 \r
605 MenuItem optionsMenu[] = {
606     {"Flip View", FlipViewProc},\r
607     {"----", NothingProc},    \r
608     {"Adjudications ...", EngineMenuProc},    \r
609     {"Engine Settings ...", UciMenuProc},    \r
610     {"Time Control ...", TimeControlProc},    \r
611     {"----", NothingProc},    \r
612     {"Always Queen", AlwaysQueenProc},\r
613     {"Animate Dragging", AnimateDraggingProc},\r
614     {"Animate Moving", AnimateMovingProc},\r
615     {"Auto Comment", AutocommProc},\r
616     {"Auto Flag", AutoflagProc},\r
617     {"Auto Flip View", AutoflipProc},\r
618     {"Auto Observe", AutobsProc},\r
619     {"Auto Raise Board", AutoraiseProc},\r
620     {"Auto Save", AutosaveProc},\r
621     {"Blindfold", BlindfoldProc},\r
622     {"Flash Moves", FlashMovesProc},\r
623     {"Get Move List", GetMoveListProc},\r
624 #if HIGHDRAG\r
625     {"Highlight Dragging", HighlightDraggingProc},\r
626 #endif\r
627     {"Highlight Last Move", HighlightLastMoveProc},\r
628     {"Move Sound", MoveSoundProc},\r
629     {"ICS Alarm", IcsAlarmProc},\r
630     {"Old Save Style", OldSaveStyleProc},\r
631     {"Periodic Updates", PeriodicUpdatesProc},  \r
632     {"Ponder Next Move", PonderNextMoveProc},\r
633     {"Popup Exit Message", PopupExitMessageProc},       \r
634     {"Popup Move Errors", PopupMoveErrorsProc}, \r
635     {"Premove", PremoveProc},\r
636     {"Quiet Play", QuietPlayProc},\r
637     {"Show Coords", ShowCoordsProc},\r
638     {"Hide Thinking", HideThinkingProc},\r
639     {"Test Legality", TestLegalityProc},\r
640     {NULL, NULL}\r
641 };\r
642 \r
643 MenuItem helpMenu[] = {\r
644     {"Info XBoard", InfoProc},\r
645     {"Man XBoard", ManProc},\r
646     {"----", NothingProc},\r
647     {"Hint", HintProc},\r
648     {"Book", BookProc},\r
649     {"----", NothingProc},\r
650     {"About XBoard", AboutProc},\r
651     {NULL, NULL}\r
652 };\r
653 \r
654 Menu menuBar[] = {\r
655     {"File", fileMenu},\r
656     {"Mode", modeMenu},\r
657     {"Action", actionMenu},\r
658     {"Step", stepMenu},\r
659     {"Options", optionsMenu},\r
660     {"Help", helpMenu},\r
661     {NULL, NULL}\r
662 };\r
663 \r
664 #define PAUSE_BUTTON "P"\r
665 MenuItem buttonBar[] = {\r
666     {"<<", ToStartProc},\r
667     {"<", BackwardProc},\r
668     {PAUSE_BUTTON, PauseProc},\r
669     {">", ForwardProc},\r
670     {">>", ToEndProc},\r
671     {NULL, NULL}\r
672 };\r
673 \r
674 #define PIECE_MENU_SIZE 11\r
675 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {\r
676     { "White", "----", "Pawn", "Knight", "Bishop", "Rook", "Queen", "King",\r
677       "----", "Empty square", "Clear board" },\r
678     { "Black", "----", "Pawn", "Knight", "Bishop", "Rook", "Queen", "King",\r
679       "----", "Empty square", "Clear board" },\r
680   };\r
681 /* must be in same order as PieceMenuStrings! */\r
682 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {\r
683     { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,\r
684         WhiteRook, WhiteQueen, WhiteKing,\r
685         (ChessSquare) 0, EmptySquare, ClearBoard },\r
686     { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,\r
687         BlackRook, BlackQueen, BlackKing,\r
688         (ChessSquare) 0, EmptySquare, ClearBoard },\r
689 };\r
690 \r
691 #define DROP_MENU_SIZE 6\r
692 String dropMenuStrings[DROP_MENU_SIZE] = {\r
693     "----", "Pawn", "Knight", "Bishop", "Rook", "Queen"\r
694   };\r
695 /* must be in same order as PieceMenuStrings! */\r
696 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {\r
697     (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,\r
698     WhiteRook, WhiteQueen\r
699 };\r
700 \r
701 typedef struct {\r
702     char piece;\r
703     char* widget;\r
704 } DropMenuEnables;\r
705 \r
706 DropMenuEnables dmEnables[] = {\r
707     { 'P', "Pawn" },\r
708     { 'N', "Knight" },\r
709     { 'B', "Bishop" },\r
710     { 'R', "Rook" },\r
711     { 'Q', "Queen" }\r
712 };\r
713 \r
714 Arg shellArgs[] = {\r
715     { XtNwidth, 0 },\r
716     { XtNheight, 0 },\r
717     { XtNminWidth, 0 },\r
718     { XtNminHeight, 0 },\r
719     { XtNmaxWidth, 0 },\r
720     { XtNmaxHeight, 0 }\r
721 };\r
722 \r
723 Arg layoutArgs[] = {\r
724     { XtNborderWidth, 0 },\r
725     { XtNdefaultDistance, 0 },\r
726 };\r
727 \r
728 Arg formArgs[] = {\r
729     { XtNborderWidth, 0 },\r
730     { XtNresizable, (XtArgVal) True },\r
731 };\r
732 \r
733 Arg boardArgs[] = {\r
734     { XtNborderWidth, 0 },\r
735     { XtNwidth, 0 },\r
736     { XtNheight, 0 }\r
737 };\r
738 \r
739 Arg titleArgs[] = {\r
740     { XtNjustify, (XtArgVal) XtJustifyRight },\r
741     { XtNlabel, (XtArgVal) "..." },\r
742     { XtNresizable, (XtArgVal) True },\r
743     { XtNresize, (XtArgVal) False }\r
744 };\r
745 \r
746 Arg messageArgs[] = {\r
747     { XtNjustify, (XtArgVal) XtJustifyLeft },\r
748     { XtNlabel, (XtArgVal) "..." },\r
749     { XtNresizable, (XtArgVal) True },\r
750     { XtNresize, (XtArgVal) False }\r
751 };\r
752 \r
753 Arg timerArgs[] = {\r
754     { XtNborderWidth, 0 },\r
755     { XtNjustify, (XtArgVal) XtJustifyLeft }\r
756 };\r
757 \r
758 XtResource clientResources[] = {\r
759     { "whitePieceColor", "whitePieceColor", XtRString, sizeof(String),\r
760         XtOffset(AppDataPtr, whitePieceColor), XtRString,\r
761         WHITE_PIECE_COLOR },\r
762     { "blackPieceColor", "blackPieceColor", XtRString, sizeof(String),\r
763         XtOffset(AppDataPtr, blackPieceColor), XtRString,\r
764         BLACK_PIECE_COLOR },\r
765     { "lightSquareColor", "lightSquareColor", XtRString,\r
766         sizeof(String), XtOffset(AppDataPtr, lightSquareColor),\r
767         XtRString, LIGHT_SQUARE_COLOR }, \r
768     { "darkSquareColor", "darkSquareColor", XtRString, sizeof(String),\r
769         XtOffset(AppDataPtr, darkSquareColor), XtRString,\r
770         DARK_SQUARE_COLOR },\r
771     { "highlightSquareColor", "highlightSquareColor", XtRString,\r
772         sizeof(String), XtOffset(AppDataPtr, highlightSquareColor),\r
773         XtRString, HIGHLIGHT_SQUARE_COLOR },\r
774     { "premoveHighlightColor", "premoveHighlightColor", XtRString,\r
775         sizeof(String), XtOffset(AppDataPtr, premoveHighlightColor),\r
776         XtRString, PREMOVE_HIGHLIGHT_COLOR },\r
777     { "movesPerSession", "movesPerSession", XtRInt, sizeof(int),\r
778         XtOffset(AppDataPtr, movesPerSession), XtRImmediate,\r
779         (XtPointer) MOVES_PER_SESSION },\r
780     { "timeIncrement", "timeIncrement", XtRInt, sizeof(int),\r
781         XtOffset(AppDataPtr, timeIncrement), XtRImmediate,\r
782         (XtPointer) TIME_INCREMENT },\r
783     { "initString", "initString", XtRString, sizeof(String),\r
784         XtOffset(AppDataPtr, initString), XtRString, INIT_STRING },\r
785     { "secondInitString", "secondInitString", XtRString, sizeof(String),\r
786         XtOffset(AppDataPtr, secondInitString), XtRString, INIT_STRING },\r
787     { "firstComputerString", "firstComputerString", XtRString,\r
788         sizeof(String), XtOffset(AppDataPtr, firstComputerString), XtRString,\r
789       COMPUTER_STRING },\r
790     { "secondComputerString", "secondComputerString", XtRString,\r
791         sizeof(String), XtOffset(AppDataPtr, secondComputerString), XtRString,\r
792       COMPUTER_STRING },\r
793     { "firstChessProgram", "firstChessProgram", XtRString,\r
794         sizeof(String), XtOffset(AppDataPtr, firstChessProgram),\r
795         XtRString, FIRST_CHESS_PROGRAM },\r
796     { "secondChessProgram", "secondChessProgram", XtRString,\r
797         sizeof(String), XtOffset(AppDataPtr, secondChessProgram),\r
798         XtRString, SECOND_CHESS_PROGRAM },\r
799     { "firstPlaysBlack", "firstPlaysBlack", XtRBoolean,\r
800         sizeof(Boolean), XtOffset(AppDataPtr, firstPlaysBlack),\r
801         XtRImmediate, (XtPointer) False },\r
802     { "noChessProgram", "noChessProgram", XtRBoolean,\r
803         sizeof(Boolean), XtOffset(AppDataPtr, noChessProgram),\r
804         XtRImmediate, (XtPointer) False },\r
805     { "firstHost", "firstHost", XtRString, sizeof(String),\r
806         XtOffset(AppDataPtr, firstHost), XtRString, FIRST_HOST },\r
807     { "secondHost", "secondHost", XtRString, sizeof(String),\r
808         XtOffset(AppDataPtr, secondHost), XtRString, SECOND_HOST },\r
809     { "firstDirectory", "firstDirectory", XtRString, sizeof(String),\r
810         XtOffset(AppDataPtr, firstDirectory), XtRString, "." },\r
811     { "secondDirectory", "secondDirectory", XtRString, sizeof(String),\r
812         XtOffset(AppDataPtr, secondDirectory), XtRString, "." },\r
813     { "bitmapDirectory", "bitmapDirectory", XtRString,\r
814         sizeof(String), XtOffset(AppDataPtr, bitmapDirectory),\r
815         XtRString, "" },\r
816     { "remoteShell", "remoteShell", XtRString, sizeof(String),\r
817         XtOffset(AppDataPtr, remoteShell), XtRString, REMOTE_SHELL },\r
818     { "remoteUser", "remoteUser", XtRString, sizeof(String),\r
819         XtOffset(AppDataPtr, remoteUser), XtRString, "" },\r
820     { "timeDelay", "timeDelay", XtRFloat, sizeof(float),\r
821         XtOffset(AppDataPtr, timeDelay), XtRString,\r
822         (XtPointer) TIME_DELAY_QUOTE },\r
823     { "timeControl", "timeControl", XtRString, sizeof(String),\r
824         XtOffset(AppDataPtr, timeControl), XtRString,\r
825         (XtPointer) TIME_CONTROL },\r
826     { "internetChessServerMode", "internetChessServerMode",\r
827         XtRBoolean, sizeof(Boolean),\r
828         XtOffset(AppDataPtr, icsActive), XtRImmediate,\r
829         (XtPointer) False },\r
830     { "internetChessServerHost", "internetChessServerHost",\r
831         XtRString, sizeof(String),\r
832         XtOffset(AppDataPtr, icsHost),\r
833         XtRString, (XtPointer) ICS_HOST },\r
834     { "internetChessServerPort", "internetChessServerPort",\r
835         XtRString, sizeof(String),\r
836         XtOffset(AppDataPtr, icsPort), XtRString,\r
837         (XtPointer) ICS_PORT },\r
838     { "internetChessServerCommPort", "internetChessServerCommPort",\r
839         XtRString, sizeof(String),\r
840         XtOffset(AppDataPtr, icsCommPort), XtRString,\r
841         ICS_COMM_PORT },\r
842     { "internetChessServerLogonScript", "internetChessServerLogonScript",\r
843         XtRString, sizeof(String),\r
844         XtOffset(AppDataPtr, icsLogon), XtRString,\r
845         ICS_LOGON },\r
846     { "internetChessServerHelper", "internetChessServerHelper",\r
847         XtRString, sizeof(String),\r
848         XtOffset(AppDataPtr, icsHelper), XtRString, "" },\r
849     { "internetChessServerInputBox", "internetChessServerInputBox",\r
850         XtRBoolean, sizeof(Boolean),\r
851         XtOffset(AppDataPtr, icsInputBox), XtRImmediate,\r
852         (XtPointer) False },\r
853     { "icsAlarm", "icsAlarm",\r
854         XtRBoolean, sizeof(Boolean),\r
855         XtOffset(AppDataPtr, icsAlarm), XtRImmediate,\r
856         (XtPointer) True },\r
857     { "icsAlarmTime", "icsAlarmTime",\r
858         XtRInt, sizeof(int),\r
859         XtOffset(AppDataPtr, icsAlarmTime), XtRImmediate,\r
860         (XtPointer) 5000 },\r
861     { "useTelnet", "useTelnet", XtRBoolean, sizeof(Boolean),\r
862         XtOffset(AppDataPtr, useTelnet), XtRImmediate,\r
863         (XtPointer) False },\r
864     { "telnetProgram", "telnetProgram", XtRString, sizeof(String),\r
865         XtOffset(AppDataPtr, telnetProgram), XtRString, TELNET_PROGRAM },\r
866     { "gateway", "gateway", XtRString, sizeof(String),\r
867         XtOffset(AppDataPtr, gateway), XtRString, "" },\r
868     { "loadGameFile", "loadGameFile", XtRString, sizeof(String),\r
869         XtOffset(AppDataPtr, loadGameFile), XtRString, "" },\r
870     { "loadGameIndex", "loadGameIndex",\r
871         XtRInt, sizeof(int),\r
872         XtOffset(AppDataPtr, loadGameIndex), XtRImmediate,\r
873         (XtPointer) 0 },\r
874     { "saveGameFile", "saveGameFile", XtRString, sizeof(String),\r
875         XtOffset(AppDataPtr, saveGameFile), XtRString, "" },\r
876     { "autoRaiseBoard", "autoRaiseBoard", XtRBoolean,\r
877         sizeof(Boolean), XtOffset(AppDataPtr, autoRaiseBoard),\r
878         XtRImmediate, (XtPointer) True },\r
879     { "autoSaveGames", "autoSaveGames", XtRBoolean,\r
880         sizeof(Boolean), XtOffset(AppDataPtr, autoSaveGames),\r
881         XtRImmediate, (XtPointer) False },\r
882     { "blindfold", "blindfold", XtRBoolean,\r
883         sizeof(Boolean), XtOffset(AppDataPtr, blindfold),\r
884         XtRImmediate, (XtPointer) False },\r
885     { "loadPositionFile", "loadPositionFile", XtRString,\r
886         sizeof(String), XtOffset(AppDataPtr, loadPositionFile),\r
887         XtRString, "" },\r
888     { "loadPositionIndex", "loadPositionIndex",\r
889         XtRInt, sizeof(int),\r
890         XtOffset(AppDataPtr, loadPositionIndex), XtRImmediate,\r
891         (XtPointer) 1 },\r
892     { "savePositionFile", "savePositionFile", XtRString,\r
893         sizeof(String), XtOffset(AppDataPtr, savePositionFile),\r
894         XtRString, "" },\r
895     { "matchMode", "matchMode", XtRBoolean, sizeof(Boolean),\r
896         XtOffset(AppDataPtr, matchMode), XtRImmediate, (XtPointer) False },\r
897     { "matchGames", "matchGames", XtRInt, sizeof(int),\r
898         XtOffset(AppDataPtr, matchGames), XtRImmediate,\r
899         (XtPointer) 0 },\r
900     { "monoMode", "monoMode", XtRBoolean, sizeof(Boolean),\r
901         XtOffset(AppDataPtr, monoMode), XtRImmediate,\r
902         (XtPointer) False },\r
903     { "debugMode", "debugMode", XtRBoolean, sizeof(Boolean),\r
904         XtOffset(AppDataPtr, debugMode), XtRImmediate,\r
905         (XtPointer) False },\r
906     { "clockMode", "clockMode", XtRBoolean, sizeof(Boolean),\r
907         XtOffset(AppDataPtr, clockMode), XtRImmediate,\r
908         (XtPointer) True },\r
909     { "boardSize", "boardSize", XtRString, sizeof(String),\r
910         XtOffset(AppDataPtr, boardSize), XtRString, "" },\r
911     { "searchTime", "searchTime", XtRString, sizeof(String),\r
912         XtOffset(AppDataPtr, searchTime), XtRString,\r
913         (XtPointer) "" },\r
914     { "searchDepth", "searchDepth", XtRInt, sizeof(int),\r
915         XtOffset(AppDataPtr, searchDepth), XtRImmediate, \r
916         (XtPointer) 0 },\r
917     { "showCoords", "showCoords", XtRBoolean, sizeof(Boolean),\r
918         XtOffset(AppDataPtr, showCoords), XtRImmediate,\r
919         (XtPointer) False },\r
920     { "showJail", "showJail", XtRInt, sizeof(int),\r
921         XtOffset(AppDataPtr, showJail), XtRImmediate,\r
922         (XtPointer) 0 },\r
923     { "showThinking", "showThinking", XtRBoolean, sizeof(Boolean),\r
924         XtOffset(AppDataPtr, showThinking), XtRImmediate,\r
925         (XtPointer) True },\r
926     { "ponderNextMove", "ponderNextMove", XtRBoolean, sizeof(Boolean),\r
927         XtOffset(AppDataPtr, ponderNextMove), XtRImmediate,\r
928         (XtPointer) True },\r
929     { "periodicUpdates", "periodicUpdates", XtRBoolean, sizeof(Boolean),\r
930         XtOffset(AppDataPtr, periodicUpdates), XtRImmediate,\r
931         (XtPointer) True },\r
932     { "clockFont", "clockFont", XtRString, sizeof(String),\r
933         XtOffset(AppDataPtr, clockFont), XtRString, CLOCK_FONT },\r
934     { "coordFont", "coordFont", XtRString, sizeof(String),\r
935         XtOffset(AppDataPtr, coordFont), XtRString, COORD_FONT },\r
936     { "font", "font", XtRString, sizeof(String),\r
937         XtOffset(AppDataPtr, font), XtRString, DEFAULT_FONT },\r
938     { "ringBellAfterMoves", "ringBellAfterMoves",\r
939         XtRBoolean, sizeof(Boolean),\r
940         XtOffset(AppDataPtr, ringBellAfterMoves),\r
941         XtRImmediate, (XtPointer) False },\r
942     { "autoCallFlag", "autoCallFlag", XtRBoolean,\r
943         sizeof(Boolean), XtOffset(AppDataPtr, autoCallFlag),\r
944         XtRImmediate, (XtPointer) False },\r
945     { "autoFlipView", "autoFlipView", XtRBoolean,\r
946         sizeof(Boolean), XtOffset(AppDataPtr, autoFlipView),\r
947         XtRImmediate, (XtPointer) True },\r
948     { "autoObserve", "autoObserve", XtRBoolean,\r
949         sizeof(Boolean), XtOffset(AppDataPtr, autoObserve),\r
950         XtRImmediate, (XtPointer) False },\r
951     { "autoComment", "autoComment", XtRBoolean,\r
952         sizeof(Boolean), XtOffset(AppDataPtr, autoComment),\r
953         XtRImmediate, (XtPointer) False },\r
954     { "getMoveList", "getMoveList", XtRBoolean,\r
955         sizeof(Boolean), XtOffset(AppDataPtr, getMoveList),\r
956         XtRImmediate, (XtPointer) True },\r
957 #if HIGHDRAG\r
958     { "highlightDragging", "highlightDragging", XtRBoolean,\r
959         sizeof(Boolean), XtOffset(AppDataPtr, highlightDragging),\r
960         XtRImmediate, (XtPointer) False },\r
961 #endif\r
962     { "highlightLastMove", "highlightLastMove", XtRBoolean,\r
963         sizeof(Boolean), XtOffset(AppDataPtr, highlightLastMove),\r
964         XtRImmediate, (XtPointer) False },\r
965     { "premove", "premove", XtRBoolean,\r
966         sizeof(Boolean), XtOffset(AppDataPtr, premove),\r
967         XtRImmediate, (XtPointer) True },\r
968     { "testLegality", "testLegality", XtRBoolean,\r
969         sizeof(Boolean), XtOffset(AppDataPtr, testLegality),\r
970         XtRImmediate, (XtPointer) True },\r
971     { "flipView", "flipView", XtRBoolean,\r
972         sizeof(Boolean), XtOffset(AppDataPtr, flipView),\r
973         XtRImmediate, (XtPointer) False },\r
974     { "cmail", "cmailGameName", XtRString, sizeof(String),\r
975         XtOffset(AppDataPtr, cmailGameName), XtRString, "" },\r
976     { "alwaysPromoteToQueen", "alwaysPromoteToQueen", XtRBoolean,\r
977         sizeof(Boolean), XtOffset(AppDataPtr, alwaysPromoteToQueen),\r
978         XtRImmediate, (XtPointer) False },\r
979     { "oldSaveStyle", "oldSaveStyle", XtRBoolean,\r
980         sizeof(Boolean), XtOffset(AppDataPtr, oldSaveStyle),\r
981         XtRImmediate, (XtPointer) False },\r
982     { "quietPlay", "quietPlay", XtRBoolean,\r
983         sizeof(Boolean), XtOffset(AppDataPtr, quietPlay),\r
984         XtRImmediate, (XtPointer) False },\r
985     { "titleInWindow", "titleInWindow", XtRBoolean,\r
986         sizeof(Boolean), XtOffset(AppDataPtr, titleInWindow),\r
987         XtRImmediate, (XtPointer) False },\r
988     { "localLineEditing", "localLineEditing", XtRBoolean,\r
989         sizeof(Boolean), XtOffset(AppDataPtr, localLineEditing),\r
990         XtRImmediate, (XtPointer) True }, /* not implemented, must be True */\r
991 #ifdef ZIPPY\r
992     { "zippyTalk", "zippyTalk", XtRBoolean,\r
993         sizeof(Boolean), XtOffset(AppDataPtr, zippyTalk),\r
994         XtRImmediate, (XtPointer) ZIPPY_TALK },\r
995     { "zippyPlay", "zippyPlay", XtRBoolean,\r
996         sizeof(Boolean), XtOffset(AppDataPtr, zippyPlay),\r
997         XtRImmediate, (XtPointer) ZIPPY_PLAY },\r
998     { "zippyLines", "zippyLines", XtRString, sizeof(String),\r
999         XtOffset(AppDataPtr, zippyLines), XtRString, ZIPPY_LINES },\r
1000     { "zippyPinhead", "zippyPinhead", XtRString, sizeof(String),\r
1001         XtOffset(AppDataPtr, zippyPinhead), XtRString, ZIPPY_PINHEAD },\r
1002     { "zippyPassword", "zippyPassword", XtRString, sizeof(String),\r
1003         XtOffset(AppDataPtr, zippyPassword), XtRString, ZIPPY_PASSWORD },\r
1004     { "zippyPassword2", "zippyPassword2", XtRString, sizeof(String),\r
1005         XtOffset(AppDataPtr, zippyPassword2), XtRString, ZIPPY_PASSWORD2 },\r
1006     { "zippyWrongPassword", "zippyWrongPassword", XtRString, sizeof(String),\r
1007         XtOffset(AppDataPtr, zippyWrongPassword), XtRString,\r
1008         ZIPPY_WRONG_PASSWORD },\r
1009     { "zippyAcceptOnly", "zippyAcceptOnly", XtRString, sizeof(String),\r
1010         XtOffset(AppDataPtr, zippyAcceptOnly), XtRString, ZIPPY_ACCEPT_ONLY },\r
1011     { "zippyUseI", "zippyUseI", XtRBoolean,\r
1012         sizeof(Boolean), XtOffset(AppDataPtr, zippyUseI),\r
1013         XtRImmediate, (XtPointer) ZIPPY_USE_I },\r
1014     { "zippyBughouse", "zippyBughouse", XtRInt,\r
1015         sizeof(int), XtOffset(AppDataPtr, zippyBughouse),\r
1016         XtRImmediate, (XtPointer) ZIPPY_BUGHOUSE },\r
1017     { "zippyNoplayCrafty", "zippyNoplayCrafty", XtRBoolean,\r
1018         sizeof(Boolean), XtOffset(AppDataPtr, zippyNoplayCrafty),\r
1019         XtRImmediate, (XtPointer) ZIPPY_NOPLAY_CRAFTY },\r
1020     { "zippyGameEnd", "zippyGameEnd", XtRString, sizeof(String),\r
1021         XtOffset(AppDataPtr, zippyGameEnd), XtRString, ZIPPY_GAME_END },\r
1022     { "zippyGameStart", "zippyGameStart", XtRString, sizeof(String),\r
1023         XtOffset(AppDataPtr, zippyGameStart), XtRString, ZIPPY_GAME_START },\r
1024     { "zippyAdjourn", "zippyAdjourn", XtRBoolean,\r
1025         sizeof(Boolean), XtOffset(AppDataPtr, zippyAdjourn),\r
1026         XtRImmediate, (XtPointer) ZIPPY_ADJOURN },\r
1027     { "zippyAbort", "zippyAbort", XtRBoolean,\r
1028         sizeof(Boolean), XtOffset(AppDataPtr, zippyAbort),\r
1029         XtRImmediate, (XtPointer) ZIPPY_ABORT },\r
1030     { "zippyVariants", "zippyVariants", XtRString, sizeof(String),\r
1031         XtOffset(AppDataPtr, zippyVariants), XtRString, ZIPPY_VARIANTS },\r
1032     { "zippyMaxGames", "zippyMaxGames", XtRInt, sizeof(int),\r
1033         XtOffset(AppDataPtr, zippyMaxGames), XtRImmediate,\r
1034         (XtPointer) ZIPPY_MAX_GAMES },\r
1035     { "zippyReplayTimeout", "zippyReplayTimeout", XtRInt, sizeof(int),\r
1036         XtOffset(AppDataPtr, zippyReplayTimeout), XtRImmediate,\r
1037         (XtPointer) ZIPPY_REPLAY_TIMEOUT },\r
1038 #endif\r
1039     { "flashCount", "flashCount", XtRInt, sizeof(int),\r
1040         XtOffset(AppDataPtr, flashCount), XtRImmediate,\r
1041         (XtPointer) FLASH_COUNT  },\r
1042     { "flashRate", "flashRate", XtRInt, sizeof(int),\r
1043         XtOffset(AppDataPtr, flashRate), XtRImmediate,\r
1044         (XtPointer) FLASH_RATE },\r
1045     { "pixmapDirectory", "pixmapDirectory", XtRString,\r
1046         sizeof(String), XtOffset(AppDataPtr, pixmapDirectory),\r
1047         XtRString, "" },\r
1048     { "msLoginDelay", "msLoginDelay", XtRInt, sizeof(int),\r
1049         XtOffset(AppDataPtr, msLoginDelay), XtRImmediate,\r
1050         (XtPointer) MS_LOGIN_DELAY },\r
1051     { "colorizeMessages", "colorizeMessages", XtRBoolean,\r
1052         sizeof(Boolean), XtOffset(AppDataPtr, colorize),\r
1053         XtRImmediate, (XtPointer) False },      \r
1054     { "colorShout", "colorShout", XtRString,\r
1055         sizeof(String), XtOffset(AppDataPtr, colorShout),\r
1056         XtRString, COLOR_SHOUT },\r
1057     { "colorSShout", "colorSShout", XtRString,\r
1058         sizeof(String), XtOffset(AppDataPtr, colorSShout),\r
1059         XtRString, COLOR_SSHOUT },\r
1060     { "colorChannel1", "colorChannel1", XtRString,\r
1061         sizeof(String), XtOffset(AppDataPtr, colorChannel1),\r
1062         XtRString, COLOR_CHANNEL1 },\r
1063     { "colorChannel", "colorChannel", XtRString,\r
1064         sizeof(String), XtOffset(AppDataPtr, colorChannel),\r
1065         XtRString, COLOR_CHANNEL },\r
1066     { "colorKibitz", "colorKibitz", XtRString,\r
1067         sizeof(String), XtOffset(AppDataPtr, colorKibitz),\r
1068         XtRString, COLOR_KIBITZ },\r
1069     { "colorTell", "colorTell", XtRString,\r
1070         sizeof(String), XtOffset(AppDataPtr, colorTell),\r
1071         XtRString, COLOR_TELL },\r
1072     { "colorChallenge", "colorChallenge", XtRString,\r
1073         sizeof(String), XtOffset(AppDataPtr, colorChallenge),\r
1074         XtRString, COLOR_CHALLENGE },\r
1075     { "colorRequest", "colorRequest", XtRString,\r
1076         sizeof(String), XtOffset(AppDataPtr, colorRequest),\r
1077         XtRString, COLOR_REQUEST },\r
1078     { "colorSeek", "colorSeek", XtRString,\r
1079         sizeof(String), XtOffset(AppDataPtr, colorSeek),\r
1080         XtRString, COLOR_SEEK },\r
1081     { "colorNormal", "colorNormal", XtRString,\r
1082         sizeof(String), XtOffset(AppDataPtr, colorNormal),\r
1083         XtRString, COLOR_NORMAL },      \r
1084     { "soundProgram", "soundProgram", XtRString,\r
1085       sizeof(String), XtOffset(AppDataPtr, soundProgram),\r
1086       XtRString, "play" },\r
1087     { "soundShout", "soundShout", XtRString,\r
1088       sizeof(String), XtOffset(AppDataPtr, soundShout),\r
1089       XtRString, "" },\r
1090     { "soundSShout", "soundSShout", XtRString,\r
1091       sizeof(String), XtOffset(AppDataPtr, soundSShout),\r
1092       XtRString, "" },\r
1093     { "soundChannel1", "soundChannel1", XtRString,\r
1094       sizeof(String), XtOffset(AppDataPtr, soundChannel1),\r
1095       XtRString, "" },\r
1096     { "soundChannel", "soundChannel", XtRString,\r
1097       sizeof(String), XtOffset(AppDataPtr, soundChannel),\r
1098       XtRString, "" },\r
1099     { "soundKibitz", "soundKibitz", XtRString,\r
1100       sizeof(String), XtOffset(AppDataPtr, soundKibitz),\r
1101       XtRString, "" },\r
1102     { "soundTell", "soundTell", XtRString,\r
1103       sizeof(String), XtOffset(AppDataPtr, soundTell),\r
1104       XtRString, "" },\r
1105     { "soundChallenge", "soundChallenge", XtRString,\r
1106       sizeof(String), XtOffset(AppDataPtr, soundChallenge),\r
1107       XtRString, "" },\r
1108     { "soundRequest", "soundRequest", XtRString,\r
1109       sizeof(String), XtOffset(AppDataPtr, soundRequest),\r
1110       XtRString, "" },\r
1111     { "soundSeek", "soundSeek", XtRString,\r
1112       sizeof(String), XtOffset(AppDataPtr, soundSeek),\r
1113       XtRString, "" },\r
1114     { "soundMove", "soundMove", XtRString,\r
1115       sizeof(String), XtOffset(AppDataPtr, soundMove),\r
1116       XtRString, "$" },\r
1117     { "soundIcsWin", "soundIcsWin", XtRString,\r
1118       sizeof(String), XtOffset(AppDataPtr, soundIcsWin),\r
1119       XtRString, "" },\r
1120     { "soundIcsLoss", "soundIcsLoss", XtRString,\r
1121       sizeof(String), XtOffset(AppDataPtr, soundIcsLoss),\r
1122       XtRString, "" },\r
1123     { "soundIcsDraw", "soundIcsDraw", XtRString,\r
1124       sizeof(String), XtOffset(AppDataPtr, soundIcsDraw),\r
1125       XtRString, "" },\r
1126     { "soundIcsUnfinished", "soundIcsUnfinished", XtRString,\r
1127       sizeof(String), XtOffset(AppDataPtr, soundIcsUnfinished),\r
1128       XtRString, "" },\r
1129     { "soundIcsAlarm", "soundIcsAlarm", XtRString,\r
1130       sizeof(String), XtOffset(AppDataPtr, soundIcsAlarm),\r
1131       XtRString, "$" },\r
1132     { "reuseFirst", "reuseFirst", XtRBoolean,\r
1133         sizeof(Boolean), XtOffset(AppDataPtr, reuseFirst),\r
1134         XtRImmediate, (XtPointer) True },\r
1135     { "reuseSecond", "reuseSecond", XtRBoolean,\r
1136         sizeof(Boolean), XtOffset(AppDataPtr, reuseSecond),\r
1137         XtRImmediate, (XtPointer) True },\r
1138     { "animateDragging", "animateDragging", XtRBoolean,\r
1139         sizeof(Boolean), XtOffset(AppDataPtr, animateDragging),\r
1140         XtRImmediate, (XtPointer) True },\r
1141     { "animateMoving", "animateMoving", XtRBoolean,\r
1142         sizeof(Boolean), XtOffset(AppDataPtr, animate),\r
1143         XtRImmediate, (XtPointer) True },\r
1144     { "animateSpeed", "animateSpeed", XtRInt,\r
1145         sizeof(int), XtOffset(AppDataPtr, animSpeed),\r
1146         XtRImmediate, (XtPointer)10 },\r
1147     { "popupExitMessage", "popupExitMessage", XtRBoolean,\r
1148         sizeof(Boolean), XtOffset(AppDataPtr, popupExitMessage),\r
1149         XtRImmediate, (XtPointer) True },\r
1150     { "popupMoveErrors", "popupMoveErrors", XtRBoolean,\r
1151         sizeof(Boolean), XtOffset(AppDataPtr, popupMoveErrors),\r
1152         XtRImmediate, (XtPointer) False },\r
1153     { "fontSizeTolerance", "fontSizeTolerance", XtRInt,\r
1154         sizeof(int), XtOffset(AppDataPtr, fontSizeTolerance),\r
1155         XtRImmediate, (XtPointer)4 },\r
1156     { "initialMode", "initialMode", XtRString,\r
1157         sizeof(String), XtOffset(AppDataPtr, initialMode),\r
1158         XtRImmediate, (XtPointer) "" },\r
1159     { "variant", "variant", XtRString,\r
1160         sizeof(String), XtOffset(AppDataPtr, variant),\r
1161         XtRImmediate, (XtPointer) "normal" },\r
1162     { "firstProtocolVersion", "firstProtocolVersion", XtRInt,\r
1163         sizeof(int), XtOffset(AppDataPtr, firstProtocolVersion),\r
1164         XtRImmediate, (XtPointer)PROTOVER },\r
1165     { "secondProtocolVersion", "secondProtocolVersion", XtRInt,\r
1166         sizeof(int), XtOffset(AppDataPtr, secondProtocolVersion),\r
1167         XtRImmediate, (XtPointer)PROTOVER },\r
1168     { "showButtonBar", "showButtonBar", XtRBoolean,\r
1169         sizeof(Boolean), XtOffset(AppDataPtr, showButtonBar),\r
1170         XtRImmediate, (XtPointer) True },\r
1171     { "firstScoreAbs", "firstScoreAbs", XtRBoolean,\r
1172         sizeof(Boolean), XtOffset(AppDataPtr, firstScoreIsAbsolute),\r
1173         XtRImmediate, (XtPointer) False },\r
1174     { "secondScoreAbs", "secondScoreAbs", XtRBoolean,\r
1175         sizeof(Boolean), XtOffset(AppDataPtr, secondScoreIsAbsolute),\r
1176         XtRImmediate, (XtPointer) False },\r
1177     { "pgnExtendedInfo", "pgnExtendedInfo", XtRBoolean,\r
1178         sizeof(Boolean), XtOffset(AppDataPtr, saveExtendedInfoInPGN),\r
1179         XtRImmediate, (XtPointer) False },\r
1180     { "hideThinkingFromHuman", "hideThinkingFromHuman", XtRBoolean,\r
1181         sizeof(Boolean), XtOffset(AppDataPtr, hideThinkingFromHuman),\r
1182         XtRImmediate, (XtPointer) True },\r
1183     { "adjudicateLossThreshold", "adjudicateLossThreshold", XtRInt,\r
1184         sizeof(int), XtOffset(AppDataPtr, adjudicateLossThreshold),\r
1185         XtRImmediate, (XtPointer) 0},\r
1186     { "pgnEventHeader", "pgnEventHeader", XtRString,\r
1187         sizeof(String), XtOffset(AppDataPtr, pgnEventHeader),\r
1188         XtRImmediate, (XtPointer) "Computer Chess Game" },    \r
1189     { "defaultFrcPosition", "defaultFrcPositon", XtRInt,\r
1190         sizeof(int), XtOffset(AppDataPtr, defaultFrcPosition),\r
1191         XtRImmediate, (XtPointer) -1},\r
1192 \r
1193     // [HGM] 4.3.xx options\r
1194     { "boardWidth", "boardWidth", XtRInt,\r
1195         sizeof(int), XtOffset(AppDataPtr, NrFiles),\r
1196         XtRImmediate, (XtPointer) -1},\r
1197     { "boardHeight", "boardHeight", XtRInt,\r
1198         sizeof(int), XtOffset(AppDataPtr, NrRanks),\r
1199         XtRImmediate, (XtPointer) -1},\r
1200     { "matchPause", "matchPause", XtRInt,\r
1201         sizeof(int), XtOffset(AppDataPtr, matchPause),\r
1202         XtRImmediate, (XtPointer) 10000},\r
1203     { "holdingsSize", "holdingsSize", XtRInt,\r
1204         sizeof(int), XtOffset(AppDataPtr, holdingsSize),\r
1205         XtRImmediate, (XtPointer) -1},\r
1206     { "flipBlack", "flipBlack", XtRBoolean,\r
1207         sizeof(Boolean), XtOffset(AppDataPtr, upsideDown),\r
1208         XtRImmediate, (XtPointer) False},\r
1209     { "allWhite", "allWhite", XtRBoolean,\r
1210         sizeof(Boolean), XtOffset(AppDataPtr, allWhite),\r
1211         XtRImmediate, (XtPointer) False},\r
1212     { "pieceToCharTable", "pieceToCharTable", XtRString,\r
1213         sizeof(String), XtOffset(AppDataPtr, pieceToCharTable),\r
1214         XtRImmediate, (XtPointer) 0},\r
1215     { "alphaRank", "alphaRank", XtRBoolean,\r
1216         sizeof(Boolean), XtOffset(AppDataPtr, alphaRank),\r
1217         XtRImmediate, (XtPointer) False},\r
1218     { "testClaims", "testClaims", XtRBoolean,\r
1219         sizeof(Boolean), XtOffset(AppDataPtr, testClaims),\r
1220         XtRImmediate, (XtPointer) True},\r
1221     { "checkMates", "checkMates", XtRBoolean,\r
1222         sizeof(Boolean), XtOffset(AppDataPtr, checkMates),\r
1223         XtRImmediate, (XtPointer) True},\r
1224     { "materialDraws", "materialDraws", XtRBoolean,\r
1225         sizeof(Boolean), XtOffset(AppDataPtr, materialDraws),\r
1226         XtRImmediate, (XtPointer) True},\r
1227     { "trivialDraws", "trivialDraws", XtRBoolean,\r
1228         sizeof(Boolean), XtOffset(AppDataPtr, trivialDraws),\r
1229         XtRImmediate, (XtPointer) False},\r
1230     { "ruleMoves", "ruleMoves", XtRInt,\r
1231         sizeof(int), XtOffset(AppDataPtr, ruleMoves),\r
1232         XtRImmediate, (XtPointer) 51},\r
1233     { "repeatsToDraw", "repeatsToDraw", XtRInt,\r
1234         sizeof(int), XtOffset(AppDataPtr, drawRepeats),\r
1235         XtRImmediate, (XtPointer) 6},\r
1236     { "engineDebugOutput", "engineDebugOutput", XtRInt,\r
1237         sizeof(int), XtOffset(AppDataPtr, engineComments),\r
1238         XtRImmediate, (XtPointer) 1},\r
1239     { "userName", "userName", XtRString,\r
1240         sizeof(int), XtOffset(AppDataPtr, userName),\r
1241         XtRImmediate, (XtPointer) 0},\r
1242     { "autoKibitz", "autoKibitz", XtRBoolean,\r
1243         sizeof(Boolean), XtOffset(AppDataPtr, autoKibitz),\r
1244         XtRImmediate, (XtPointer) False},\r
1245     { "firstTimeOdds", "firstTimeOdds", XtRInt,\r
1246         sizeof(int), XtOffset(AppDataPtr, firstTimeOdds),\r
1247         XtRImmediate, (XtPointer) 1},\r
1248     { "secondTimeOdds", "secondTimeOdds", XtRInt,\r
1249         sizeof(int), XtOffset(AppDataPtr, secondTimeOdds),\r
1250         XtRImmediate, (XtPointer) 1},\r
1251     { "timeOddsMode", "timeOddsMode", XtRInt,\r
1252         sizeof(int), XtOffset(AppDataPtr, timeOddsMode),\r
1253         XtRImmediate, (XtPointer) 0},\r
1254     { "firstAccumulateTC", "firstAccumulateTC", XtRInt,\r
1255         sizeof(int), XtOffset(AppDataPtr, firstAccumulateTC),\r
1256         XtRImmediate, (XtPointer) 1},\r
1257     { "secondAccumulateTC", "secondAccumulateTC", XtRInt,\r
1258         sizeof(int), XtOffset(AppDataPtr, secondAccumulateTC),\r
1259         XtRImmediate, (XtPointer) 1},\r
1260     { "firstNPS", "firstNPS", XtRInt,\r
1261         sizeof(int), XtOffset(AppDataPtr, firstNPS),\r
1262         XtRImmediate, (XtPointer) -1},\r
1263     { "secondNPS", "secondNPS", XtRInt,\r
1264         sizeof(int), XtOffset(AppDataPtr, secondNPS),\r
1265         XtRImmediate, (XtPointer) -1},\r
1266     { "serverMoves", "serverMoves", XtRString,\r
1267         sizeof(String), XtOffset(AppDataPtr, serverMovesName),\r
1268         XtRImmediate, (XtPointer) 0},\r
1269     { "serverPause", "serverPause", XtRInt,\r
1270         sizeof(int), XtOffset(AppDataPtr, serverPause),\r
1271         XtRImmediate, (XtPointer) 0},\r
1272     { "suppressLoadMoves", "suppressLoadMoves", XtRBoolean,\r
1273         sizeof(Boolean), XtOffset(AppDataPtr, suppressLoadMoves),\r
1274         XtRImmediate, (XtPointer) False},
1275     { "userName", "userName", XtRString,\r
1276         sizeof(String), XtOffset(AppDataPtr, userName),\r
1277         XtRImmediate, (XtPointer) 0},\r
1278     { "egtFormats", "egtFormats", XtRString,\r
1279         sizeof(String), XtOffset(AppDataPtr, egtFormats),\r
1280         XtRImmediate, (XtPointer) 0},\r
1281     { "rewindIndex", "rewindIndex", XtRInt,\r
1282         sizeof(int), XtOffset(AppDataPtr, rewindIndex),\r
1283         XtRImmediate, (XtPointer) 0},\r
1284     { "sameColorGames", "sameColorGames", XtRInt,\r
1285         sizeof(int), XtOffset(AppDataPtr, sameColorGames),\r
1286         XtRImmediate, (XtPointer) 0},\r
1287     { "smpCores", "smpCores", XtRInt,\r
1288         sizeof(int), XtOffset(AppDataPtr, smpCores),\r
1289         XtRImmediate, (XtPointer) 1},\r
1290
1291     // [HGM] Winboard_x UCI options\r
1292     { "firstIsUCI", "firstIsUCI", XtRBoolean,\r
1293         sizeof(Boolean), XtOffset(AppDataPtr, firstIsUCI),\r
1294         XtRImmediate, (XtPointer) False},\r
1295     { "secondIsUCI", "secondIsUCI", XtRBoolean,\r
1296         sizeof(Boolean), XtOffset(AppDataPtr, secondIsUCI),\r
1297         XtRImmediate, (XtPointer) False},\r
1298     { "firstHasOwnBookUCI", "firstHasOwnBookUCI", XtRBoolean,\r
1299         sizeof(Boolean), XtOffset(AppDataPtr, firstHasOwnBookUCI),\r
1300         XtRImmediate, (XtPointer) True},\r
1301     { "secondHasOwnBookUCI", "secondHasOwnBookUCI", XtRBoolean,\r
1302         sizeof(Boolean), XtOffset(AppDataPtr, secondHasOwnBookUCI),\r
1303         XtRImmediate, (XtPointer) True},\r
1304     { "usePolyglotBook", "usePolyglotBook", XtRBoolean,\r
1305         sizeof(Boolean), XtOffset(AppDataPtr, usePolyglotBook),\r
1306         XtRImmediate, (XtPointer) False},\r
1307     { "defaultHashSize", "defaultHashSize", XtRInt,\r
1308         sizeof(int), XtOffset(AppDataPtr, defaultHashSize),\r
1309         XtRImmediate, (XtPointer) 64},\r
1310     { "defaultCacheSizeEGTB", "defaultCacheSizeEGTB", XtRInt,\r
1311         sizeof(int), XtOffset(AppDataPtr, defaultCacheSizeEGTB),\r
1312         XtRImmediate, (XtPointer) 4},\r
1313     { "polyglotDir", "polyglotDir", XtRString,\r
1314         sizeof(String), XtOffset(AppDataPtr, polyglotDir),\r
1315         XtRImmediate, (XtPointer) "." },\r
1316     { "polyglotBook", "polyglotBook", XtRString,\r
1317         sizeof(String), XtOffset(AppDataPtr, polyglotBook),\r
1318         XtRImmediate, (XtPointer) "" },    \r
1319     { "defaultPathEGTB", "defaultPathEGTB", XtRString,\r
1320         sizeof(String), XtOffset(AppDataPtr, defaultPathEGTB),\r
1321         XtRImmediate, (XtPointer) "/usr/local/share/egtb"},\r
1322 };\r
1323 \r
1324 XrmOptionDescRec shellOptions[] = {\r
1325     { "-whitePieceColor", "whitePieceColor", XrmoptionSepArg, NULL },\r
1326     { "-blackPieceColor", "blackPieceColor", XrmoptionSepArg, NULL },\r
1327     { "-lightSquareColor", "lightSquareColor", XrmoptionSepArg, NULL },\r
1328     { "-darkSquareColor", "darkSquareColor", XrmoptionSepArg, NULL },\r
1329     { "-highlightSquareColor", "highlightSquareColor", XrmoptionSepArg, NULL },\r
1330     { "-premoveHighlightColor", "premoveHighlightColor", XrmoptionSepArg,NULL},\r
1331     { "-movesPerSession", "movesPerSession", XrmoptionSepArg, NULL },\r
1332     { "-mps", "movesPerSession", XrmoptionSepArg, NULL },\r
1333     { "-timeIncrement", "timeIncrement", XrmoptionSepArg, NULL },\r
1334     { "-inc", "timeIncrement", XrmoptionSepArg, NULL },\r
1335     { "-initString", "initString", XrmoptionSepArg, NULL },\r
1336     { "-firstInitString", "initString", XrmoptionSepArg, NULL },\r
1337     { "-secondInitString", "secondInitString", XrmoptionSepArg, NULL },\r
1338     { "-firstComputerString", "firstComputerString", XrmoptionSepArg, NULL },\r
1339     { "-secondComputerString", "secondComputerString", XrmoptionSepArg, NULL },\r
1340     { "-firstChessProgram", "firstChessProgram", XrmoptionSepArg, NULL },\r
1341     { "-fcp", "firstChessProgram", XrmoptionSepArg, NULL },\r
1342     { "-secondChessProgram", "secondChessProgram", XrmoptionSepArg, NULL },\r
1343     { "-scp", "secondChessProgram", XrmoptionSepArg, NULL },\r
1344     { "-firstPlaysBlack", "firstPlaysBlack", XrmoptionSepArg, NULL },\r
1345     { "-fb", "firstPlaysBlack", XrmoptionNoArg, "True" },\r
1346     { "-xfb", "firstPlaysBlack", XrmoptionNoArg, "False" },\r
1347     { "-noChessProgram", "noChessProgram", XrmoptionSepArg, NULL },\r
1348     { "-ncp", "noChessProgram", XrmoptionNoArg, "True" },\r
1349     { "-xncp", "noChessProgram", XrmoptionNoArg, "False" },\r
1350     { "-firstHost", "firstHost", XrmoptionSepArg, NULL },\r
1351     { "-fh", "firstHost", XrmoptionSepArg, NULL },\r
1352     { "-secondHost", "secondHost", XrmoptionSepArg, NULL },\r
1353     { "-sh", "secondHost", XrmoptionSepArg, NULL },\r
1354     { "-firstDirectory", "firstDirectory", XrmoptionSepArg, NULL },\r
1355     { "-fd", "firstDirectory", XrmoptionSepArg, NULL },\r
1356     { "-secondDirectory", "secondDirectory", XrmoptionSepArg, NULL },\r
1357     { "-sd", "secondDirectory", XrmoptionSepArg, NULL },\r
1358     { "-bitmapDirectory", "bitmapDirectory", XrmoptionSepArg, NULL },\r
1359     { "-bm", "bitmapDirectory", XrmoptionSepArg, NULL },\r
1360     { "-remoteShell", "remoteShell", XrmoptionSepArg, NULL },\r
1361     { "-rsh", "remoteShell", XrmoptionSepArg, NULL },\r
1362     { "-remoteUser", "remoteUser", XrmoptionSepArg, NULL },\r
1363     { "-ruser", "remoteUser", XrmoptionSepArg, NULL },\r
1364     { "-timeDelay", "timeDelay", XrmoptionSepArg, NULL },\r
1365     { "-td", "timeDelay", XrmoptionSepArg, NULL },\r
1366     { "-timeControl", "timeControl", XrmoptionSepArg, NULL },\r
1367     { "-tc", "timeControl", XrmoptionSepArg, NULL },\r
1368     { "-internetChessServerMode", "internetChessServerMode",\r
1369         XrmoptionSepArg, NULL },\r
1370     { "-ics", "internetChessServerMode", XrmoptionNoArg, "True" },\r
1371     { "-xics", "internetChessServerMode", XrmoptionNoArg, "False" },\r
1372     { "-internetChessServerHost", "internetChessServerHost",\r
1373         XrmoptionSepArg, NULL },\r
1374     { "-icshost", "internetChessServerHost", XrmoptionSepArg, NULL },\r
1375     { "-internetChessServerPort", "internetChessServerPort",\r
1376         XrmoptionSepArg, NULL },\r
1377     { "-icsport", "internetChessServerPort", XrmoptionSepArg, NULL },\r
1378     { "-internetChessServerCommPort", "internetChessServerCommPort",\r
1379         XrmoptionSepArg, NULL },\r
1380     { "-icscomm", "internetChessServerCommPort", XrmoptionSepArg, NULL },\r
1381     { "-internetChessServerLogonScript", "internetChessServerLogonScript",\r
1382         XrmoptionSepArg, NULL },\r
1383     { "-icslogon", "internetChessServerLogonScript", XrmoptionSepArg, NULL },\r
1384     { "-internetChessServerHelper", "internetChessServerHelper",\r
1385         XrmoptionSepArg, NULL },\r
1386     { "-icshelper", "internetChessServerHelper", XrmoptionSepArg, NULL },\r
1387     { "-internetChessServerInputBox", "internetChessServerInputBox",\r
1388         XrmoptionSepArg, NULL },\r
1389     { "-icsinput", "internetChessServerInputBox", XrmoptionNoArg, "True" },\r
1390     { "-xicsinput", "internetChessServerInputBox", XrmoptionNoArg, "False" },\r
1391     { "-icsAlarm", "icsAlarm", XrmoptionSepArg, NULL },\r
1392     { "-alarm", "icsAlarm", XrmoptionNoArg, "True" },\r
1393     { "-xalarm", "icsAlarm", XrmoptionNoArg, "False" },\r
1394     { "-icsAlarmTime", "icsAlarmTime", XrmoptionSepArg, NULL },\r
1395     { "-useTelnet", "useTelnet", XrmoptionSepArg, NULL },\r
1396     { "-telnet", "useTelnet", XrmoptionNoArg, "True" },\r
1397     { "-xtelnet", "useTelnet", XrmoptionNoArg, "False" },\r
1398     { "-telnetProgram", "telnetProgram", XrmoptionSepArg, NULL },\r
1399     { "-gateway", "gateway", XrmoptionSepArg, NULL },\r
1400     { "-loadGameFile", "loadGameFile", XrmoptionSepArg, NULL },\r
1401     { "-lgf", "loadGameFile", XrmoptionSepArg, NULL },\r
1402     { "-loadGameIndex", "loadGameIndex", XrmoptionSepArg, NULL },\r
1403     { "-lgi", "loadGameIndex", XrmoptionSepArg, NULL },\r
1404     { "-saveGameFile", "saveGameFile", XrmoptionSepArg, NULL },\r
1405     { "-sgf", "saveGameFile", XrmoptionSepArg, NULL },\r
1406     { "-autoSaveGames", "autoSaveGames", XrmoptionSepArg, NULL },\r
1407     { "-autosave", "autoSaveGames", XrmoptionNoArg, "True" },\r
1408     { "-xautosave", "autoSaveGames", XrmoptionNoArg, "False" },\r
1409     { "-autoRaiseBoard", "autoRaiseBoard", XrmoptionSepArg, NULL },\r
1410     { "-autoraise", "autoRaiseBoard", XrmoptionNoArg, "True" },\r
1411     { "-xautoraise", "autoRaiseBoard", XrmoptionNoArg, "False" },\r
1412     { "-blindfold", "blindfold", XrmoptionSepArg, NULL },\r
1413     { "-blind", "blindfold", XrmoptionNoArg, "True" },\r
1414     { "-xblind", "blindfold", XrmoptionNoArg, "False" },\r
1415     { "-loadPositionFile", "loadPositionFile", XrmoptionSepArg, NULL },\r
1416     { "-lpf", "loadPositionFile", XrmoptionSepArg, NULL },\r
1417     { "-loadPositionIndex", "loadPositionIndex", XrmoptionSepArg, NULL },\r
1418     { "-lpi", "loadPositionIndex", XrmoptionSepArg, NULL },\r
1419     { "-savePositionFile", "savePositionFile", XrmoptionSepArg, NULL },\r
1420     { "-spf", "savePositionFile", XrmoptionSepArg, NULL },\r
1421     { "-matchMode", "matchMode", XrmoptionSepArg, NULL },\r
1422     { "-mm", "matchMode", XrmoptionNoArg, "True" },\r
1423     { "-xmm", "matchMode", XrmoptionNoArg, "False" },\r
1424     { "-matchGames", "matchGames", XrmoptionSepArg, NULL },\r
1425     { "-mg", "matchGames", XrmoptionSepArg, NULL },\r
1426     { "-monoMode", "monoMode", XrmoptionSepArg, NULL },\r
1427     { "-mono", "monoMode", XrmoptionNoArg, "True" },\r
1428     { "-xmono", "monoMode", XrmoptionNoArg, "False" },\r
1429     { "-debugMode", "debugMode", XrmoptionSepArg, NULL },\r
1430     { "-debug", "debugMode", XrmoptionNoArg, "True" },\r
1431     { "-xdebug", "debugMode", XrmoptionNoArg, "False" },\r
1432     { "-clockMode", "clockMode", XrmoptionSepArg, NULL },\r
1433     { "-clock", "clockMode", XrmoptionNoArg, "True" },\r
1434     { "-xclock", "clockMode", XrmoptionNoArg, "False" },\r
1435     { "-boardSize", "boardSize", XrmoptionSepArg, NULL },\r
1436     { "-size", "boardSize", XrmoptionSepArg, NULL },\r
1437     { "-searchTime", "searchTime", XrmoptionSepArg, NULL },\r
1438     { "-st", "searchTime", XrmoptionSepArg, NULL },\r
1439     { "-searchDepth", "searchDepth", XrmoptionSepArg, NULL },\r
1440     { "-depth", "searchDepth", XrmoptionSepArg, NULL },\r
1441     { "-showCoords", "showCoords", XrmoptionSepArg, NULL },\r
1442     { "-coords", "showCoords", XrmoptionNoArg, "True" },\r
1443     { "-xcoords", "showCoords", XrmoptionNoArg, "False" },\r
1444 #if JAIL\r
1445     { "-showJail", "showJail", XrmoptionSepArg, NULL },\r
1446     { "-jail", "showJail", XrmoptionNoArg, "1" },\r
1447     { "-sidejail", "showJail", XrmoptionNoArg, "2" },\r
1448     { "-xjail", "showJail", XrmoptionNoArg, "0" },\r
1449 #endif\r
1450     { "-showThinking", "showThinking", XrmoptionSepArg, NULL },\r
1451     { "-thinking", "showThinking", XrmoptionNoArg, "True" },\r
1452     { "-xthinking", "showThinking", XrmoptionNoArg, "False" },\r
1453     { "-ponderNextMove", "ponderNextMove", XrmoptionSepArg, NULL },\r
1454     { "-ponder", "ponderNextMove", XrmoptionNoArg, "True" },\r
1455     { "-xponder", "ponderNextMove", XrmoptionNoArg, "False" },\r
1456     { "-periodicUpdates", "periodicUpdates", XrmoptionSepArg, NULL },\r
1457     { "-periodic", "periodicUpdates", XrmoptionNoArg, "True" },\r
1458     { "-xperiodic", "periodicUpdates", XrmoptionNoArg, "False" },\r
1459     { "-clockFont", "clockFont", XrmoptionSepArg, NULL },\r
1460     { "-coordFont", "coordFont", XrmoptionSepArg, NULL },\r
1461     { "-font", "font", XrmoptionSepArg, NULL },\r
1462     { "-ringBellAfterMoves", "ringBellAfterMoves", XrmoptionSepArg, NULL },\r
1463     { "-bell", "ringBellAfterMoves", XrmoptionNoArg, "True" },\r
1464     { "-xbell", "ringBellAfterMoves", XrmoptionNoArg, "False" },\r
1465     { "-movesound", "ringBellAfterMoves", XrmoptionNoArg, "True" },\r
1466     { "-xmovesound", "ringBellAfterMoves", XrmoptionNoArg, "False" },\r
1467     { "-autoCallFlag", "autoCallFlag", XrmoptionSepArg, NULL },\r
1468     { "-autoflag", "autoCallFlag", XrmoptionNoArg, "True" },\r
1469     { "-xautoflag", "autoCallFlag", XrmoptionNoArg, "False" },\r
1470     { "-autoFlipView", "autoFlipView", XrmoptionSepArg, NULL },\r
1471     { "-autoflip", "autoFlipView", XrmoptionNoArg, "True" },\r
1472     { "-xautoflip", "autoFlipView", XrmoptionNoArg, "False" },\r
1473     { "-autoObserve", "autoObserve", XrmoptionSepArg, NULL },\r
1474     { "-autobs", "autoObserve", XrmoptionNoArg, "True" },\r
1475     { "-xautobs", "autoObserve", XrmoptionNoArg, "False" },\r
1476     { "-autoComment", "autoComment", XrmoptionSepArg, NULL },\r
1477     { "-autocomm", "autoComment", XrmoptionNoArg, "True" },\r
1478     { "-xautocomm", "autoComment", XrmoptionNoArg, "False" },\r
1479     { "-getMoveList", "getMoveList", XrmoptionSepArg, NULL },\r
1480     { "-moves", "getMoveList", XrmoptionNoArg, "True" },\r
1481     { "-xmoves", "getMoveList", XrmoptionNoArg, "False" },\r
1482 #if HIGHDRAG\r
1483     { "-highlightDragging", "highlightDragging", XrmoptionSepArg, NULL },\r
1484     { "-highdrag", "highlightDragging", XrmoptionNoArg, "True" },\r
1485     { "-xhighdrag", "highlightDragging", XrmoptionNoArg, "False" },\r
1486 #endif\r
1487     { "-highlightLastMove", "highlightLastMove", XrmoptionSepArg, NULL },\r
1488     { "-highlight", "highlightLastMove", XrmoptionNoArg, "True" },\r
1489     { "-xhighlight", "highlightLastMove", XrmoptionNoArg, "False" },\r
1490     { "-premove", "premove", XrmoptionSepArg, NULL },\r
1491     { "-pre", "premove", XrmoptionNoArg, "True" },\r
1492     { "-xpre", "premove", XrmoptionNoArg, "False" },\r
1493     { "-testLegality", "testLegality", XrmoptionSepArg, NULL },\r
1494     { "-legal", "testLegality", XrmoptionNoArg, "True" },\r
1495     { "-xlegal", "testLegality", XrmoptionNoArg, "False" },\r
1496     { "-flipView", "flipView", XrmoptionSepArg, NULL },\r
1497     { "-flip", "flipView", XrmoptionNoArg, "True" },\r
1498     { "-xflip", "flipView", XrmoptionNoArg, "False" },\r
1499     { "-cmail", "cmailGameName", XrmoptionSepArg, NULL },\r
1500     { "-alwaysPromoteToQueen", "alwaysPromoteToQueen",\r
1501         XrmoptionSepArg, NULL },\r
1502     { "-queen", "alwaysPromoteToQueen", XrmoptionNoArg, "True" },\r
1503     { "-xqueen", "alwaysPromoteToQueen", XrmoptionNoArg, "False" },\r
1504     { "-oldSaveStyle", "oldSaveStyle", XrmoptionSepArg, NULL },\r
1505     { "-oldsave", "oldSaveStyle", XrmoptionNoArg, "True" },\r
1506     { "-xoldsave", "oldSaveStyle", XrmoptionNoArg, "False" },\r
1507     { "-quietPlay", "quietPlay", XrmoptionSepArg, NULL },\r
1508     { "-quiet", "quietPlay", XrmoptionNoArg, "True" },\r
1509     { "-xquiet", "quietPlay", XrmoptionNoArg, "False" },\r
1510     { "-titleInWindow", "titleInWindow", XrmoptionSepArg, NULL },\r
1511     { "-title", "titleInWindow", XrmoptionNoArg, "True" },\r
1512     { "-xtitle", "titleInWindow", XrmoptionNoArg, "False" },\r
1513 #ifdef ZIPPY\r
1514     { "-zippyTalk", "zippyTalk", XrmoptionSepArg, NULL },\r
1515     { "-zt", "zippyTalk", XrmoptionNoArg, "True" },\r
1516     { "-xzt", "zippyTalk", XrmoptionNoArg, "False" },\r
1517     { "-zippyPlay", "zippyPlay", XrmoptionSepArg, NULL },\r
1518     { "-zp", "zippyPlay", XrmoptionNoArg, "True" },\r
1519     { "-xzp", "zippyPlay", XrmoptionNoArg, "False" },\r
1520     { "-zippyLines", "zippyLines", XrmoptionSepArg, NULL },\r
1521     { "-zippyPinhead", "zippyPinhead", XrmoptionSepArg, NULL },\r
1522     { "-zippyPassword", "zippyPassword", XrmoptionSepArg, NULL },\r
1523     { "-zippyPassword2", "zippyPassword2", XrmoptionSepArg, NULL },\r
1524     { "-zippyWrongPassword", "zippyWrongPassword", XrmoptionSepArg, NULL },\r
1525     { "-zippyAcceptOnly", "zippyAcceptOnly", XrmoptionSepArg, NULL },\r
1526     { "-zippyUseI", "zippyUseI", XrmoptionSepArg, NULL },\r
1527     { "-zui", "zippyUseI", XrmoptionNoArg, "True" },\r
1528     { "-xzui", "zippyUseI", XrmoptionNoArg, "False" },\r
1529     { "-zippyBughouse", "zippyBughouse", XrmoptionSepArg, NULL },\r
1530     { "-zippyNoplayCrafty", "zippyNoplayCrafty", XrmoptionSepArg, NULL },\r
1531     { "-znc", "zippyNoplayCrafty", XrmoptionNoArg, "True" },\r
1532     { "-xznc", "zippyNoplayCrafty", XrmoptionNoArg, "False" },\r
1533     { "-zippyGameEnd", "zippyGameEnd", XrmoptionSepArg, NULL },\r
1534     { "-zippyGameStart", "zippyGameStart", XrmoptionSepArg, NULL },\r
1535     { "-zippyAdjourn", "zippyAdjourn", XrmoptionSepArg, NULL },\r
1536     { "-zadj", "zippyAdjourn", XrmoptionNoArg, "True" },\r
1537     { "-xzadj", "zippyAdjourn", XrmoptionNoArg, "False" },\r
1538     { "-zippyAbort", "zippyAbort", XrmoptionSepArg, NULL },\r
1539     { "-zab", "zippyAbort", XrmoptionNoArg, "True" },\r
1540     { "-xzab", "zippyAbort", XrmoptionNoArg, "False" },\r
1541     { "-zippyVariants", "zippyVariants", XrmoptionSepArg, NULL },\r
1542     { "-zippyMaxGames", "zippyMaxGames", XrmoptionSepArg, NULL },\r
1543     { "-zippyReplayTimeout", "zippyReplayTimeout", XrmoptionSepArg, NULL },\r
1544 #endif\r
1545     { "-flashCount", "flashCount", XrmoptionSepArg, NULL },\r
1546     { "-flash", "flashCount", XrmoptionNoArg, "3" },\r
1547     { "-xflash", "flashCount", XrmoptionNoArg, "0" },\r
1548     { "-flashRate", "flashRate", XrmoptionSepArg, NULL },\r
1549     { "-pixmapDirectory", "pixmapDirectory", XrmoptionSepArg, NULL },\r
1550     { "-msLoginDelay", "msLoginDelay", XrmoptionSepArg, NULL },\r
1551     { "-pixmap", "pixmapDirectory", XrmoptionSepArg, NULL },\r
1552     { "-colorizeMessages", "colorizeMessages", XrmoptionSepArg, NULL },\r
1553     { "-colorize", "colorizeMessages", XrmoptionNoArg, "True" },\r
1554     { "-xcolorize", "colorizeMessages", XrmoptionNoArg, "False" },\r
1555     { "-colorShout", "colorShout", XrmoptionSepArg, NULL },\r
1556     { "-colorSShout", "colorSShout", XrmoptionSepArg, NULL },\r
1557     { "-colorCShout", "colorSShout", XrmoptionSepArg, NULL }, /*FICS name*/\r
1558     { "-colorChannel1", "colorChannel1", XrmoptionSepArg, NULL },\r
1559     { "-colorChannel", "colorChannel", XrmoptionSepArg, NULL },\r
1560     { "-colorKibitz", "colorKibitz", XrmoptionSepArg, NULL },\r
1561     { "-colorTell", "colorTell", XrmoptionSepArg, NULL },\r
1562     { "-colorChallenge", "colorChallenge", XrmoptionSepArg, NULL },\r
1563     { "-colorRequest", "colorRequest", XrmoptionSepArg, NULL },\r
1564     { "-colorSeek", "colorSeek", XrmoptionSepArg, NULL },\r
1565     { "-colorNormal", "colorNormal", XrmoptionSepArg, NULL },\r
1566     { "-soundProgram", "soundProgram", XrmoptionSepArg, NULL },\r
1567     { "-soundShout", "soundShout", XrmoptionSepArg, NULL },\r
1568     { "-soundSShout", "soundSShout", XrmoptionSepArg, NULL },\r
1569     { "-soundCShout", "soundSShout", XrmoptionSepArg, NULL }, /*FICS name*/\r
1570     { "-soundChannel1", "soundChannel1", XrmoptionSepArg, NULL },\r
1571     { "-soundChannel", "soundChannel", XrmoptionSepArg, NULL },\r
1572     { "-soundKibitz", "soundKibitz", XrmoptionSepArg, NULL },\r
1573     { "-soundTell", "soundTell", XrmoptionSepArg, NULL },\r
1574     { "-soundChallenge", "soundChallenge", XrmoptionSepArg, NULL },\r
1575     { "-soundRequest", "soundRequest", XrmoptionSepArg, NULL },\r
1576     { "-soundSeek", "soundSeek", XrmoptionSepArg, NULL },\r
1577     { "-soundMove", "soundMove", XrmoptionSepArg, NULL },\r
1578     { "-soundIcsWin", "soundIcsWin", XrmoptionSepArg, NULL },\r
1579     { "-soundIcsLoss", "soundIcsLoss", XrmoptionSepArg, NULL },\r
1580     { "-soundIcsDraw", "soundIcsDraw", XrmoptionSepArg, NULL },\r
1581     { "-soundIcsUnfinished", "soundIcsUnfinished", XrmoptionSepArg, NULL },\r
1582     { "-soundIcsAlarm", "soundIcsAlarm", XrmoptionSepArg, NULL },\r
1583     { "-reuseFirst", "reuseFirst", XrmoptionSepArg, NULL },\r
1584     { "-reuseChessPrograms", "reuseFirst", XrmoptionSepArg, NULL }, /*compat*/\r
1585     { "-reuse", "reuseFirst", XrmoptionNoArg, "True" },\r
1586     { "-xreuse", "reuseFirst", XrmoptionNoArg, "False" },\r
1587     { "-reuseSecond", "reuseSecond", XrmoptionSepArg, NULL },\r
1588     { "-reuse2", "reuseSecond", XrmoptionNoArg, "True" },\r
1589     { "-xreuse2", "reuseSecond", XrmoptionNoArg, "False" },\r
1590     { "-animateMoving", "animateMoving", XrmoptionSepArg, NULL },\r
1591     { "-animate", "animateMoving", XrmoptionNoArg, "True" },\r
1592     { "-xanimate", "animateMoving", XrmoptionNoArg, "False" },\r
1593     { "-animateDragging", "animateDragging", XrmoptionSepArg, NULL },\r
1594     { "-drag", "animateDragging", XrmoptionNoArg, "True" },\r
1595     { "-xdrag", "animateDragging", XrmoptionNoArg, "False" },\r
1596     { "-animateSpeed", "animateSpeed", XrmoptionSepArg, NULL },\r
1597     { "-popupExitMessage", "popupExitMessage", XrmoptionSepArg, NULL },\r
1598     { "-exit", "popupExitMessage", XrmoptionNoArg, "True" },\r
1599     { "-xexit", "popupExitMessage", XrmoptionNoArg, "False" },\r
1600     { "-popupMoveErrors", "popupMoveErrors", XrmoptionSepArg, NULL },\r
1601     { "-popup", "popupMoveErrors", XrmoptionNoArg, "True" },\r
1602     { "-xpopup", "popupMoveErrors", XrmoptionNoArg, "False" },\r
1603     { "-fontSizeTolerance", "fontSizeTolerance", XrmoptionSepArg, NULL },\r
1604     { "-initialMode", "initialMode", XrmoptionSepArg, NULL },\r
1605     { "-mode", "initialMode", XrmoptionSepArg, NULL },\r
1606     { "-variant", "variant", XrmoptionSepArg, NULL },\r
1607     { "-firstProtocolVersion", "firstProtocolVersion", XrmoptionSepArg, NULL },\r
1608     { "-secondProtocolVersion","secondProtocolVersion",XrmoptionSepArg, NULL },\r
1609     { "-showButtonBar", "showButtonBar", XrmoptionSepArg, NULL },\r
1610     { "-buttons", "showButtonBar", XrmoptionNoArg, "True" },\r
1611     { "-xbuttons", "showButtonBar", XrmoptionNoArg, "False" },\r
1612     /* [AS,HR] New features */\r
1613     { "-firstScoreAbs", "firstScoreAbs", XrmoptionSepArg, NULL },\r
1614     { "-secondScoreAbs", "secondScoreAbs", XrmoptionSepArg, NULL },\r
1615     { "-pgnExtendedInfo", "pgnExtendedInfo", XrmoptionSepArg, NULL },\r
1616     { "-hideThinkingFromHuman", "hideThinkingFromHuman", XrmoptionSepArg, NULL },\r
1617     { "-adjudicateLossThreshold", "adjudicateLossThreshold", XrmoptionSepArg, NULL },\r
1618     { "-pgnEventHeader", "pgnEventHeader", XrmoptionSepArg, NULL },\r
1619     { "-firstIsUCI", "firstIsUCI", XrmoptionSepArg, NULL },\r
1620     { "-secondIsUCI", "secondIsUCI", XrmoptionSepArg, NULL },\r
1621     { "-fUCI", "firstIsUCI", XrmoptionNoArg, "True" },\r
1622     { "-sUCI", "secondIsUCI", XrmoptionNoArg, "True" },\r
1623     { "-firstHasOwnBookUCI", "firstHasOwnBookUCI", XrmoptionSepArg, NULL },\r
1624     { "-secondHasOwnBookUCI", "secondHasOwnBookUCI", XrmoptionSepArg, NULL },\r
1625     { "-fNoOwnBookUCI", "firstHasOwnBookUCI", XrmoptionNoArg, "False" },\r
1626     { "-sNoOwnBookUCI", "secondHasOwnBookUCI", XrmoptionNoArg, "False" },\r
1627     { "-polyglotDir", "polyglotDir", XrmoptionSepArg, NULL },\r
1628     { "-usePolyglotBook", "usePolyglotBook", XrmoptionSepArg, NULL },\r
1629     { "-polyglotBook", "polyglotBook", XrmoptionSepArg, NULL },\r
1630     { "-defaultHashSize", "defaultHashSize", XrmoptionSepArg, NULL },\r
1631     { "-defaultCacheSizeEGTB", "defaultCacheSizeEGTB", XrmoptionSepArg, NULL },\r
1632     { "-defaultPathEGTB", "defaultPathEGTB", XrmoptionSepArg, NULL },\r
1633     { "-defaultFrcPosition", "defaultFrcPosition", XrmoptionSepArg, NULL },\r
1634     // [HGM] I am sure AS added many more options, but we have to fish them out, from the list in winboard.c\r
1635 \r
1636     /* [HGM,HR] User-selectable board size */\r
1637     { "-boardWidth", "boardWidth", XrmoptionSepArg, NULL }, \r
1638     { "-boardHeight", "boardHeight", XrmoptionSepArg, NULL }, \r
1639     { "-matchPause", "matchPause", XrmoptionSepArg, NULL }, \r
1640 \r
1641     /* [HGM] new arguments of 4.3.xx. All except first three are back-end options, which should work immediately */\r
1642     { "-holdingsSize", "holdingsSize", XrmoptionSepArg, NULL }, // requires extensive front-end changes to work\r
1643     { "-flipBlack", "flipBlack", XrmoptionSepArg, NULL },       // requires front-end changes to work\r
1644     { "-allWhite", "allWhite", XrmoptionSepArg, NULL },         // requires front-end changes to work\r
1645     { "-pieceToCharTable", "pieceToCharTable", XrmoptionSepArg, NULL }, \r
1646     { "-alphaRank", "alphaRank", XrmoptionSepArg, NULL }, \r
1647     { "-testClaims", "testClaims", XrmoptionSepArg, NULL }, \r
1648     { "-checkMates", "checkMates", XrmoptionSepArg, NULL }, \r
1649     { "-materialDraws", "materialDraws", XrmoptionSepArg, NULL }, \r
1650     { "-trivialDraws", "trivialDraws", XrmoptionSepArg, NULL }, \r
1651     { "-ruleMoves", "ruleMoves", XrmoptionSepArg, NULL }, \r
1652     { "-repeatsToDraw", "repeatsToDraw", XrmoptionSepArg, NULL },\r
1653     { "-engineDebugOutput", "engineDebugOutput", XrmoptionSepArg, NULL }, \r
1654     { "-userName", "userName", XrmoptionSepArg, NULL }, \r
1655     { "-autoKibitz", "autoKibitz", XrmoptionNoArg, "True" }, \r
1656     { "-firstTimeOdds", "firstTimeOdds", XrmoptionSepArg, NULL }, \r
1657     { "-secondTimeOdds", "secondTimeOdds", XrmoptionSepArg, NULL }, \r
1658     { "-timeOddsMode", "timeOddsMode", XrmoptionSepArg, NULL }, \r
1659     { "-firstAccumulateTC", "firstAccumulateTC", XrmoptionSepArg, NULL }, \r
1660     { "-secondAccumulateTC", "secondAccumulateTC", XrmoptionSepArg, NULL }, \r
1661     { "-firstNPS", "firstNPS", XrmoptionSepArg, NULL }, \r
1662     { "-secondNPS", "secondNPS", XrmoptionSepArg, NULL }, \r
1663     { "-serverMoves", "serverMoves", XrmoptionSepArg, NULL }, \r
1664     { "-serverPause", "serverPause", XrmoptionSepArg, NULL }, \r
1665     { "-suppressLoadMoves", "suppressLoadMoves", XrmoptionSepArg, NULL }, \r
1666     { "-egtFormats", "egtFormats", XrmoptionSepArg, NULL }, \r
1667     { "-userName", "userName", XrmoptionSepArg, NULL }, \r
1668     { "-smpCores", "smpCores", XrmoptionSepArg, NULL }, \r
1669     { "-sameColorGames", "sameColorGames", XrmoptionSepArg, NULL }, \r
1670     { "-rewindIndex", "rewindIndex", XrmoptionSepArg, NULL }, \r
1671 };\r
1672 \r
1673 \r
1674 XtActionsRec boardActions[] = {\r
1675     { "DrawPosition", DrawPositionProc },\r
1676     { "HandleUserMove", HandleUserMove },\r
1677     { "AnimateUserMove", AnimateUserMove },\r
1678     { "FileNameAction", FileNameAction },\r
1679     { "AskQuestionProc", AskQuestionProc },\r
1680     { "AskQuestionReplyAction", AskQuestionReplyAction },\r
1681     { "PieceMenuPopup", PieceMenuPopup },\r
1682     { "WhiteClock", WhiteClock },\r
1683     { "BlackClock", BlackClock },\r
1684     { "Iconify", Iconify },\r
1685     { "ResetProc", ResetProc },\r
1686     { "LoadGameProc", LoadGameProc },\r
1687     { "LoadNextGameProc", LoadNextGameProc },\r
1688     { "LoadPrevGameProc", LoadPrevGameProc },\r
1689     { "LoadSelectedProc", LoadSelectedProc },\r
1690     { "ReloadGameProc", ReloadGameProc },\r
1691     { "LoadPositionProc", LoadPositionProc },\r
1692     { "LoadNextPositionProc", LoadNextPositionProc },\r
1693     { "LoadPrevPositionProc", LoadPrevPositionProc },\r
1694     { "ReloadPositionProc", ReloadPositionProc },\r
1695     { "CopyPositionProc", CopyPositionProc },\r
1696     { "PastePositionProc", PastePositionProc },\r
1697     { "CopyGameProc", CopyGameProc },\r
1698     { "PasteGameProc", PasteGameProc },\r
1699     { "SaveGameProc", SaveGameProc },\r
1700     { "SavePositionProc", SavePositionProc },\r
1701     { "MailMoveProc", MailMoveProc },\r
1702     { "ReloadCmailMsgProc", ReloadCmailMsgProc },\r
1703     { "QuitProc", QuitProc },\r
1704     { "MachineWhiteProc", MachineWhiteProc },\r
1705     { "MachineBlackProc", MachineBlackProc },\r
1706     { "AnalysisModeProc", AnalyzeModeProc },\r
1707     { "AnalyzeFileProc", AnalyzeFileProc },\r
1708     { "TwoMachinesProc", TwoMachinesProc },\r
1709     { "IcsClientProc", IcsClientProc },\r
1710     { "EditGameProc", EditGameProc },\r
1711     { "EditPositionProc", EditPositionProc },\r
1712     { "TrainingProc", EditPositionProc },\r
1713     { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window\r
1714     { "ShowGameListProc", ShowGameListProc },\r
1715     { "ShowMoveListProc", HistoryShowProc},\r
1716     { "EditTagsProc", EditCommentProc },\r
1717     { "EditCommentProc", EditCommentProc },\r
1718     { "IcsAlarmProc", IcsAlarmProc },\r
1719     { "IcsInputBoxProc", IcsInputBoxProc },\r
1720     { "PauseProc", PauseProc },\r
1721     { "AcceptProc", AcceptProc },\r
1722     { "DeclineProc", DeclineProc },\r
1723     { "RematchProc", RematchProc },\r
1724     { "CallFlagProc", CallFlagProc },\r
1725     { "DrawProc", DrawProc },\r
1726     { "AdjournProc", AdjournProc },\r
1727     { "AbortProc", AbortProc },\r
1728     { "ResignProc", ResignProc },\r
1729     { "EnterKeyProc", EnterKeyProc },\r
1730     { "StopObservingProc", StopObservingProc },\r
1731     { "StopExaminingProc", StopExaminingProc },\r
1732     { "BackwardProc", BackwardProc },\r
1733     { "ForwardProc", ForwardProc },\r
1734     { "ToStartProc", ToStartProc },\r
1735     { "ToEndProc", ToEndProc },\r
1736     { "RevertProc", RevertProc },\r
1737     { "TruncateGameProc", TruncateGameProc },\r
1738     { "MoveNowProc", MoveNowProc },\r
1739     { "RetractMoveProc", RetractMoveProc },\r
1740     { "AlwaysQueenProc", AlwaysQueenProc },\r
1741     { "AnimateDraggingProc", AnimateDraggingProc },\r
1742     { "AnimateMovingProc", AnimateMovingProc },\r
1743     { "AutoflagProc", AutoflagProc },\r
1744     { "AutoflipProc", AutoflipProc },\r
1745     { "AutobsProc", AutobsProc },\r
1746     { "AutoraiseProc", AutoraiseProc },\r
1747     { "AutosaveProc", AutosaveProc },\r
1748     { "BlindfoldProc", BlindfoldProc },\r
1749     { "FlashMovesProc", FlashMovesProc },\r
1750     { "FlipViewProc", FlipViewProc },\r
1751     { "GetMoveListProc", GetMoveListProc },\r
1752 #if HIGHDRAG\r
1753     { "HighlightDraggingProc", HighlightDraggingProc },\r
1754 #endif\r
1755     { "HighlightLastMoveProc", HighlightLastMoveProc },\r
1756     { "IcsAlarmProc", IcsAlarmProc },\r
1757     { "MoveSoundProc", MoveSoundProc },\r
1758     { "OldSaveStyleProc", OldSaveStyleProc },\r
1759     { "PeriodicUpdatesProc", PeriodicUpdatesProc },     \r
1760     { "PonderNextMoveProc", PonderNextMoveProc },\r
1761     { "PopupExitMessageProc", PopupExitMessageProc },   \r
1762     { "PopupMoveErrorsProc", PopupMoveErrorsProc },     \r
1763     { "PremoveProc", PremoveProc },\r
1764     { "QuietPlayProc", QuietPlayProc },\r
1765     { "ShowCoordsProc", ShowCoordsProc },\r
1766     { "ShowThinkingProc", ShowThinkingProc },\r
1767     { "HideThinkingProc", HideThinkingProc },\r
1768     { "TestLegalityProc", TestLegalityProc },\r
1769     { "InfoProc", InfoProc },\r
1770     { "ManProc", ManProc },\r
1771     { "HintProc", HintProc },\r
1772     { "BookProc", BookProc },\r
1773     { "AboutGameProc", AboutGameProc },\r
1774     { "AboutProc", AboutProc },\r
1775     { "DebugProc", DebugProc },\r
1776     { "NothingProc", NothingProc },\r
1777     { "CommentPopDown", (XtActionProc) CommentPopDown },\r
1778     { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },\r
1779     { "TagsPopDown", (XtActionProc) TagsPopDown },\r
1780     { "ErrorPopDown", (XtActionProc) ErrorPopDown },\r
1781     { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },\r
1782     { "AnalysisPopDown", (XtActionProc) AnalysisPopDown },\r
1783     { "FileNamePopDown", (XtActionProc) FileNamePopDown },\r
1784     { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },\r
1785     { "GameListPopDown", (XtActionProc) GameListPopDown },\r
1786     { "PromotionPopDown", (XtActionProc) PromotionPopDown },\r
1787     { "HistoryPopDown", (XtActionProc) HistoryPopDown },\r
1788     { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },\r
1789     { "ShufflePopDown", (XtActionProc) ShufflePopDown },\r
1790     { "EnginePopDown", (XtActionProc) EnginePopDown },\r
1791     { "UciPopDown", (XtActionProc) UciPopDown },\r
1792     { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },\r
1793     { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },\r
1794 };\r
1795      \r
1796 char globalTranslations[] =\r
1797   ":<Key>R: ResignProc() \n \\r
1798    :<Key>r: ResetProc() \n \\r
1799    :<Key>g: LoadGameProc() \n \\r
1800    :<Key>N: LoadNextGameProc() \n \\r
1801    :<Key>P: LoadPrevGameProc() \n \\r
1802    :<Key>Q: QuitProc() \n \\r
1803    :<Key>F: ToEndProc() \n \\r
1804    :<Key>f: ForwardProc() \n \\r
1805    :<Key>B: ToStartProc() \n \\r
1806    :<Key>b: BackwardProc() \n \\r
1807    :<Key>p: PauseProc() \n \\r
1808    :<Key>d: DrawProc() \n \\r
1809    :<Key>t: CallFlagProc() \n \\r
1810    :<Key>i: Iconify() \n \\r
1811    :<Key>c: Iconify() \n \\r
1812    :<Key>v: FlipViewProc() \n \\r
1813    <KeyDown>Control_L: BackwardProc() \n \\r
1814    <KeyUp>Control_L: ForwardProc() \n \\r
1815    <KeyDown>Control_R: BackwardProc() \n \\r
1816    <KeyUp>Control_R: ForwardProc() \n \\r
1817    Shift<Key>1: AskQuestionProc(\"Direct command\",\\r
1818                                 \"Send to chess program:\",,1) \n \\r
1819    Shift<Key>2: AskQuestionProc(\"Direct command\",\\r
1820                                 \"Send to second chess program:\",,2) \n";\r
1821 \r
1822 char boardTranslations[] =\r
1823    "<Btn1Down>: HandleUserMove() \n \\r
1824    <Btn1Up>: HandleUserMove() \n \\r
1825    <Btn1Motion>: AnimateUserMove() \n \\r
1826    Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\\r
1827                  PieceMenuPopup(menuB) \n \\r
1828    Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \\r
1829                  PieceMenuPopup(menuW) \n \\r
1830    Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\\r
1831                  PieceMenuPopup(menuW) \n \\r
1832    Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \\r
1833                  PieceMenuPopup(menuB) \n";\r
1834      \r
1835 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";\r
1836 char blackTranslations[] = "<BtnDown>: BlackClock()\n";\r
1837      \r
1838 char ICSInputTranslations[] =\r
1839     "<Key>Return: EnterKeyProc() \n";\r
1840 \r
1841 String xboardResources[] = {\r
1842     "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",\r
1843     "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",\r
1844     "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",\r
1845     NULL\r
1846   };\r
1847      \r
1848 \r
1849 /* Max possible square size */\r
1850 #define MAXSQSIZE 256\r
1851 \r
1852 static int xpm_avail[MAXSQSIZE];\r
1853 \r
1854 #ifdef HAVE_DIR_STRUCT\r
1855 \r
1856 /* Extract piece size from filename */\r
1857 static int\r
1858 xpm_getsize(name, len, ext)\r
1859      char *name;\r
1860      int len;\r
1861      char *ext;\r
1862 {\r
1863     char *p, *d;\r
1864     char buf[10];\r
1865   \r
1866     if (len < 4)\r
1867       return 0;\r
1868 \r
1869     if ((p=strchr(name, '.')) == NULL ||\r
1870         StrCaseCmp(p+1, ext) != 0)\r
1871       return 0;\r
1872   \r
1873     p = name + 3;\r
1874     d = buf;\r
1875 \r
1876     while (*p && isdigit(*p))\r
1877       *(d++) = *(p++);\r
1878 \r
1879     *d = 0;\r
1880     return atoi(buf);\r
1881 }\r
1882 \r
1883 /* Setup xpm_avail */\r
1884 static int\r
1885 xpm_getavail(dirname, ext)\r
1886      char *dirname;\r
1887      char *ext;\r
1888 {\r
1889     DIR *dir;\r
1890     struct dirent *ent;\r
1891     int  i;\r
1892 \r
1893     for (i=0; i<MAXSQSIZE; ++i)\r
1894       xpm_avail[i] = 0;\r
1895 \r
1896     if (appData.debugMode)\r
1897       fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);\r
1898   \r
1899     dir = opendir(dirname);\r
1900     if (!dir)\r
1901       {\r
1902           fprintf(stderr, "%s: Can't access XPM directory %s\n", \r
1903                   programName, dirname);\r
1904           exit(1);\r
1905       }\r
1906   \r
1907     while ((ent=readdir(dir)) != NULL) {\r
1908         i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);\r
1909         if (i > 0 && i < MAXSQSIZE)\r
1910           xpm_avail[i] = 1;\r
1911     }\r
1912 \r
1913     closedir(dir);\r
1914 \r
1915     return 0;\r
1916 }\r
1917 \r
1918 void\r
1919 xpm_print_avail(fp, ext)\r
1920      FILE *fp;\r
1921      char *ext;\r
1922 {\r
1923     int i;\r
1924 \r
1925     fprintf(fp, "Available `%s' sizes:\n", ext);\r
1926     for (i=1; i<MAXSQSIZE; ++i) {\r
1927         if (xpm_avail[i])\r
1928           printf("%d\n", i);\r
1929     }\r
1930 }\r
1931 \r
1932 /* Return XPM piecesize closest to size */\r
1933 int\r
1934 xpm_closest_to(dirname, size, ext)\r
1935      char *dirname;\r
1936      int size;\r
1937      char *ext;\r
1938 {\r
1939     int i;\r
1940     int sm_diff = MAXSQSIZE;\r
1941     int sm_index = 0;\r
1942     int diff;\r
1943   \r
1944     xpm_getavail(dirname, ext);\r
1945 \r
1946     if (appData.debugMode)\r
1947       xpm_print_avail(stderr, ext);\r
1948   \r
1949     for (i=1; i<MAXSQSIZE; ++i) {\r
1950         if (xpm_avail[i]) {\r
1951             diff = size - i;\r
1952             diff = (diff<0) ? -diff : diff;\r
1953             if (diff < sm_diff) {\r
1954                 sm_diff = diff;\r
1955                 sm_index = i;\r
1956             }\r
1957         }\r
1958     }\r
1959 \r
1960     if (!sm_index) {\r
1961         fprintf(stderr, "Error: No `%s' files!\n", ext);\r
1962         exit(1);\r
1963     }\r
1964 \r
1965     return sm_index;\r
1966 }\r
1967 #else   /* !HAVE_DIR_STRUCT */\r
1968 /* If we are on a system without a DIR struct, we can't\r
1969    read the directory, so we can't collect a list of\r
1970    filenames, etc., so we can't do any size-fitting. */\r
1971 int\r
1972 xpm_closest_to(dirname, size, ext)\r
1973      char *dirname;\r
1974      int size;\r
1975      char *ext;\r
1976 {\r
1977     fprintf(stderr, "Warning: No DIR structure found on this system --\n");\r
1978     fprintf(stderr, "         Unable to autosize for XPM/XIM pieces.\n");\r
1979     fprintf(stderr, "   Please report this error to frankm@hiwaay.net.\n");\r
1980     fprintf(stderr, "   Include system type & operating system in message.\n");\r
1981     return size;\r
1982 }\r
1983 #endif /* HAVE_DIR_STRUCT */\r
1984 \r
1985 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",\r
1986                              "magenta", "cyan", "white" };\r
1987 typedef struct {\r
1988     int attr, bg, fg;\r
1989 } TextColors;\r
1990 TextColors textColors[(int)NColorClasses];\r
1991 \r
1992 /* String is: "fg, bg, attr". Which is 0, 1, 2 */\r
1993 static int\r
1994 parse_color(str, which)\r
1995      char *str;\r
1996      int which;\r
1997 {\r
1998     char *p, buf[100], *d;\r
1999     int i;\r
2000   \r
2001     if (strlen(str) > 99)       /* watch bounds on buf */\r
2002       return -1;\r
2003 \r
2004     p = str;\r
2005     d = buf;\r
2006     for (i=0; i<which; ++i) {\r
2007         p = strchr(p, ',');\r
2008         if (!p)\r
2009           return -1;\r
2010         ++p;\r
2011     }\r
2012 \r
2013     /* Could be looking at something like:\r
2014        black, , 1\r
2015        .. in which case we want to stop on a comma also */\r
2016     while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))\r
2017       ++p;\r
2018 \r
2019     if (*p == ',') {\r
2020         return -1;              /* Use default for empty field */\r
2021     }\r
2022     \r
2023     if (which == 2 || isdigit(*p))\r
2024       return atoi(p);\r
2025  \r
2026     while (*p && isalpha(*p))\r
2027       *(d++) = *(p++);\r
2028 \r
2029     *d = 0;\r
2030 \r
2031     for (i=0; i<8; ++i) {\r
2032         if (!StrCaseCmp(buf, cnames[i]))\r
2033           return which? (i+40) : (i+30);\r
2034     }\r
2035     if (!StrCaseCmp(buf, "default")) return -1;\r
2036 \r
2037     fprintf(stderr, "%s: unrecognized color %s\n", programName, buf);\r
2038     return -2;\r
2039 }\r
2040 \r
2041 static int\r
2042 parse_cpair(cc, str)\r
2043      ColorClass cc;\r
2044      char *str;\r
2045 {\r
2046     if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {\r
2047         fprintf(stderr, "%s: can't parse foreground color in `%s'\n",\r
2048                 programName, str);\r
2049         return -1;\r
2050     }\r
2051 \r
2052     /* bg and attr are optional */\r
2053     textColors[(int)cc].bg = parse_color(str, 1);\r
2054     if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {\r
2055         textColors[(int)cc].attr = 0;\r
2056     }\r
2057     return 0;\r
2058 }\r
2059 \r
2060 \r
2061 /* Arrange to catch delete-window events */\r
2062 Atom wm_delete_window;\r
2063 void\r
2064 CatchDeleteWindow(Widget w, String procname)\r
2065 {\r
2066   char buf[MSG_SIZ];\r
2067   XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);\r
2068   sprintf(buf, "<Message>WM_PROTOCOLS: %s() \n", procname);\r
2069   XtAugmentTranslations(w, XtParseTranslationTable(buf));\r
2070 }\r
2071 \r
2072 void\r
2073 BoardToTop()\r
2074 {\r
2075   Arg args[16];\r
2076   XtSetArg(args[0], XtNiconic, False);\r
2077   XtSetValues(shellWidget, args, 1);\r
2078 \r
2079   XtPopup(shellWidget, XtGrabNone); /* Raise if lowered  */\r
2080 }\r
2081 \r
2082 #ifdef IDSIZES\r
2083   // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined\r
2084 #else
2085 #define BoardSize int\r
2086 void InitDrawingSizes(BoardSize boardSize, int flags)\r
2087 {   // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)\r
2088     Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
2089     Arg args[16];
2090     XtGeometryResult gres;\r
2091     int i;
2092
2093     if(!formWidget) return;\r
2094
2095     /*\r
2096      * Enable shell resizing.\r
2097      */\r
2098     shellArgs[0].value = (XtArgVal) &w;\r
2099     shellArgs[1].value = (XtArgVal) &h;\r
2100     XtGetValues(shellWidget, shellArgs, 2);\r
2101
2102     shellArgs[4].value = 2*w; shellArgs[2].value = 10;\r
2103     shellArgs[5].value = 2*h; shellArgs[3].value = 10;\r
2104     XtSetValues(shellWidget, &shellArgs[2], 4);
2105 \r
2106     XtSetArg(args[0], XtNdefaultDistance, &sep);\r    XtGetValues(formWidget, args, 1);
2107 \r
2108     boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);\r
2109     boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
2110     CreateGrid();\r
2111
2112     XtSetArg(args[0], XtNwidth, boardWidth);\r
2113     XtSetArg(args[1], XtNheight, boardHeight);\r
2114     XtSetValues(boardWidget, args, 2);\r
2115 \r
2116     timerWidth = (boardWidth - sep) / 2;\r
2117     XtSetArg(args[0], XtNwidth, timerWidth);\r
2118     XtSetValues(whiteTimerWidget, args, 1);\r
2119     XtSetValues(blackTimerWidget, args, 1);\r
2120 \r
2121     XawFormDoLayout(formWidget, False);\r
2122
2123     if (appData.titleInWindow) {\r
2124         i = 0;\r
2125         XtSetArg(args[i], XtNborderWidth, &bor); i++;\r
2126         XtSetArg(args[i], XtNheight, &h);  i++;\r
2127         XtGetValues(titleWidget, args, i);\r
2128         if (smallLayout) {\r
2129             w = boardWidth - 2*bor;\r
2130         } else {\r
2131             XtSetArg(args[0], XtNwidth, &w);\r
2132             XtGetValues(menuBarWidget, args, 1);\r
2133             w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE\r
2134         }\r
2135 \r
2136         gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);\r
2137         if (gres != XtGeometryYes && appData.debugMode) {\r
2138             fprintf(stderr,\r
2139                     "%s: titleWidget geometry error %d %d %d %d %d\n",\r
2140                     programName, gres, w, h, wr, hr);\r
2141         }\r
2142     }\r
2143 \r
2144     XawFormDoLayout(formWidget, True);\r
2145
2146     /*\r
2147      * Inhibit shell resizing.\r
2148      */
2149     shellArgs[0].value = w = (XtArgVal) boardWidth + marginW;\r
2150     shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;\r
2151     shellArgs[4].value = shellArgs[2].value = w;\r
2152     shellArgs[5].value = shellArgs[3].value = h;\r
2153     XtSetValues(shellWidget, &shellArgs[0], 6);\r
2154 }\r
2155 #endif\r
2156 \r
2157 int\r
2158 main(argc, argv)\r
2159      int argc;\r
2160      char **argv;\r
2161 {\r
2162     int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;\r
2163     XSetWindowAttributes window_attributes;\r
2164     Arg args[16];\r
2165     Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;\r
2166     XrmValue vFrom, vTo;\r
2167     XtGeometryResult gres;\r
2168     char *p;\r
2169     XrmDatabase xdb;\r
2170     int forceMono = False;
2171 #define INDIRECTION\r
2172 #ifdef INDIRECTION
2173     // [HGM] before anything else, expand any indirection files amongst options
2174     char *argvCopy[1000]; // 1000 seems enough
2175     char newArgs[10000];  // holds actual characters
2176     int k = 0;
2177
2178     srandom(time(0)); // [HGM] book: make random truly random
2179
2180     j = 0;
2181     for(i=0; i<argc; i++) {
2182         if(j >= 1000-2) { printf("too many arguments\n"); exit(-1); }
2183 //fprintf(stderr, "arg %s\n", argv[i]);
2184         if(argv[i][0] != '@') argvCopy[j++] = argv[i]; else {
2185             char c;
2186             FILE *f = fopen(argv[i]+1, "rb");
2187             if(f == NULL) { fprintf(stderr, "ignore %s\n", argv[i]); continue; } // do not expand non-existing
2188             argvCopy[j++] = newArgs + k; // get ready for first argument from file
2189             while((c = fgetc(f)) != EOF) { // each line of file inserts 1 argument in the list
2190                 if(c == '\n') {
2191                     if(j >= 1000-2) { printf("too many arguments\n"); exit(-1); }
2192                     newArgs[k++] = 0;  // terminate current arg
2193                     if(k >= 10000-1) { printf("too long arguments\n"); exit(-1); }
2194                     argvCopy[j++] = newArgs + k; // get ready for next
2195                 } else {
2196                     if(k >= 10000-1) { printf("too long arguments\n"); exit(-1); }
2197                     newArgs[k++] = c;
2198                 }
2199             }
2200             newArgs[k] = 0;
2201             j--;
2202             fclose(f);
2203         }
2204     }
2205     argvCopy[j] = NULL;
2206     argv = argvCopy;
2207     argc = j;
2208 #if 0
2209     if(appData.debugMode,1) { // OK, appData is not initialized here yet...
2210         for(i=0; i<argc; i++) fprintf(stderr, "argv[%2d] = '%s'\n", i, argv[i]);
2211     }
2212 #endif
2213 #endif
2214
2215 \r
2216     setbuf(stdout, NULL);\r
2217     setbuf(stderr, NULL);\r
2218     debugFP = stderr;\r
2219     \r
2220     programName = strrchr(argv[0], '/');\r
2221     if (programName == NULL)\r
2222       programName = argv[0];\r
2223     else\r
2224       programName++;\r
2225 \r
2226     shellWidget =\r
2227       XtAppInitialize(&appContext, "XBoard", shellOptions,\r
2228                       XtNumber(shellOptions),\r
2229                       &argc, argv, xboardResources, NULL, 0);\r
2230     if (argc > 1) {\r
2231         fprintf(stderr, "%s: unrecognized argument %s\n",\r
2232                 programName, argv[1]);\r
2233         exit(2);\r
2234     }\r
2235     \r
2236     if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {\r
2237         chessDir = ".";\r
2238     } else {\r
2239         if (chdir(chessDir) != 0) {\r
2240             fprintf(stderr, "%s: can't cd to CHESSDIR: ", programName);\r
2241             perror(chessDir);\r
2242             exit(1);\r
2243         }\r
2244     }\r
2245     \r
2246     p = getenv("HOME");\r
2247     if (p == NULL) p = "/tmp";\r
2248     i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;\r
2249     gameCopyFilename = (char*) malloc(i);\r
2250     gamePasteFilename = (char*) malloc(i);\r
2251     sprintf(gameCopyFilename, "%s/.xboard%05uc.pgn", p, getpid());\r
2252     sprintf(gamePasteFilename, "%s/.xboard%05up.pgn", p, getpid());\r
2253 \r
2254     XtGetApplicationResources(shellWidget, (XtPointer) &appData,\r
2255                               clientResources, XtNumber(clientResources),\r
2256                               NULL, 0);\r
2257 \r
2258     /* [HGM,HR] make sure board size is acceptable */\r
2259     if(appData.NrFiles > BOARD_SIZE ||\r
2260        appData.NrRanks > BOARD_SIZE   )\r
2261          DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);\r
2262 \r
2263 #if !HIGHDRAG\r
2264     /* This feature does not work; animation needs a rewrite */\r
2265     appData.highlightDragging = FALSE;\r
2266 #endif\r
2267     InitBackEnd1();\r
2268 \r
2269     xDisplay = XtDisplay(shellWidget);\r
2270     xScreen = DefaultScreen(xDisplay);\r
2271     wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);\r
2272 \r
2273         gameInfo.variant = StringToVariant(appData.variant);\r
2274         InitPosition(FALSE);\r
2275 #if 0\r
2276     /*\r
2277      * Determine boardSize\r
2278      */\r
2279     gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] boardsize: make sure we start as 8x8\r
2280 \r
2281 //#ifndef IDSIZE\r
2282     // [HGM] as long as we have not created the possibility to change size while running, start with requested size\r
2283     gameInfo.boardWidth    = appData.NrFiles > 0 ? appData.NrFiles : 8; \r
2284     gameInfo.boardHeight   = appData.NrRanks > 0 ? appData.NrRanks : 8;\r
2285     gameInfo.holdingsWidth = appData.holdingsSize > 0 ? 2 : 0;\r
2286 #endif\r
2287 \r
2288 \r
2289 #ifdef IDSIZE\r
2290     InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine\r
2291 #else\r
2292     if (isdigit(appData.boardSize[0])) {\r
2293         i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,\r
2294                    &lineGap, &clockFontPxlSize, &coordFontPxlSize,\r
2295                    &fontPxlSize, &smallLayout, &tinyLayout);\r
2296         if (i == 0) {\r
2297             fprintf(stderr, "%s: bad boardSize syntax %s\n",\r
2298                     programName, appData.boardSize);\r
2299             exit(2);\r
2300         }\r
2301         if (i < 7) {\r
2302             /* Find some defaults; use the nearest known size */\r
2303             SizeDefaults *szd, *nearest;\r
2304             int distance = 99999;\r
2305             nearest = szd = sizeDefaults;\r
2306             while (szd->name != NULL) {\r
2307                 if (abs(szd->squareSize - squareSize) < distance) {\r
2308                     nearest = szd;\r
2309                     distance = abs(szd->squareSize - squareSize);\r
2310                     if (distance == 0) break;\r
2311                 }\r
2312                 szd++;\r
2313             }\r
2314             if (i < 2) lineGap = nearest->lineGap;\r
2315             if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;\r
2316             if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;\r
2317             if (i < 5) fontPxlSize = nearest->fontPxlSize;\r
2318             if (i < 6) smallLayout = nearest->smallLayout;\r
2319             if (i < 7) tinyLayout = nearest->tinyLayout;\r
2320         }\r
2321     } else {\r
2322         SizeDefaults *szd = sizeDefaults;\r
2323         if (*appData.boardSize == NULLCHAR) {\r
2324             while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||\r
2325                    DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {\r
2326               szd++;\r
2327             }\r
2328             if (szd->name == NULL) szd--;\r
2329         } else {\r
2330             while (szd->name != NULL &&\r
2331                    StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;\r
2332             if (szd->name == NULL) {\r
2333                 fprintf(stderr, "%s: unrecognized boardSize name %s\n",\r
2334                         programName, appData.boardSize);\r
2335                 exit(2);\r
2336             }\r
2337         }\r
2338         squareSize = szd->squareSize;\r
2339         lineGap = szd->lineGap;\r
2340         clockFontPxlSize = szd->clockFontPxlSize;\r
2341         coordFontPxlSize = szd->coordFontPxlSize;\r
2342         fontPxlSize = szd->fontPxlSize;\r
2343         smallLayout = szd->smallLayout;\r
2344         tinyLayout = szd->tinyLayout;\r
2345     }\r
2346 \r
2347     /* Now, using squareSize as a hint, find a good XPM/XIM set size */\r
2348     if (strlen(appData.pixmapDirectory) > 0) {\r
2349         p = ExpandPathName(appData.pixmapDirectory);\r
2350         if (!p) {\r
2351             fprintf(stderr, "Error expanding path name \"%s\"\n",\r
2352                    appData.pixmapDirectory);\r
2353             exit(1);\r
2354         }\r
2355         if (appData.debugMode) {\r
2356             fprintf(stderr, "XBoard square size (hint): %d\n", squareSize);\r
2357             fprintf(stderr, "%s fulldir:%s:\n", IMAGE_EXT, p);\r
2358         }\r
2359         squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);\r
2360         if (appData.debugMode) {\r
2361             fprintf(stderr, "Closest %s size: %d\n", IMAGE_EXT, squareSize);\r
2362         }\r
2363     }\r
2364                 \r
2365     /* [HR] height treated separately (hacked) */\r
2366     boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);\r
2367     boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);\r
2368     if (appData.showJail == 1) {\r
2369         /* Jail on top and bottom */\r
2370         XtSetArg(boardArgs[1], XtNwidth, boardWidth);\r
2371         XtSetArg(boardArgs[2], XtNheight,\r
2372                  boardHeight + 2*(lineGap + squareSize));\r
2373     } else if (appData.showJail == 2) {\r
2374         /* Jail on sides */\r
2375         XtSetArg(boardArgs[1], XtNwidth,\r
2376                  boardWidth + 2*(lineGap + squareSize));\r
2377         XtSetArg(boardArgs[2], XtNheight, boardHeight);\r
2378     } else {\r
2379         /* No jail */\r
2380         XtSetArg(boardArgs[1], XtNwidth, boardWidth);\r
2381         XtSetArg(boardArgs[2], XtNheight, boardHeight);\r
2382     }\r
2383 \r
2384     /*\r
2385      * Determine what fonts to use.\r
2386      */\r
2387     appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);\r
2388     clockFontID = XLoadFont(xDisplay, appData.clockFont);\r
2389     clockFontStruct = XQueryFont(xDisplay, clockFontID);\r
2390     appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);\r
2391     coordFontID = XLoadFont(xDisplay, appData.coordFont);\r
2392     coordFontStruct = XQueryFont(xDisplay, coordFontID);\r
2393     appData.font = FindFont(appData.font, fontPxlSize);\r
2394     countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings\r
2395     countFontStruct = XQueryFont(xDisplay, countFontID);\r
2396 //    appData.font = FindFont(appData.font, fontPxlSize);\r
2397 \r
2398     xdb = XtDatabase(xDisplay);\r
2399     XrmPutStringResource(&xdb, "*font", appData.font);\r
2400 \r
2401     /*\r
2402      * Detect if there are not enough colors available and adapt.\r
2403      */\r
2404     if (DefaultDepth(xDisplay, xScreen) <= 2) {\r
2405       appData.monoMode = True;\r
2406     }\r
2407 \r
2408     if (!appData.monoMode) {\r
2409         vFrom.addr = (caddr_t) appData.lightSquareColor;\r
2410         vFrom.size = strlen(appData.lightSquareColor);\r
2411         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);\r
2412         if (vTo.addr == NULL) {\r
2413           appData.monoMode = True;\r
2414           forceMono = True;\r
2415         } else {\r
2416           lightSquareColor = *(Pixel *) vTo.addr;\r
2417         }\r
2418     }\r
2419     if (!appData.monoMode) {\r
2420         vFrom.addr = (caddr_t) appData.darkSquareColor;\r
2421         vFrom.size = strlen(appData.darkSquareColor);\r
2422         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);\r
2423         if (vTo.addr == NULL) {\r
2424           appData.monoMode = True;\r
2425           forceMono = True;\r
2426         } else {\r
2427           darkSquareColor = *(Pixel *) vTo.addr;\r
2428         }\r
2429     }\r
2430     if (!appData.monoMode) {\r
2431         vFrom.addr = (caddr_t) appData.whitePieceColor;\r
2432         vFrom.size = strlen(appData.whitePieceColor);\r
2433         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);\r
2434         if (vTo.addr == NULL) {\r
2435           appData.monoMode = True;\r
2436           forceMono = True;\r
2437         } else {\r
2438           whitePieceColor = *(Pixel *) vTo.addr;\r
2439         }\r
2440     }\r
2441     if (!appData.monoMode) {\r
2442         vFrom.addr = (caddr_t) appData.blackPieceColor;\r
2443         vFrom.size = strlen(appData.blackPieceColor);\r
2444         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);\r
2445         if (vTo.addr == NULL) {\r
2446           appData.monoMode = True;\r
2447           forceMono = True;\r
2448         } else {\r
2449           blackPieceColor = *(Pixel *) vTo.addr;\r
2450         }\r
2451     }\r
2452 \r
2453     if (!appData.monoMode) {\r
2454         vFrom.addr = (caddr_t) appData.highlightSquareColor;\r
2455         vFrom.size = strlen(appData.highlightSquareColor);\r
2456         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);\r
2457         if (vTo.addr == NULL) {\r
2458           appData.monoMode = True;\r
2459           forceMono = True;\r
2460         } else {\r
2461           highlightSquareColor = *(Pixel *) vTo.addr;\r
2462         }\r
2463     }\r
2464 \r
2465     if (!appData.monoMode) {\r
2466         vFrom.addr = (caddr_t) appData.premoveHighlightColor;\r
2467         vFrom.size = strlen(appData.premoveHighlightColor);\r
2468         XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);\r
2469         if (vTo.addr == NULL) {\r
2470           appData.monoMode = True;\r
2471           forceMono = True;\r
2472         } else {\r
2473           premoveHighlightColor = *(Pixel *) vTo.addr;\r
2474         }\r
2475     }\r
2476 \r
2477     if (forceMono) {\r
2478       fprintf(stderr, "%s: too few colors available; trying monochrome mode\n",\r
2479               programName);\r
2480     }\r
2481 \r
2482     if (appData.monoMode && appData.debugMode) {\r
2483         fprintf(stderr, "white pixel = 0x%lx, black pixel = 0x%lx\n",\r
2484                 (unsigned long) XWhitePixel(xDisplay, xScreen),\r
2485                 (unsigned long) XBlackPixel(xDisplay, xScreen));\r
2486     }\r
2487     \r
2488     if (parse_cpair(ColorShout, appData.colorShout) < 0 ||\r
2489         parse_cpair(ColorSShout, appData.colorSShout) < 0 ||\r
2490         parse_cpair(ColorChannel1, appData.colorChannel1) < 0  ||\r
2491         parse_cpair(ColorChannel, appData.colorChannel) < 0  ||\r
2492         parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||\r
2493         parse_cpair(ColorTell, appData.colorTell) < 0 ||\r
2494         parse_cpair(ColorChallenge, appData.colorChallenge) < 0  ||\r
2495         parse_cpair(ColorRequest, appData.colorRequest) < 0  ||\r
2496         parse_cpair(ColorSeek, appData.colorSeek) < 0  ||\r
2497         parse_cpair(ColorNormal, appData.colorNormal) < 0)\r
2498       {\r
2499           if (appData.colorize) {\r
2500               fprintf(stderr,\r
2501                       "%s: can't parse color names; disabling colorization\n",\r
2502                       programName);\r
2503           }\r
2504           appData.colorize = FALSE;\r
2505       }\r
2506     textColors[ColorNone].fg = textColors[ColorNone].bg = -1;\r
2507     textColors[ColorNone].attr = 0;\r
2508     \r
2509     XtAppAddActions(appContext, boardActions, XtNumber(boardActions));\r
2510     \r
2511     /*\r
2512      * widget hierarchy\r
2513      */\r
2514     if (tinyLayout) {\r
2515         layoutName = "tinyLayout";\r
2516     } else if (smallLayout) {\r
2517         layoutName = "smallLayout";\r
2518     } else {\r
2519         layoutName = "normalLayout";\r
2520     }\r
2521     /* Outer layoutWidget is there only to provide a name for use in\r
2522        resources that depend on the layout style */\r
2523     layoutWidget =\r
2524       XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,\r
2525                             layoutArgs, XtNumber(layoutArgs));\r
2526     formWidget =\r
2527       XtCreateManagedWidget("form", formWidgetClass, layoutWidget,\r
2528                             formArgs, XtNumber(formArgs));\r
2529     XtSetArg(args[0], XtNdefaultDistance, &sep);\r
2530     XtGetValues(formWidget, args, 1);\r
2531 \r
2532     j = 0;\r
2533     widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);\r
2534     XtSetArg(args[0], XtNtop,    XtChainTop);\r
2535     XtSetArg(args[1], XtNbottom, XtChainTop);
2536     XtSetValues(menuBarWidget, args, 2);\r
2537 \r
2538     widgetList[j++] = whiteTimerWidget =\r
2539       XtCreateWidget("whiteTime", labelWidgetClass,\r
2540                      formWidget, timerArgs, XtNumber(timerArgs));\r
2541     XtSetArg(args[0], XtNfont, clockFontStruct);\r
2542     XtSetArg(args[1], XtNtop,    XtChainTop);\r
2543     XtSetArg(args[2], XtNbottom, XtChainTop);
2544     XtSetValues(whiteTimerWidget, args, 3);\r
2545     \r
2546     widgetList[j++] = blackTimerWidget =\r
2547       XtCreateWidget("blackTime", labelWidgetClass,\r
2548                      formWidget, timerArgs, XtNumber(timerArgs));\r
2549     XtSetArg(args[0], XtNfont, clockFontStruct);\r
2550     XtSetArg(args[1], XtNtop,    XtChainTop);\r
2551     XtSetArg(args[2], XtNbottom, XtChainTop);
2552     XtSetValues(blackTimerWidget, args, 3);\r
2553     \r
2554     if (appData.titleInWindow) {\r
2555         widgetList[j++] = titleWidget = \r
2556           XtCreateWidget("title", labelWidgetClass, formWidget,\r
2557                          titleArgs, XtNumber(titleArgs));\r
2558         XtSetArg(args[0], XtNtop,    XtChainTop);\r
2559         XtSetArg(args[1], XtNbottom, XtChainTop);
2560         XtSetValues(titleWidget, args, 2);\r
2561     }\r
2562 \r
2563     if (appData.showButtonBar) {\r
2564       widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);\r
2565       XtSetArg(args[0], XtNleft,  XtChainRight); // [HGM] glue to right window edge\r
2566       XtSetArg(args[1], XtNright, XtChainRight); //       for good run-time sizing
2567       XtSetArg(args[2], XtNtop,    XtChainTop);\r
2568       XtSetArg(args[3], XtNbottom, XtChainTop);
2569       XtSetValues(buttonBarWidget, args, 4);\r
2570     }\r
2571 \r
2572     widgetList[j++] = messageWidget =\r
2573       XtCreateWidget("message", labelWidgetClass, formWidget,\r
2574                      messageArgs, XtNumber(messageArgs));
2575     XtSetArg(args[0], XtNtop,    XtChainTop);\r
2576     XtSetArg(args[1], XtNbottom, XtChainTop);
2577     XtSetValues(messageWidget, args, 2);\r
2578 \r
2579     widgetList[j++] = boardWidget =\r
2580       XtCreateWidget("board", widgetClass, formWidget, boardArgs,\r
2581                      XtNumber(boardArgs));\r
2582 \r
2583     XtManageChildren(widgetList, j);\r
2584     \r
2585     timerWidth = (boardWidth - sep) / 2;\r
2586     XtSetArg(args[0], XtNwidth, timerWidth);\r
2587     XtSetValues(whiteTimerWidget, args, 1);\r
2588     XtSetValues(blackTimerWidget, args, 1);\r
2589     \r
2590     XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);\r
2591     XtSetArg(args[1], XtNforeground, &timerForegroundPixel);\r
2592     XtGetValues(whiteTimerWidget, args, 2);\r
2593     \r
2594     if (appData.showButtonBar) {\r
2595       XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);\r
2596       XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);\r
2597       XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);\r
2598     }\r
2599 \r
2600     /*\r
2601      * formWidget uses these constraints but they are stored\r
2602      * in the children.\r
2603      */\r
2604     i = 0;\r
2605     XtSetArg(args[i], XtNfromHoriz, 0); i++;\r
2606     XtSetValues(menuBarWidget, args, i);\r
2607     if (appData.titleInWindow) {\r
2608         if (smallLayout) {\r
2609             i = 0;\r
2610             XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;\r
2611             XtSetValues(whiteTimerWidget, args, i);\r
2612             i = 0;\r
2613             XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;\r
2614             XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;\r
2615             XtSetValues(blackTimerWidget, args, i);\r
2616             i = 0;\r
2617             XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;\r
2618             XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;\r
2619             XtSetValues(titleWidget, args, i);\r
2620             i = 0;\r
2621             XtSetArg(args[i], XtNfromVert, titleWidget); i++;\r
2622             XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;\r
2623             XtSetValues(messageWidget, args, i);\r
2624             if (appData.showButtonBar) {\r
2625               i = 0;\r
2626               XtSetArg(args[i], XtNfromVert, titleWidget); i++;\r
2627               XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;\r
2628               XtSetValues(buttonBarWidget, args, i);\r
2629             }\r
2630         } else {\r
2631             i = 0;\r
2632             XtSetArg(args[i], XtNfromVert, titleWidget); i++;\r
2633             XtSetValues(whiteTimerWidget, args, i);\r
2634             i = 0;\r
2635             XtSetArg(args[i], XtNfromVert, titleWidget); i++;\r
2636             XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;\r
2637             XtSetValues(blackTimerWidget, args, i);\r
2638             i = 0;\r
2639             XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;\r
2640             XtSetValues(titleWidget, args, i);\r
2641             i = 0;\r
2642             XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;\r
2643             XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;\r
2644             XtSetValues(messageWidget, args, i);\r
2645             if (appData.showButtonBar) {\r
2646               i = 0;\r
2647               XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;\r
2648               XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;\r
2649               XtSetValues(buttonBarWidget, args, i);\r
2650             }\r
2651         }\r
2652     } else {\r
2653         i = 0;\r
2654         XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;\r
2655         XtSetValues(whiteTimerWidget, args, i);\r
2656         i = 0;\r
2657         XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;\r
2658         XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;\r
2659         XtSetValues(blackTimerWidget, args, i);\r
2660         i = 0;\r
2661         XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;\r
2662         XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;\r
2663         XtSetValues(messageWidget, args, i);\r
2664         if (appData.showButtonBar) {\r
2665           i = 0;\r
2666           XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;\r
2667           XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;\r
2668           XtSetValues(buttonBarWidget, args, i);\r
2669         }\r
2670     }\r
2671     i = 0;\r
2672     XtSetArg(args[0], XtNfromVert, messageWidget);\r
2673     XtSetArg(args[1], XtNtop,    XtChainTop);\r
2674     XtSetArg(args[2], XtNbottom, XtChainBottom);
2675     XtSetArg(args[3], XtNleft,   XtChainLeft);\r
2676     XtSetArg(args[4], XtNright,  XtChainRight);
2677     XtSetValues(boardWidget, args, 5);\r
2678 \r
2679     XtRealizeWidget(shellWidget);\r
2680 \r
2681     /*\r
2682      * Correct the width of the message and title widgets.\r
2683      * It is not known why some systems need the extra fudge term.\r
2684      * The value "2" is probably larger than needed.\r
2685      */\r
2686     XawFormDoLayout(formWidget, False);\r
2687
2688 #define WIDTH_FUDGE 2\r
2689     i = 0;\r
2690     XtSetArg(args[i], XtNborderWidth, &bor);  i++;\r
2691     XtSetArg(args[i], XtNheight, &h);  i++;\r
2692     XtGetValues(messageWidget, args, i);\r
2693     if (appData.showButtonBar) {\r
2694       i = 0;\r
2695       XtSetArg(args[i], XtNwidth, &w);  i++;\r
2696       XtGetValues(buttonBarWidget, args, i);\r
2697       w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;\r
2698     } else {\r
2699       w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */\r
2700     }\r
2701 \r
2702     gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);\r
2703     if (gres != XtGeometryYes && appData.debugMode) {\r
2704       fprintf(stderr, "%s: messageWidget geometry error %d %d %d %d %d\n",\r
2705               programName, gres, w, h, wr, hr);\r
2706     }\r
2707     \r
2708     /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */\r
2709     /* The size used for the child widget in layout lags one resize behind\r
2710        its true size, so we resize a second time, 1 pixel smaller.  Yeech! */\r
2711     w--;\r
2712     gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);\r
2713     if (gres != XtGeometryYes && appData.debugMode) {\r
2714       fprintf(stderr, "%s: messageWidget geometry error %d %d %d %d %d\n",\r
2715               programName, gres, w, h, wr, hr);\r
2716     }\r
2717     /* !! end hack */\r
2718     XtSetArg(args[0], XtNleft,  XtChainLeft);  // [HGM] glue ends for good run-time sizing\r
2719     XtSetArg(args[1], XtNright, XtChainRight);
2720     XtSetValues(messageWidget, args, 2);\r
2721 \r
2722     if (appData.titleInWindow) {\r
2723         i = 0;\r
2724         XtSetArg(args[i], XtNborderWidth, &bor); i++;\r
2725         XtSetArg(args[i], XtNheight, &h);  i++;\r
2726         XtGetValues(titleWidget, args, i);\r
2727         if (smallLayout) {\r
2728             w = boardWidth - 2*bor;\r
2729         } else {\r
2730             XtSetArg(args[0], XtNwidth, &w);\r
2731             XtGetValues(menuBarWidget, args, 1);\r
2732             w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;\r
2733         }\r
2734 \r
2735         gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);\r
2736         if (gres != XtGeometryYes && appData.debugMode) {\r
2737             fprintf(stderr,\r
2738                     "%s: titleWidget geometry error %d %d %d %d %d\n",\r
2739                     programName, gres, w, h, wr, hr);\r
2740         }\r
2741     }\r
2742     XawFormDoLayout(formWidget, True);\r
2743 \r
2744     xBoardWindow = XtWindow(boardWidget);\r
2745 \r
2746     // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would\r
2747     //       not need to go into InitDrawingSizes().\r
2748 #endif    \r
2749 \r
2750     /* \r
2751      * Create X checkmark bitmap and initialize option menu checks.\r
2752      */\r
2753     ReadBitmap(&xMarkPixmap, "checkmark.bm",\r
2754                checkmark_bits, checkmark_width, checkmark_height);\r
2755     XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);\r
2756     if (appData.alwaysPromoteToQueen) {\r
2757         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),\r
2758                     args, 1);\r
2759     }\r
2760     if (appData.animateDragging) {\r
2761         XtSetValues(XtNameToWidget(menuBarWidget,\r
2762                                    "menuOptions.Animate Dragging"),\r
2763                     args, 1);\r
2764     }\r
2765     if (appData.animate) {\r
2766         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),\r
2767                     args, 1);\r
2768     }\r
2769     if (appData.autoComment) {\r
2770         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),\r
2771                     args, 1);\r
2772     }\r
2773     if (appData.autoCallFlag) {\r
2774         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),\r
2775                     args, 1);\r
2776     }\r
2777     if (appData.autoFlipView) {\r
2778         XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),\r
2779                     args, 1);\r
2780     }\r
2781     if (appData.autoObserve) {\r
2782         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),\r
2783                     args, 1);\r
2784     }\r
2785     if (appData.autoRaiseBoard) {\r
2786         XtSetValues(XtNameToWidget(menuBarWidget,\r
2787                                    "menuOptions.Auto Raise Board"), args, 1);\r
2788     }\r
2789     if (appData.autoSaveGames) {\r
2790         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),\r
2791                     args, 1);\r
2792     }\r
2793     if (appData.saveGameFile[0] != NULLCHAR) {\r
2794         /* Can't turn this off from menu */\r
2795         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),\r
2796                     args, 1);\r
2797         XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),\r
2798                        False);\r
2799 \r
2800     }\r
2801     if (appData.blindfold) {\r
2802         XtSetValues(XtNameToWidget(menuBarWidget,\r
2803                                    "menuOptions.Blindfold"), args, 1);\r
2804     }\r
2805     if (appData.flashCount > 0) {\r
2806         XtSetValues(XtNameToWidget(menuBarWidget,\r
2807                                    "menuOptions.Flash Moves"),\r
2808                     args, 1);\r
2809     }\r
2810     if (appData.getMoveList) {\r
2811         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),\r
2812                     args, 1);\r
2813     }\r
2814 #if HIGHDRAG\r
2815     if (appData.highlightDragging) {\r
2816         XtSetValues(XtNameToWidget(menuBarWidget,\r
2817                                    "menuOptions.Highlight Dragging"),\r
2818                     args, 1);\r
2819     }\r
2820 #endif\r
2821     if (appData.highlightLastMove) {\r
2822         XtSetValues(XtNameToWidget(menuBarWidget,\r
2823                                    "menuOptions.Highlight Last Move"),\r
2824                     args, 1);\r
2825     }\r
2826     if (appData.icsAlarm) {\r
2827         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),\r
2828                     args, 1);\r
2829     }\r
2830     if (appData.ringBellAfterMoves) {\r
2831         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),\r
2832                     args, 1);\r
2833     }\r
2834     if (appData.oldSaveStyle) {\r
2835         XtSetValues(XtNameToWidget(menuBarWidget,\r
2836                                    "menuOptions.Old Save Style"), args, 1);\r
2837     }\r
2838     if (appData.periodicUpdates) {\r
2839         XtSetValues(XtNameToWidget(menuBarWidget,\r
2840                                    "menuOptions.Periodic Updates"), args, 1);\r
2841     }   \r
2842     if (appData.ponderNextMove) {\r
2843         XtSetValues(XtNameToWidget(menuBarWidget,\r
2844                                    "menuOptions.Ponder Next Move"), args, 1);\r
2845     }   \r
2846     if (appData.popupExitMessage) {\r
2847         XtSetValues(XtNameToWidget(menuBarWidget,\r
2848                                    "menuOptions.Popup Exit Message"), args, 1);\r
2849     }   \r
2850     if (appData.popupMoveErrors) {\r
2851         XtSetValues(XtNameToWidget(menuBarWidget,\r
2852                                    "menuOptions.Popup Move Errors"), args, 1);\r
2853     }   \r
2854     if (appData.premove) {\r
2855         XtSetValues(XtNameToWidget(menuBarWidget,\r
2856                                    "menuOptions.Premove"), args, 1);\r
2857     }\r
2858     if (appData.quietPlay) {\r
2859         XtSetValues(XtNameToWidget(menuBarWidget,\r
2860                                    "menuOptions.Quiet Play"), args, 1);\r
2861     }\r
2862     if (appData.showCoords) {\r
2863         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),\r
2864                     args, 1);\r
2865     }\r
2866     if (appData.hideThinkingFromHuman) {\r
2867         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),\r
2868                     args, 1);\r
2869     }\r
2870     if (appData.testLegality) {\r
2871         XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),\r
2872                     args, 1);\r
2873     }\r
2874 \r
2875     /*\r
2876      * Create an icon.\r
2877      */\r
2878     ReadBitmap(&wIconPixmap, "icon_white.bm",\r
2879                icon_white_bits, icon_white_width, icon_white_height);\r
2880     ReadBitmap(&bIconPixmap, "icon_black.bm",\r
2881                icon_black_bits, icon_black_width, icon_black_height);\r
2882     iconPixmap = wIconPixmap;\r
2883     i = 0;\r
2884     XtSetArg(args[i], XtNiconPixmap, iconPixmap);  i++;\r
2885     XtSetValues(shellWidget, args, i);\r
2886     \r
2887     /*\r
2888      * Create a cursor for the board widget.\r
2889      */\r
2890     window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);\r
2891     XChangeWindowAttributes(xDisplay, xBoardWindow,\r
2892                             CWCursor, &window_attributes);\r
2893     \r
2894     /*\r
2895      * Inhibit shell resizing.\r
2896      */\r
2897     shellArgs[0].value = (XtArgVal) &w;\r
2898     shellArgs[1].value = (XtArgVal) &h;\r
2899     XtGetValues(shellWidget, shellArgs, 2);\r
2900     shellArgs[4].value = shellArgs[2].value = w;\r
2901     shellArgs[5].value = shellArgs[3].value = h;\r
2902     XtSetValues(shellWidget, &shellArgs[2], 4);
2903     marginW =  w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board\r
2904     marginH =  h - boardHeight;\r
2905 \r
2906     CatchDeleteWindow(shellWidget, "QuitProc");\r
2907 \r
2908     CreateGCs();\r
2909     CreateGrid();\r
2910 #if HAVE_LIBXPM\r
2911     if (appData.bitmapDirectory[0] != NULLCHAR) {\r
2912       CreatePieces();\r
2913     } else {\r
2914       CreateXPMPieces();\r
2915     }\r
2916 #else\r
2917     CreateXIMPieces();\r
2918     /* Create regular pieces */\r
2919     if (!useImages) CreatePieces();\r
2920 #endif  \r
2921 \r
2922     CreatePieceMenus();\r
2923 \r
2924     if (appData.animate || appData.animateDragging)\r
2925       CreateAnimVars();\r
2926     \r
2927     XtAugmentTranslations(formWidget,\r
2928                           XtParseTranslationTable(globalTranslations));\r
2929     XtAugmentTranslations(boardWidget,\r
2930                           XtParseTranslationTable(boardTranslations));\r
2931     XtAugmentTranslations(whiteTimerWidget,\r
2932                           XtParseTranslationTable(whiteTranslations));\r
2933     XtAugmentTranslations(blackTimerWidget,\r
2934                           XtParseTranslationTable(blackTranslations));\r
2935 \r
2936     /* Why is the following needed on some versions of X instead\r
2937      * of a translation? */\r
2938     XtAddEventHandler(boardWidget, ExposureMask, False,\r
2939                       (XtEventHandler) EventProc, NULL);\r
2940     /* end why */\r
2941 \r
2942     InitBackEnd2();\r
2943     \r
2944     if (errorExitStatus == -1) {\r
2945         if (appData.icsActive) {\r
2946             /* We now wait until we see "login:" from the ICS before\r
2947                sending the logon script (problems with timestamp otherwise) */\r
2948             /*ICSInitScript();*/\r
2949             if (appData.icsInputBox) ICSInputBoxPopUp();\r
2950         }\r
2951 \r
2952         signal(SIGINT, IntSigHandler);\r
2953         signal(SIGTERM, IntSigHandler);\r
2954         if (*appData.cmailGameName != NULLCHAR) {\r
2955             signal(SIGUSR1, CmailSigHandler);\r
2956         }\r
2957     }\r
2958         InitPosition(TRUE);\r
2959 \r
2960     XtAppMainLoop(appContext);\r
2961     return 0;\r
2962 }\r
2963 \r
2964 void\r
2965 ShutDownFrontEnd()\r
2966 {\r
2967     if (appData.icsActive && oldICSInteractionTitle != NULL) {\r
2968         DisplayIcsInteractionTitle(oldICSInteractionTitle);\r
2969     }\r
2970     unlink(gameCopyFilename);\r
2971     unlink(gamePasteFilename);\r
2972 }\r
2973 \r
2974 RETSIGTYPE\r
2975 IntSigHandler(sig)\r
2976      int sig;\r
2977 {\r
2978     ExitEvent(sig);\r
2979 }\r
2980 \r
2981 RETSIGTYPE\r
2982 CmailSigHandler(sig)\r
2983      int sig;\r
2984 {\r
2985     int dummy = 0;\r
2986     int error;\r
2987 \r
2988     signal(SIGUSR1, SIG_IGN);   /* suspend handler     */\r
2989 \r
2990     /* Activate call-back function CmailSigHandlerCallBack()             */\r
2991     OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);\r
2992 \r
2993     signal(SIGUSR1, CmailSigHandler); /* re-activate handler */\r
2994 }\r
2995 \r
2996 void\r
2997 CmailSigHandlerCallBack(isr, closure, message, count, error)\r
2998      InputSourceRef isr;\r
2999      VOIDSTAR closure;\r
3000      char *message;\r
3001      int count;\r
3002      int error;\r
3003 {\r
3004     BoardToTop();\r
3005     ReloadCmailMsgEvent(TRUE);  /* Reload cmail msg  */\r
3006 }\r
3007 /**** end signal code ****/\r
3008 \r
3009 \r
3010 void\r
3011 ICSInitScript()\r
3012 {\r
3013     FILE *f;\r
3014     char buf[MSG_SIZ];\r
3015     char *p;\r
3016 \r
3017     f = fopen(appData.icsLogon, "r");\r
3018     if (f == NULL) {\r
3019         p = getenv("HOME");\r
3020         if (p != NULL) {\r
3021             strcpy(buf, p);\r
3022             strcat(buf, "/");\r
3023             strcat(buf, appData.icsLogon);\r
3024             f = fopen(buf, "r");\r
3025         }\r
3026     }\r
3027     if (f != NULL)\r
3028       ProcessICSInitScript(f);\r
3029 }\r
3030 \r
3031 void\r
3032 ResetFrontEnd()\r
3033 {\r
3034     CommentPopDown();\r
3035     EditCommentPopDown();\r
3036     TagsPopDown();\r
3037     return;\r
3038 }\r
3039 \r
3040 typedef struct {\r
3041     char *name;\r
3042     Boolean value;\r
3043 } Enables;\r
3044 \r
3045 void\r
3046 SetMenuEnables(enab)\r
3047      Enables *enab;\r
3048 {\r
3049   Widget w;\r
3050   if (!menuBarWidget) return;\r
3051   while (enab->name != NULL) {\r
3052     w = XtNameToWidget(menuBarWidget, enab->name);\r
3053     if (w == NULL) {\r
3054       DisplayError(enab->name, 0);\r
3055     } else {\r
3056       XtSetSensitive(w, enab->value);\r
3057     }\r
3058     enab++;\r
3059   }\r
3060 }\r
3061 \r
3062 Enables icsEnables[] = {\r
3063     { "menuFile.Mail Move", False },\r
3064     { "menuFile.Reload CMail Message", False },\r
3065     { "menuMode.Machine Black", False },\r
3066     { "menuMode.Machine White", False },\r
3067     { "menuMode.Analysis Mode", False },\r
3068     { "menuMode.Analyze File", False },\r
3069     { "menuMode.Two Machines", False },\r
3070 #ifndef ZIPPY\r
3071     { "menuHelp.Hint", False },\r
3072     { "menuHelp.Book", False },\r
3073     { "menuStep.Move Now", False },\r
3074     { "menuOptions.Periodic Updates", False },  \r
3075     { "menuOptions.Hide Thinking", False },\r
3076     { "menuOptions.Ponder Next Move", False },\r
3077 #endif\r
3078     { NULL, False }\r
3079 };\r
3080 \r
3081 Enables ncpEnables[] = {    \r
3082     { "menuFile.Mail Move", False },\r
3083     { "menuFile.Reload CMail Message", False },\r
3084     { "menuMode.Machine White", False },\r
3085     { "menuMode.Machine Black", False },\r
3086     { "menuMode.Analysis Mode", False },\r
3087     { "menuMode.Analyze File", False },\r
3088     { "menuMode.Two Machines", False },\r
3089     { "menuMode.ICS Client", False },\r
3090     { "menuMode.ICS Input Box", False },\r
3091     { "Action", False },\r
3092     { "menuStep.Revert", False },\r
3093     { "menuStep.Move Now", False },\r
3094     { "menuStep.Retract Move", False },\r
3095     { "menuOptions.Auto Comment", False },\r
3096     { "menuOptions.Auto Flag", False },\r
3097     { "menuOptions.Auto Flip View", False },\r
3098     { "menuOptions.Auto Observe", False },\r
3099     { "menuOptions.Auto Raise Board", False },\r
3100     { "menuOptions.Get Move List", False },\r
3101     { "menuOptions.ICS Alarm", False },\r
3102     { "menuOptions.Move Sound", False },\r
3103     { "menuOptions.Quiet Play", False },\r
3104     { "menuOptions.Hide Thinking", False },\r
3105     { "menuOptions.Periodic Updates", False },  \r
3106     { "menuOptions.Ponder Next Move", False },\r
3107     { "menuHelp.Hint", False },\r
3108     { "menuHelp.Book", False },\r
3109     { NULL, False }\r
3110 };\r
3111 \r
3112 Enables gnuEnables[] = {    \r
3113     { "menuMode.ICS Client", False },\r
3114     { "menuMode.ICS Input Box", False },\r
3115     { "menuAction.Accept", False },\r
3116     { "menuAction.Decline", False },\r
3117     { "menuAction.Rematch", False },\r
3118     { "menuAction.Adjourn", False },\r
3119     { "menuAction.Stop Examining", False },\r
3120     { "menuAction.Stop Observing", False },\r
3121     { "menuStep.Revert", False },\r
3122     { "menuOptions.Auto Comment", False },\r
3123     { "menuOptions.Auto Observe", False },\r
3124     { "menuOptions.Auto Raise Board", False },\r
3125     { "menuOptions.Get Move List", False },\r
3126     { "menuOptions.Premove", False },\r
3127     { "menuOptions.Quiet Play", False },\r
3128 \r
3129     /* The next two options rely on SetCmailMode being called *after*    */\r
3130     /* SetGNUMode so that when GNU is being used to give hints these     */\r
3131     /* menu options are still available                                  */\r
3132 \r
3133     { "menuFile.Mail Move", False },\r
3134     { "menuFile.Reload CMail Message", False },\r
3135     { NULL, False }\r
3136 };\r
3137 \r
3138 Enables cmailEnables[] = {    \r
3139     { "Action", True },\r
3140     { "menuAction.Call Flag", False },\r
3141     { "menuAction.Draw", True },\r
3142     { "menuAction.Adjourn", False },\r
3143     { "menuAction.Abort", False },\r
3144     { "menuAction.Stop Observing", False },\r
3145     { "menuAction.Stop Examining", False },\r
3146     { "menuFile.Mail Move", True },\r
3147     { "menuFile.Reload CMail Message", True },\r
3148     { NULL, False }\r
3149 };\r
3150 \r
3151 Enables trainingOnEnables[] = {    \r
3152   { "menuMode.Edit Comment", False },\r
3153   { "menuMode.Pause", False },\r
3154   { "menuStep.Forward", False },\r
3155   { "menuStep.Backward", False },\r
3156   { "menuStep.Forward to End", False },\r
3157   { "menuStep.Back to Start", False },\r
3158   { "menuStep.Move Now", False },\r
3159   { "menuStep.Truncate Game", False },\r
3160   { NULL, False }\r
3161 };\r
3162 \r
3163 Enables trainingOffEnables[] = {    \r
3164   { "menuMode.Edit Comment", True },\r
3165   { "menuMode.Pause", True },\r
3166   { "menuStep.Forward", True },\r
3167   { "menuStep.Backward", True },\r
3168   { "menuStep.Forward to End", True },\r
3169   { "menuStep.Back to Start", True },\r
3170   { "menuStep.Move Now", True },\r
3171   { "menuStep.Truncate Game", True },\r
3172   { NULL, False }\r
3173 };\r
3174 \r
3175 Enables machineThinkingEnables[] = {\r
3176   { "menuFile.Load Game", False },\r
3177   { "menuFile.Load Next Game", False },\r
3178   { "menuFile.Load Previous Game", False },\r
3179   { "menuFile.Reload Same Game", False },\r
3180   { "menuFile.Paste Game", False },\r
3181   { "menuFile.Load Position", False },\r
3182   { "menuFile.Load Next Position", False },\r
3183   { "menuFile.Load Previous Position", False },\r
3184   { "menuFile.Reload Same Position", False },\r
3185   { "menuFile.Paste Position", False },\r
3186   { "menuMode.Machine White", False },\r
3187   { "menuMode.Machine Black", False },\r
3188   { "menuMode.Two Machines", False },\r
3189   { "menuStep.Retract Move", False },\r
3190   { NULL, False }\r
3191 };\r
3192 \r
3193 Enables userThinkingEnables[] = {\r
3194   { "menuFile.Load Game", True },\r
3195   { "menuFile.Load Next Game", True },\r
3196   { "menuFile.Load Previous Game", True },\r
3197   { "menuFile.Reload Same Game", True },\r
3198   { "menuFile.Paste Game", True },\r
3199   { "menuFile.Load Position", True },\r
3200   { "menuFile.Load Next Position", True },\r
3201   { "menuFile.Load Previous Position", True },\r
3202   { "menuFile.Reload Same Position", True },\r
3203   { "menuFile.Paste Position", True },\r
3204   { "menuMode.Machine White", True },\r
3205   { "menuMode.Machine Black", True },\r
3206   { "menuMode.Two Machines", True },\r
3207   { "menuStep.Retract Move", True },\r
3208   { NULL, False }\r
3209 };\r
3210 \r
3211 void SetICSMode()\r
3212 {\r
3213   SetMenuEnables(icsEnables);\r
3214 }\r
3215 \r
3216 void\r
3217 SetNCPMode()\r
3218 {\r
3219   SetMenuEnables(ncpEnables);\r
3220 }\r
3221 \r
3222 void\r
3223 SetGNUMode()\r
3224 {\r
3225   SetMenuEnables(gnuEnables);\r
3226 }\r
3227 \r
3228 void\r
3229 SetCmailMode()\r
3230 {\r
3231   SetMenuEnables(cmailEnables);\r
3232 }\r
3233 \r
3234 void\r
3235 SetTrainingModeOn()\r
3236 {\r
3237   SetMenuEnables(trainingOnEnables);\r
3238   if (appData.showButtonBar) {\r
3239     XtSetSensitive(buttonBarWidget, False);\r
3240   }\r
3241   CommentPopDown();\r
3242 }\r
3243 \r
3244 void\r
3245 SetTrainingModeOff()\r
3246 {\r
3247   SetMenuEnables(trainingOffEnables);\r
3248   if (appData.showButtonBar) {\r
3249     XtSetSensitive(buttonBarWidget, True);\r
3250   }\r
3251 }\r
3252 \r
3253 void\r
3254 SetUserThinkingEnables()\r
3255 {\r
3256   if (appData.noChessProgram) return;\r
3257   SetMenuEnables(userThinkingEnables);\r
3258 }\r
3259 \r
3260 void\r
3261 SetMachineThinkingEnables()\r
3262 {\r
3263   if (appData.noChessProgram) return;\r
3264   SetMenuEnables(machineThinkingEnables);\r
3265   switch (gameMode) {\r
3266   case MachinePlaysBlack:\r
3267   case MachinePlaysWhite:\r
3268   case TwoMachinesPlay:\r
3269     XtSetSensitive(XtNameToWidget(menuBarWidget,\r
3270                                   ModeToWidgetName(gameMode)), True);\r
3271     break;\r
3272   default:\r
3273     break;\r
3274   }\r
3275 }\r
3276 \r
3277 #define Abs(n) ((n)<0 ? -(n) : (n))\r
3278 \r
3279 /*\r
3280  * Find a font that matches "pattern" that is as close as\r
3281  * possible to the targetPxlSize.  Prefer fonts that are k\r
3282  * pixels smaller to fonts that are k pixels larger.  The\r
3283  * pattern must be in the X Consortium standard format, \r
3284  * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".\r
3285  * The return value should be freed with XtFree when no\r
3286  * longer needed.\r
3287  */\r
3288 char *FindFont(pattern, targetPxlSize)\r
3289      char *pattern;\r
3290      int targetPxlSize;\r
3291 {\r
3292     char **fonts, *p, *best, *scalable, *scalableTail;\r
3293     int i, j, nfonts, minerr, err, pxlSize;\r
3294 \r
3295     fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);\r
3296     if (nfonts < 1) {\r
3297         fprintf(stderr, "%s: no fonts match pattern %s\n",\r
3298                 programName, pattern);\r
3299         exit(2);\r
3300     }\r
3301     best = fonts[0];\r
3302     scalable = NULL;\r
3303     minerr = 999999;\r
3304     for (i=0; i<nfonts; i++) {\r
3305         j = 0;\r
3306         p = fonts[i];\r
3307         if (*p != '-') continue;\r
3308         while (j < 7) {\r
3309             if (*p == NULLCHAR) break;\r
3310             if (*p++ == '-') j++;\r
3311         }\r
3312         if (j < 7) continue;\r
3313         pxlSize = atoi(p);\r
3314         if (pxlSize == 0) {\r
3315             scalable = fonts[i];\r
3316             scalableTail = p;\r
3317         } else {\r
3318             err = pxlSize - targetPxlSize;\r
3319             if (Abs(err) < Abs(minerr) ||\r
3320                 (minerr > 0 && err < 0 && -err == minerr)) {\r
3321                 best = fonts[i];\r
3322                 minerr = err;\r
3323             }\r
3324         }\r
3325     }\r
3326     if (scalable && Abs(minerr) > appData.fontSizeTolerance) {\r
3327         /* If the error is too big and there is a scalable font,\r
3328            use the scalable font. */\r
3329         int headlen = scalableTail - scalable;\r
3330         p = (char *) XtMalloc(strlen(scalable) + 10);\r
3331         while (isdigit(*scalableTail)) scalableTail++;\r
3332         sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);\r
3333     } else {\r
3334         p = (char *) XtMalloc(strlen(best) + 1);\r
3335         strcpy(p, best);\r
3336     }\r
3337     if (appData.debugMode) {\r
3338         fprintf(debugFP, "resolved %s at pixel size %d\n  to %s\n",\r
3339                 pattern, targetPxlSize, p);\r
3340     }\r
3341     XFreeFontNames(fonts);\r
3342     return p;\r
3343 }\r
3344 \r
3345 void CreateGCs()\r
3346 {\r
3347     XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground\r
3348       | GCBackground | GCFunction | GCPlaneMask;\r
3349     XGCValues gc_values;\r
3350     GC copyInvertedGC;\r
3351     \r
3352     gc_values.plane_mask = AllPlanes;\r
3353     gc_values.line_width = lineGap;\r
3354     gc_values.line_style = LineSolid;\r
3355     gc_values.function = GXcopy;\r
3356     \r
3357     gc_values.foreground = XBlackPixel(xDisplay, xScreen);\r
3358     gc_values.background = XBlackPixel(xDisplay, xScreen);\r
3359     lineGC = XtGetGC(shellWidget, value_mask, &gc_values);\r
3360     \r
3361     gc_values.foreground = XBlackPixel(xDisplay, xScreen);\r
3362     gc_values.background = XWhitePixel(xDisplay, xScreen);\r
3363     coordGC = XtGetGC(shellWidget, value_mask, &gc_values);\r
3364     XSetFont(xDisplay, coordGC, coordFontID);\r
3365     \r
3366     // [HGM] make font for holdings counts (white on black0
3367     gc_values.foreground = XWhitePixel(xDisplay, xScreen);\r
3368     gc_values.background = XBlackPixel(xDisplay, xScreen);\r
3369     countGC = XtGetGC(shellWidget, value_mask, &gc_values);\r
3370     XSetFont(xDisplay, countGC, countFontID);\r
3371     \r
3372     if (appData.monoMode) {\r
3373         gc_values.foreground = XWhitePixel(xDisplay, xScreen);\r
3374         gc_values.background = XWhitePixel(xDisplay, xScreen);\r
3375         highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);      \r
3376 \r
3377         gc_values.foreground = XWhitePixel(xDisplay, xScreen);\r
3378         gc_values.background = XBlackPixel(xDisplay, xScreen);\r
3379         lightSquareGC = wbPieceGC \r
3380           = XtGetGC(shellWidget, value_mask, &gc_values);\r
3381 \r
3382         gc_values.foreground = XBlackPixel(xDisplay, xScreen);\r
3383         gc_values.background = XWhitePixel(xDisplay, xScreen);\r
3384         darkSquareGC = bwPieceGC\r
3385           = XtGetGC(shellWidget, value_mask, &gc_values);\r
3386 \r
3387         if (DefaultDepth(xDisplay, xScreen) == 1) {\r
3388             /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */\r
3389             gc_values.function = GXcopyInverted;\r
3390             copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);\r
3391             gc_values.function = GXcopy;\r
3392             if (XBlackPixel(xDisplay, xScreen) == 1) {\r
3393                 bwPieceGC = darkSquareGC;\r
3394                 wbPieceGC = copyInvertedGC;\r
3395             } else {\r
3396                 bwPieceGC = copyInvertedGC;\r
3397                 wbPieceGC = lightSquareGC;\r
3398             }\r
3399         }\r
3400     } else {\r
3401         gc_values.foreground = highlightSquareColor;\r
3402         gc_values.background = highlightSquareColor;\r
3403         highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);      \r
3404 \r
3405         gc_values.foreground = premoveHighlightColor;\r
3406         gc_values.background = premoveHighlightColor;\r
3407         prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);       \r
3408 \r
3409         gc_values.foreground = lightSquareColor;\r
3410         gc_values.background = darkSquareColor;\r
3411         lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);\r
3412         \r
3413         gc_values.foreground = darkSquareColor;\r
3414         gc_values.background = lightSquareColor;\r
3415         darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);\r
3416 \r
3417         gc_values.foreground = jailSquareColor;\r
3418         gc_values.background = jailSquareColor;\r
3419         jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);\r
3420 \r
3421         gc_values.foreground = whitePieceColor;\r
3422         gc_values.background = darkSquareColor;\r
3423         wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);\r
3424         \r
3425         gc_values.foreground = whitePieceColor;\r
3426         gc_values.background = lightSquareColor;\r
3427         wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);\r
3428         \r
3429         gc_values.foreground = whitePieceColor;\r
3430         gc_values.background = jailSquareColor;\r
3431         wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);\r
3432         \r
3433         gc_values.foreground = blackPieceColor;\r
3434         gc_values.background = darkSquareColor;\r
3435         bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);\r
3436         \r
3437         gc_values.foreground = blackPieceColor;\r
3438         gc_values.background = lightSquareColor;\r
3439         blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);\r
3440 \r
3441         gc_values.foreground = blackPieceColor;\r
3442         gc_values.background = jailSquareColor;\r
3443         bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);\r
3444     }\r
3445 }\r
3446 \r
3447 void loadXIM(xim, xmask, filename, dest, mask)\r
3448      XImage *xim;\r
3449      XImage *xmask;\r
3450      char *filename;\r
3451      Pixmap *dest;\r
3452      Pixmap *mask;\r
3453 {\r
3454     int x, y, w, h, p;\r
3455     FILE *fp;\r
3456     Pixmap temp;\r
3457     XGCValues   values;\r
3458     GC maskGC;\r
3459 \r
3460     fp = fopen(filename, "rb");\r
3461     if (!fp) {\r
3462         fprintf(stderr, "%s: error loading XIM!\n", programName);\r
3463         exit(1);\r
3464     }\r
3465           \r
3466     w = fgetc(fp);\r
3467     h = fgetc(fp);\r
3468   \r
3469     for (y=0; y<h; ++y) {\r
3470         for (x=0; x<h; ++x) {\r
3471             p = fgetc(fp);\r
3472 \r
3473             switch (p) {\r
3474               case 0:   \r
3475                 XPutPixel(xim, x, y, blackPieceColor); \r
3476                 if (xmask)\r
3477                   XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));\r
3478                 break;\r
3479               case 1:   \r
3480                 XPutPixel(xim, x, y, darkSquareColor); \r
3481                 if (xmask)\r
3482                   XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));\r
3483                 break;\r
3484               case 2:   \r
3485                 XPutPixel(xim, x, y, whitePieceColor); \r
3486                 if (xmask)\r
3487                   XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));\r
3488                 break;\r
3489               case 3:   \r
3490                 XPutPixel(xim, x, y, lightSquareColor);\r
3491                 if (xmask)\r
3492                   XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));\r
3493                 break;\r
3494             }\r
3495         }\r
3496     }\r
3497 \r
3498     /* create Pixmap of piece */\r
3499     *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),\r
3500                           w, h, xim->depth);\r
3501     XPutImage(xDisplay, *dest, lightSquareGC, xim,\r
3502               0, 0, 0, 0, w, h);  \r
3503 \r
3504     /* create Pixmap of clipmask \r
3505        Note: We assume the white/black pieces have the same\r
3506              outline, so we make only 6 masks. This is okay\r
3507              since the XPM clipmask routines do the same. */\r
3508     if (xmask) {\r
3509       temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),\r
3510                             w, h, xim->depth);\r
3511       XPutImage(xDisplay, temp, lightSquareGC, xmask,\r
3512               0, 0, 0, 0, w, h);  \r
3513 \r
3514       /* now create the 1-bit version */\r
3515       *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),\r
3516                           w, h, 1);\r
3517 \r
3518       values.foreground = 1;\r
3519       values.background = 0;\r
3520 \r
3521       /* Don't use XtGetGC, not read only */\r
3522       maskGC = XCreateGC(xDisplay, *mask, \r
3523                     GCForeground | GCBackground, &values);\r
3524       XCopyPlane(xDisplay, temp, *mask, maskGC, \r
3525                   0, 0, squareSize, squareSize, 0, 0, 1);\r
3526       XFreePixmap(xDisplay, temp);\r
3527     }\r
3528 }\r
3529 \r
3530 void CreateXIMPieces()\r
3531 {\r
3532     int piece, kind;\r
3533     char buf[MSG_SIZ];\r
3534     u_int ss;\r
3535     static char *ximkind[] = { "ll", "ld", "dl", "dd" };\r
3536     XImage *ximtemp;\r
3537 \r
3538     ss = squareSize;\r
3539 \r
3540     /* The XSynchronize calls were copied from CreatePieces.\r
3541        Not sure if needed, but can't hurt */\r
3542     XSynchronize(xDisplay, True); /* Work-around for xlib/xt\r
3543                                      buffering bug */\r
3544   \r
3545     /* temp needed by loadXIM() */\r
3546     ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),\r
3547                  0, 0, ss, ss, AllPlanes, XYPixmap);\r
3548 \r
3549     if (strlen(appData.pixmapDirectory) == 0) {\r
3550       useImages = 0;\r
3551     } else {\r
3552         useImages = 1;\r
3553         if (appData.monoMode) {\r
3554           DisplayFatalError("XIM pieces cannot be used in monochrome mode",\r
3555                             0, 2);\r
3556           ExitEvent(2);\r
3557         }\r
3558         fprintf(stderr, "\nLoading XIMs...\n");\r
3559         /* Load pieces */\r
3560         for (piece = (int) WhitePawn; piece <= (int) WhiteKing; piece++) {\r
3561             fprintf(stderr, "%d", piece+1);\r
3562             for (kind=0; kind<4; kind++) {\r
3563                 fprintf(stderr, ".");\r
3564                 sprintf(buf, "%s/%c%s%u.xim",\r
3565                         ExpandPathName(appData.pixmapDirectory),\r
3566                         ToLower(PieceToChar((ChessSquare)piece)),\r
3567                         ximkind[kind], ss);\r
3568                 ximPieceBitmap[kind][piece] =\r
3569                   XGetImage(xDisplay, DefaultRootWindow(xDisplay),\r
3570                             0, 0, ss, ss, AllPlanes, XYPixmap);\r
3571                 if (appData.debugMode)\r
3572                   fprintf(stderr, "(File:%s:) ", buf);\r
3573                 loadXIM(ximPieceBitmap[kind][piece], \r
3574                         ximtemp, buf,\r
3575                         &(xpmPieceBitmap[kind][piece]),\r
3576                         &(ximMaskPm[piece%(int)BlackPawn]));\r
3577             }\r
3578             fprintf(stderr," ");\r
3579         }\r
3580         /* Load light and dark squares */\r
3581         /* If the LSQ and DSQ pieces don't exist, we will \r
3582            draw them with solid squares. */\r
3583         sprintf(buf, "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);\r
3584         if (access(buf, 0) != 0) {\r
3585             useImageSqs = 0;\r
3586         } else {\r
3587             useImageSqs = 1;\r
3588             fprintf(stderr, "light square ");\r
3589             ximLightSquare= \r
3590               XGetImage(xDisplay, DefaultRootWindow(xDisplay),\r
3591                         0, 0, ss, ss, AllPlanes, XYPixmap);\r
3592             if (appData.debugMode)\r
3593               fprintf(stderr, "(File:%s:) ", buf);\r
3594 \r
3595             loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);\r
3596             fprintf(stderr, "dark square ");\r
3597             sprintf(buf, "%s/dsq%u.xim",\r
3598                     ExpandPathName(appData.pixmapDirectory), ss);\r
3599             if (appData.debugMode)\r
3600               fprintf(stderr, "(File:%s:) ", buf);\r
3601             ximDarkSquare= \r
3602               XGetImage(xDisplay, DefaultRootWindow(xDisplay),\r
3603                         0, 0, ss, ss, AllPlanes, XYPixmap);\r
3604             loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);\r
3605             xpmJailSquare = xpmLightSquare;\r
3606         }\r
3607         fprintf(stderr, "Done.\n");\r
3608     }\r
3609     XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */\r
3610 }\r
3611 \r
3612 #if HAVE_LIBXPM\r
3613 void CreateXPMPieces()\r
3614 {\r
3615     int piece, kind, r;\r
3616     char buf[MSG_SIZ];\r
3617     u_int ss = squareSize;\r
3618     XpmAttributes attr;\r
3619     static char *xpmkind[] = { "ll", "ld", "dl", "dd" };\r
3620     XpmColorSymbol symbols[4];\r
3621 \r
3622 #if 0\r
3623     /* Apparently some versions of Xpm don't define XpmFormat at all --tpm */\r
3624     if (appData.debugMode) {\r
3625         fprintf(stderr, "XPM Library Version: %d.%d%c\n", \r
3626                 XpmFormat, XpmVersion, (char)('a' + XpmRevision - 1));\r
3627     }\r
3628 #endif\r
3629   \r
3630     /* The XSynchronize calls were copied from CreatePieces.\r
3631        Not sure if needed, but can't hurt */\r
3632     XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */\r
3633   \r
3634     /* Setup translations so piece colors match square colors */\r
3635     symbols[0].name = "light_piece";\r
3636     symbols[0].value = appData.whitePieceColor;\r
3637     symbols[1].name = "dark_piece";\r
3638     symbols[1].value = appData.blackPieceColor;\r
3639     symbols[2].name = "light_square";\r
3640     symbols[2].value = appData.lightSquareColor;\r
3641     symbols[3].name = "dark_square";\r
3642     symbols[3].value = appData.darkSquareColor;\r
3643 \r
3644     attr.valuemask = XpmColorSymbols;\r
3645     attr.colorsymbols = symbols;\r
3646     attr.numsymbols = 4;\r
3647 \r
3648     if (appData.monoMode) {\r
3649       DisplayFatalError("XPM pieces cannot be used in monochrome mode",\r
3650                         0, 2);\r
3651       ExitEvent(2);\r
3652     }\r
3653     if (strlen(appData.pixmapDirectory) == 0) {\r
3654         XpmPieces* pieces = builtInXpms;\r
3655         useImages = 1;\r
3656         /* Load pieces */\r
3657         while (pieces->size != squareSize && pieces->size) pieces++;\r
3658         if (!pieces->size) {\r
3659           fprintf(stderr, "No builtin XPM pieces of size %d\n", squareSize);\r
3660           exit(1);\r
3661         }\r
3662         for (piece = (int) WhitePawn; piece <= (int) WhiteKing; piece++) {\r
3663             for (kind=0; kind<4; kind++) {\r
3664 \r
3665                 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,\r
3666                                                pieces->xpm[piece][kind],\r
3667                                                &(xpmPieceBitmap[kind][piece]),\r
3668                                                NULL, &attr)) != 0) {\r
3669                   fprintf(stderr, "Error %d loading XPM image \"%s\"\n",\r
3670                           r, buf);\r
3671                   exit(1); \r
3672                 }       \r
3673             }   \r
3674         }\r
3675         useImageSqs = 0;\r
3676         xpmJailSquare = xpmLightSquare;\r
3677     } else {\r
3678         useImages = 1;\r
3679         \r
3680         fprintf(stderr, "\nLoading XPMs...\n");\r
3681 \r
3682         /* Load pieces */\r
3683         for (piece = (int) WhitePawn; piece <= (int) WhiteKing; piece++) {\r
3684             fprintf(stderr, "%d ", piece+1);\r
3685             for (kind=0; kind<4; kind++) {\r
3686                 sprintf(buf, "%s/%c%s%u.xpm",\r
3687                         ExpandPathName(appData.pixmapDirectory),\r
3688                         ToLower(PieceToChar((ChessSquare)piece)),\r
3689                         xpmkind[kind], ss);\r
3690                 if (appData.debugMode) {\r
3691                     fprintf(stderr, "(File:%s:) ", buf);\r
3692                 }\r
3693                 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,\r
3694                                            &(xpmPieceBitmap[kind][piece]),\r
3695                                            NULL, &attr)) != 0) {\r
3696                     fprintf(stderr, "Error %d loading XPM file \"%s\"\n",\r
3697                             r, buf);\r
3698                     exit(1); \r
3699                 }       \r
3700             }   \r
3701         }\r
3702         /* Load light and dark squares */\r
3703         /* If the LSQ and DSQ pieces don't exist, we will \r
3704            draw them with solid squares. */\r
3705         fprintf(stderr, "light square ");\r
3706         sprintf(buf, "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);\r
3707         if (access(buf, 0) != 0) {\r
3708             useImageSqs = 0;\r
3709         } else {\r
3710             useImageSqs = 1;\r
3711             if (appData.debugMode)\r
3712               fprintf(stderr, "(File:%s:) ", buf);\r
3713 \r
3714             if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,\r
3715                                        &xpmLightSquare, NULL, &attr)) != 0) {\r
3716                 fprintf(stderr, "Error %d loading XPM file \"%s\"\n", r, buf);\r
3717                 exit(1);\r
3718             }\r
3719             fprintf(stderr, "dark square ");\r
3720             sprintf(buf, "%s/dsq%u.xpm",\r
3721                     ExpandPathName(appData.pixmapDirectory), ss);\r
3722             if (appData.debugMode) {\r
3723                 fprintf(stderr, "(File:%s:) ", buf);\r
3724             }\r
3725             if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,\r
3726                                        &xpmDarkSquare, NULL, &attr)) != 0) {\r
3727                 fprintf(stderr, "Error %d loading XPM file \"%s\"\n", r, buf);\r
3728                 exit(1);\r
3729             }\r
3730         }\r
3731         xpmJailSquare = xpmLightSquare;\r
3732         fprintf(stderr, "Done.\n");\r
3733     }\r
3734     XSynchronize(xDisplay, False); /* Work-around for xlib/xt\r
3735                                       buffering bug */  \r
3736 }\r
3737 #endif /* HAVE_LIBXPM */\r
3738 \r
3739 #if HAVE_LIBXPM\r
3740 /* No built-in bitmaps */\r
3741 void CreatePieces()\r
3742 {\r
3743     int piece, kind;\r
3744     char buf[MSG_SIZ];\r
3745     u_int ss = squareSize;\r
3746         \r
3747     XSynchronize(xDisplay, True); /* Work-around for xlib/xt\r
3748                                      buffering bug */\r
3749 \r
3750     for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {\r
3751         for (piece = (int) WhitePawn; piece <= (int) WhiteKing; piece++) {\r
3752             sprintf(buf, "%c%u%c.bm", ToLower(PieceToChar((ChessSquare)piece)),\r
3753                     ss, kind == SOLID ? 's' : 'o');\r
3754             ReadBitmap(&pieceBitmap[kind][piece], buf, NULL, ss, ss);\r
3755         }\r
3756     }\r
3757     \r
3758     XSynchronize(xDisplay, False); /* Work-around for xlib/xt\r
3759                                       buffering bug */\r
3760 }\r
3761 #else\r
3762 /* With built-in bitmaps */\r
3763 void CreatePieces()\r
3764 {\r
3765     BuiltInBits* bib = builtInBits;\r
3766     int piece, kind;\r
3767     char buf[MSG_SIZ];\r
3768     u_int ss = squareSize;\r
3769         \r
3770     XSynchronize(xDisplay, True); /* Work-around for xlib/xt\r
3771                                      buffering bug */\r
3772 \r
3773     while (bib->squareSize != ss && bib->squareSize != 0) bib++;\r
3774 \r
3775     for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {\r
3776         for (piece = (int) WhitePawn; piece <= (int) WhiteKing; piece++) {\r
3777             sprintf(buf, "%c%u%c.bm", ToLower(PieceToChar((ChessSquare)piece)),\r
3778                     ss, kind == SOLID ? 's' : 'o');\r
3779             ReadBitmap(&pieceBitmap[kind][piece], buf,\r
3780                        bib->bits[kind][piece], ss, ss);\r
3781         }\r
3782     }\r
3783     \r
3784     XSynchronize(xDisplay, False); /* Work-around for xlib/xt\r
3785                                       buffering bug */\r
3786 }\r
3787 #endif\r
3788 \r
3789 void ReadBitmap(pm, name, bits, wreq, hreq)\r
3790      Pixmap *pm;\r
3791      String name;\r
3792      unsigned char bits[];\r
3793      u_int wreq, hreq;\r
3794 {\r
3795     int x_hot, y_hot;\r
3796     u_int w, h;\r
3797     int errcode;\r
3798     char msg[MSG_SIZ], fullname[MSG_SIZ];\r
3799     \r
3800     if (*appData.bitmapDirectory != NULLCHAR) {\r
3801         strcpy(fullname, appData.bitmapDirectory);\r
3802         strcat(fullname, "/");\r
3803         strcat(fullname, name);\r
3804         errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,\r
3805                                   &w, &h, pm, &x_hot, &y_hot);\r
3806         if (errcode != BitmapSuccess) {\r
3807             switch (errcode) {\r
3808               case BitmapOpenFailed:\r
3809                 sprintf(msg, "Can't open bitmap file %s", fullname);\r
3810                 break;\r
3811               case BitmapFileInvalid:\r
3812                 sprintf(msg, "Invalid bitmap in file %s", fullname);\r
3813                 break;\r
3814               case BitmapNoMemory:\r
3815                 sprintf(msg, "Ran out of memory reading bitmap file %s",\r
3816                         fullname);\r
3817                 break;\r
3818               default:\r
3819                 sprintf(msg, "Unknown XReadBitmapFile error %d on file %s",\r
3820                         errcode, fullname);\r
3821                 break;\r
3822             }\r
3823             fprintf(stderr, "%s: %s...using built-in\n",\r
3824                     programName, msg);\r
3825         } else if (w != wreq || h != hreq) {\r
3826             fprintf(stderr,\r
3827                     "%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n",\r
3828                     programName, fullname, w, h, wreq, hreq);\r
3829         } else {\r
3830             return;\r
3831         }\r
3832     }\r
3833     if (bits == NULL) {\r
3834 #if 0\r
3835         fprintf(stderr, "%s: No built-in bitmap for %s; giving up\n",\r
3836                 programName, name);\r
3837         exit(1);\r
3838 #endif\r
3839         ; // [HGM] bitmaps: make it non-fatal if we have no bitmap;\r
3840     } else {\r
3841         *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,\r
3842                                     wreq, hreq);\r
3843     }\r
3844 }\r
3845 \r
3846 void CreateGrid()\r
3847 {\r
3848     int i, j;\r
3849     \r
3850     if (lineGap == 0) return;\r
3851 \r
3852     /* [HR] Split this into 2 loops for non-square boards. */\r
3853 \r
3854     for (i = 0; i < BOARD_HEIGHT + 1; i++) {\r
3855         gridSegments[i].x1 = 0;\r
3856         gridSegments[i].x2 =\r
3857           lineGap + BOARD_WIDTH * (squareSize + lineGap);\r
3858         gridSegments[i].y1 = gridSegments[i].y2\r
3859           = lineGap / 2 + (i * (squareSize + lineGap));\r
3860     }\r
3861 \r
3862     for (j = 0; j < BOARD_WIDTH + 1; j++) {\r
3863         gridSegments[j + i].y1 = 0;\r
3864         gridSegments[j + i].y2 =\r
3865           lineGap + BOARD_HEIGHT * (squareSize + lineGap);\r
3866         gridSegments[j + i].x1 = gridSegments[j + i].x2\r
3867           = lineGap / 2 + (j * (squareSize + lineGap));\r
3868     }\r
3869 }\r
3870 \r
3871 static void MenuBarSelect(w, addr, index)\r
3872      Widget w;\r
3873      caddr_t addr;\r
3874      caddr_t index;\r
3875 {\r
3876     XtActionProc proc = (XtActionProc) addr;\r
3877 \r
3878     (proc)(NULL, NULL, NULL, NULL);\r
3879 }\r
3880 \r
3881 void CreateMenuBarPopup(parent, name, mb)\r
3882      Widget parent;\r
3883      String name;\r
3884      Menu *mb;\r
3885 {\r
3886     int j;\r
3887     Widget menu, entry;\r
3888     MenuItem *mi;\r
3889     Arg args[16];\r
3890 \r
3891     menu = XtCreatePopupShell(name, simpleMenuWidgetClass,\r
3892                               parent, NULL, 0);\r
3893     j = 0;\r
3894     XtSetArg(args[j], XtNleftMargin, 20);   j++;\r
3895     XtSetArg(args[j], XtNrightMargin, 20);  j++;\r
3896     mi = mb->mi;\r
3897     while (mi->string != NULL) {\r
3898         if (strcmp(mi->string, "----") == 0) {\r
3899             entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,\r
3900                                           menu, args, j);\r
3901         } else {\r
3902             entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,\r
3903                                           menu, args, j);\r
3904             XtAddCallback(entry, XtNcallback,\r
3905                           (XtCallbackProc) MenuBarSelect,\r
3906                           (caddr_t) mi->proc);\r
3907         }\r
3908         mi++;\r
3909     }\r
3910 }       \r
3911 \r
3912 Widget CreateMenuBar(mb)\r
3913      Menu *mb;\r
3914 {\r
3915     int j;\r
3916     Widget anchor, menuBar;\r
3917     Arg args[16];\r
3918     char menuName[MSG_SIZ];\r
3919 \r
3920     j = 0;\r
3921     XtSetArg(args[j], XtNorientation, XtorientHorizontal);  j++;\r
3922     XtSetArg(args[j], XtNvSpace, 0);                        j++;\r
3923     XtSetArg(args[j], XtNborderWidth, 0);                   j++;\r
3924     menuBar = XtCreateWidget("menuBar", boxWidgetClass,\r
3925                              formWidget, args, j);\r
3926 \r
3927     while (mb->name != NULL) {\r
3928         strcpy(menuName, "menu");\r
3929         strcat(menuName, mb->name);\r
3930         j = 0;\r
3931         XtSetArg(args[j], XtNmenuName, XtNewString(menuName));  j++;\r
3932         if (tinyLayout) {\r
3933             char shortName[2];\r
3934             shortName[0] = mb->name[0];\r
3935             shortName[1] = NULLCHAR;\r
3936             XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;\r
3937         }\r
3938         XtSetArg(args[j], XtNborderWidth, 0);                   j++;\r
3939         anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,\r
3940                                        menuBar, args, j);\r
3941         CreateMenuBarPopup(menuBar, menuName, mb);\r
3942         mb++;\r
3943     }\r
3944     return menuBar;\r
3945 }\r
3946 \r
3947 Widget CreateButtonBar(mi)\r
3948      MenuItem *mi;\r
3949 {\r
3950     int j;\r
3951     Widget button, buttonBar;\r
3952     Arg args[16];\r
3953 \r
3954     j = 0;\r
3955     XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;\r
3956     if (tinyLayout) {\r
3957         XtSetArg(args[j], XtNhSpace, 0); j++;\r
3958     }\r
3959     XtSetArg(args[j], XtNborderWidth, 0); j++;\r
3960     XtSetArg(args[j], XtNvSpace, 0);                        j++;\r
3961     buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,\r
3962                                formWidget, args, j);\r
3963 \r
3964     while (mi->string != NULL) {\r
3965         j = 0;\r
3966         if (tinyLayout) {\r
3967             XtSetArg(args[j], XtNinternalWidth, 2); j++;\r
3968             XtSetArg(args[j], XtNborderWidth, 0); j++;\r
3969         }\r
3970         button = XtCreateManagedWidget(mi->string, commandWidgetClass,\r
3971                                        buttonBar, args, j);\r
3972         XtAddCallback(button, XtNcallback,\r
3973                       (XtCallbackProc) MenuBarSelect,\r
3974                       (caddr_t) mi->proc);\r
3975         mi++;\r
3976     }\r
3977     return buttonBar;\r
3978 }     \r
3979 \r
3980 Widget\r
3981 CreatePieceMenu(name, color)\r
3982      char *name;\r
3983      int color;\r
3984 {\r
3985     int i;\r
3986     Widget entry, menu;\r
3987     Arg args[16];\r
3988     ChessSquare selection;\r
3989 \r
3990     menu = XtCreatePopupShell(name, simpleMenuWidgetClass,\r
3991                               boardWidget, args, 0);\r
3992     \r
3993     for (i = 0; i < PIECE_MENU_SIZE; i++) {\r
3994         String item = pieceMenuStrings[color][i];\r
3995         \r
3996         if (strcmp(item, "----") == 0) {\r
3997             entry = XtCreateManagedWidget(item, smeLineObjectClass,\r
3998                                           menu, NULL, 0);\r
3999         } else {\r
4000             entry = XtCreateManagedWidget(item, smeBSBObjectClass,\r
4001                                           menu, NULL, 0);\r
4002             selection = pieceMenuTranslation[color][i];\r
4003             XtAddCallback(entry, XtNcallback,\r
4004                           (XtCallbackProc) PieceMenuSelect,\r
4005                           (caddr_t) selection);\r
4006             if (selection == WhitePawn || selection == BlackPawn) {\r
4007                 XtSetArg(args[0], XtNpopupOnEntry, entry);\r
4008                 XtSetValues(menu, args, 1);\r
4009             }\r
4010         }\r
4011     }\r
4012     return menu;\r
4013 }\r
4014 \r
4015 void\r
4016 CreatePieceMenus()\r
4017 {\r
4018     int i;\r
4019     Widget entry;\r
4020     Arg args[16];\r
4021     ChessSquare selection;\r
4022 \r
4023     whitePieceMenu = CreatePieceMenu("menuW", 0);\r
4024     blackPieceMenu = CreatePieceMenu("menuB", 1);\r
4025     \r
4026     XtRegisterGrabAction(PieceMenuPopup, True,\r
4027                          (unsigned)(ButtonPressMask|ButtonReleaseMask),\r
4028                          GrabModeAsync, GrabModeAsync);\r
4029 \r
4030     XtSetArg(args[0], XtNlabel, "Drop");\r
4031     dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,\r
4032                                   boardWidget, args, 1);\r
4033     for (i = 0; i < DROP_MENU_SIZE; i++) {\r
4034         String item = dropMenuStrings[i];\r
4035         \r
4036         if (strcmp(item, "----") == 0) {\r
4037             entry = XtCreateManagedWidget(item, smeLineObjectClass,\r
4038                                           dropMenu, NULL, 0);\r
4039         } else {\r
4040             entry = XtCreateManagedWidget(item, smeBSBObjectClass,\r
4041                                           dropMenu, NULL, 0);\r
4042             selection = dropMenuTranslation[i];\r
4043             XtAddCallback(entry, XtNcallback,\r
4044                           (XtCallbackProc) DropMenuSelect,\r
4045                           (caddr_t) selection);\r
4046         }\r
4047     }\r
4048 }       \r
4049 \r
4050 void SetupDropMenu()\r
4051 {\r
4052     int i, j, count;\r
4053     char label[32];\r
4054     Arg args[16];\r
4055     Widget entry;\r
4056     char* p;\r
4057 \r
4058     for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {\r
4059         entry = XtNameToWidget(dropMenu, dmEnables[i].widget);\r
4060         p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,\r
4061                    dmEnables[i].piece);\r
4062         XtSetSensitive(entry, p != NULL || !appData.testLegality\r
4063                        /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse\r
4064                                        && !appData.icsActive));\r
4065         count = 0;\r
4066         while (p && *p++ == dmEnables[i].piece) count++;\r
4067         sprintf(label, "%s  %d", dmEnables[i].widget, count);\r
4068         j = 0;\r
4069         XtSetArg(args[j], XtNlabel, label); j++;\r
4070         XtSetValues(entry, args, j);\r
4071     }\r
4072 }\r
4073 \r
4074 void PieceMenuPopup(w, event, params, num_params)\r
4075      Widget w;\r
4076      XEvent *event;\r
4077      String *params;\r
4078      Cardinal *num_params;\r
4079 {\r
4080     String whichMenu;\r
4081     if (event->type != ButtonPress) return;\r
4082     if (errorUp) ErrorPopDown();\r
4083     switch (gameMode) {\r
4084       case EditPosition:\r
4085       case IcsExamining:\r
4086         whichMenu = params[0];\r
4087         break;\r
4088       case IcsPlayingWhite:\r
4089       case IcsPlayingBlack:\r
4090       case EditGame:\r
4091       case MachinePlaysWhite:\r
4092       case MachinePlaysBlack:\r
4093         if (appData.testLegality &&\r
4094             gameInfo.variant != VariantBughouse &&\r
4095             gameInfo.variant != VariantCrazyhouse) return;\r
4096         SetupDropMenu();\r
4097         whichMenu = "menuD";\r
4098         break;\r
4099       default:\r
4100         return;\r
4101     }\r
4102     \r
4103     if (((pmFromX = EventToSquare(event->xbutton.x, BOARD_WIDTH)) < 0) ||\r
4104         ((pmFromY = EventToSquare(event->xbutton.y, BOARD_HEIGHT)) < 0)) {\r
4105         pmFromX = pmFromY = -1;\r
4106         return;\r
4107     }\r
4108     if (flipView)\r
4109       pmFromX = BOARD_WIDTH - 1 - pmFromX;\r
4110     else\r
4111       pmFromY = BOARD_HEIGHT - 1 - pmFromY;\r
4112     \r
4113     XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));\r
4114 }\r
4115 \r
4116 static void PieceMenuSelect(w, piece, junk)\r
4117      Widget w;\r
4118      ChessSquare piece;\r
4119      caddr_t junk;\r
4120 {\r
4121     if (pmFromX < 0 || pmFromY < 0) return;\r
4122     EditPositionMenuEvent(piece, pmFromX, pmFromY);\r
4123 }\r
4124 \r
4125 static void DropMenuSelect(w, piece, junk)\r
4126      Widget w;\r
4127      ChessSquare piece;\r
4128      caddr_t junk;\r
4129 {\r
4130     if (pmFromX < 0 || pmFromY < 0) return;\r
4131     DropMenuEvent(piece, pmFromX, pmFromY);\r
4132 }\r
4133 \r
4134 void WhiteClock(w, event, prms, nprms)\r
4135      Widget w;\r
4136      XEvent *event;\r
4137      String *prms;\r
4138      Cardinal *nprms;\r
4139 {\r
4140     if (gameMode == EditPosition || gameMode == IcsExamining) {\r
4141         SetWhiteToPlayEvent();\r
4142     } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {\r
4143         CallFlagEvent();\r
4144     }\r
4145 }\r
4146 \r
4147 void BlackClock(w, event, prms, nprms)\r
4148      Widget w;\r
4149      XEvent *event;\r
4150      String *prms;\r
4151      Cardinal *nprms;\r
4152 {\r
4153     if (gameMode == EditPosition || gameMode == IcsExamining) {\r
4154         SetBlackToPlayEvent();\r
4155     } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {\r
4156         CallFlagEvent();\r
4157     }\r
4158 }\r
4159 \r
4160 \r
4161 /*\r
4162  * If the user selects on a border boundary, return -1; if off the board,\r
4163  *   return -2.  Otherwise map the event coordinate to the square.\r
4164  */\r
4165 int EventToSquare(x, limit)\r
4166      int x;\r
4167 {\r
4168     if (x <= 0) \r
4169       return -2;\r
4170     if (x < lineGap)\r
4171       return -1;\r
4172     x -= lineGap;\r
4173     if ((x % (squareSize + lineGap)) >= squareSize)\r
4174       return -1;\r
4175     x /= (squareSize + lineGap);\r
4176     if (x >= limit)\r
4177       return -2;\r
4178     return x;\r
4179 }\r
4180 \r
4181 static void do_flash_delay(msec)\r
4182      unsigned long msec;\r
4183 {\r
4184     TimeDelay(msec);\r
4185 }\r
4186 \r
4187 static void drawHighlight(file, rank, gc)\r
4188      int file, rank;\r
4189      GC gc;\r
4190 {\r
4191     int x, y;\r
4192 \r
4193     if (lineGap == 0 || appData.blindfold) return;\r
4194     \r
4195     if (flipView) {\r
4196         x = lineGap/2 + ((BOARD_WIDTH-1)-file) * \r
4197           (squareSize + lineGap);\r
4198         y = lineGap/2 + rank * (squareSize + lineGap);\r
4199     } else {\r
4200         x = lineGap/2 + file * (squareSize + lineGap);\r
4201         y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) * \r
4202           (squareSize + lineGap);\r
4203     }\r
4204     \r
4205     XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,\r
4206                    squareSize+lineGap, squareSize+lineGap);\r
4207 }\r
4208 \r
4209 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;\r
4210 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;\r
4211 \r
4212 void\r
4213 SetHighlights(fromX, fromY, toX, toY)\r
4214      int fromX, fromY, toX, toY;\r
4215 {\r
4216     if (hi1X != fromX || hi1Y != fromY) {\r
4217         if (hi1X >= 0 && hi1Y >= 0) {\r
4218             drawHighlight(hi1X, hi1Y, lineGC);\r
4219         }\r
4220         if (fromX >= 0 && fromY >= 0) {\r
4221             drawHighlight(fromX, fromY, highlineGC);\r
4222         }\r
4223     }\r
4224     if (hi2X != toX || hi2Y != toY) {\r
4225         if (hi2X >= 0 && hi2Y >= 0) {\r
4226             drawHighlight(hi2X, hi2Y, lineGC);\r
4227         }\r
4228         if (toX >= 0 && toY >= 0) {\r
4229             drawHighlight(toX, toY, highlineGC);\r
4230         }\r
4231     }\r
4232     hi1X = fromX;\r
4233     hi1Y = fromY;\r
4234     hi2X = toX;\r
4235     hi2Y = toY;\r
4236 }\r
4237 \r
4238 void\r
4239 ClearHighlights()\r
4240 {\r
4241     SetHighlights(-1, -1, -1, -1);\r
4242 }\r
4243 \r
4244 \r
4245 void\r
4246 SetPremoveHighlights(fromX, fromY, toX, toY)\r
4247      int fromX, fromY, toX, toY;\r
4248 {\r
4249     if (pm1X != fromX || pm1Y != fromY) {\r
4250         if (pm1X >= 0 && pm1Y >= 0) {\r
4251             drawHighlight(pm1X, pm1Y, lineGC);\r
4252         }\r
4253         if (fromX >= 0 && fromY >= 0) {\r
4254             drawHighlight(fromX, fromY, prelineGC);\r
4255         }\r
4256     }\r
4257     if (pm2X != toX || pm2Y != toY) {\r
4258         if (pm2X >= 0 && pm2Y >= 0) {\r
4259             drawHighlight(pm2X, pm2Y, lineGC);\r
4260         }\r
4261         if (toX >= 0 && toY >= 0) {\r
4262             drawHighlight(toX, toY, prelineGC);\r
4263         }\r
4264     }\r
4265     pm1X = fromX;\r
4266     pm1Y = fromY;\r
4267     pm2X = toX;\r
4268     pm2Y = toY;\r
4269 }\r
4270 \r
4271 void\r
4272 ClearPremoveHighlights()\r
4273 {\r
4274   SetPremoveHighlights(-1, -1, -1, -1);\r
4275 }\r
4276 \r
4277 static void BlankSquare(x, y, color, piece, dest)\r
4278      int x, y, color;\r
4279      ChessSquare piece;\r
4280      Drawable dest;\r
4281 {\r
4282     if (useImages && useImageSqs) {\r
4283         Pixmap pm;\r
4284         switch (color) {\r
4285           case 1: /* light */\r
4286             pm = xpmLightSquare;\r
4287             break;\r
4288           case 0: /* dark */\r
4289             pm = xpmDarkSquare;\r
4290             break;\r
4291           case 2: /* neutral */\r
4292           default:\r
4293             pm = xpmJailSquare;\r
4294             break;\r
4295         }\r
4296         XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,\r
4297                   squareSize, squareSize, x, y);\r
4298     } else {\r
4299         GC gc;\r
4300         switch (color) {\r
4301           case 1: /* light */\r
4302             gc = lightSquareGC;\r
4303             break;\r
4304           case 0: /* dark */\r
4305             gc = darkSquareGC;\r
4306             break;\r
4307           case 2: /* neutral */\r
4308           default:\r
4309             gc = jailSquareGC;\r
4310             break;\r
4311         }\r
4312         XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);\r
4313     }\r
4314 }\r
4315 \r
4316 /*\r
4317    I split out the routines to draw a piece so that I could\r
4318    make a generic flash routine.\r
4319 */\r
4320 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)\r
4321      ChessSquare piece;\r
4322      int square_color, x, y;\r
4323      Drawable dest;\r
4324 {\r
4325     /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */\r
4326     switch (square_color) {\r
4327       case 1: /* light */\r
4328       case 2: /* neutral */\r
4329       default:\r
4330         XCopyArea(xDisplay, (int) piece < (int) BlackPawn\r
4331                   ? *pieceToOutline(piece)\r
4332                   : *pieceToSolid(piece),\r
4333                   dest, bwPieceGC, 0, 0,\r
4334                   squareSize, squareSize, x, y);\r
4335         break;\r
4336       case 0: /* dark */\r
4337         XCopyArea(xDisplay, (int) piece < (int) BlackPawn\r
4338                   ? *pieceToSolid(piece)\r
4339                   : *pieceToOutline(piece),\r
4340                   dest, wbPieceGC, 0, 0,\r
4341                   squareSize, squareSize, x, y);\r
4342         break;\r
4343     }\r
4344 }\r
4345 \r
4346 static void monoDrawPiece(piece, square_color, x, y, dest)\r
4347      ChessSquare piece;\r
4348      int square_color, x, y;\r
4349      Drawable dest;\r
4350 {\r
4351     switch (square_color) {\r
4352       case 1: /* light */\r
4353       case 2: /* neutral */\r
4354       default:\r
4355         XCopyPlane(xDisplay, (int) piece < (int) BlackPawn\r
4356                    ? *pieceToOutline(piece)\r
4357                    : *pieceToSolid(piece),\r
4358                    dest, bwPieceGC, 0, 0,\r
4359                    squareSize, squareSize, x, y, 1);\r
4360         break;\r
4361       case 0: /* dark */\r
4362         XCopyPlane(xDisplay, (int) piece < (int) BlackPawn\r
4363                    ? *pieceToSolid(piece)\r
4364                    : *pieceToOutline(piece),\r
4365                    dest, wbPieceGC, 0, 0,\r
4366                    squareSize, squareSize, x, y, 1);\r
4367         break;\r
4368     }\r
4369 }\r
4370 \r
4371 static void colorDrawPiece(piece, square_color, x, y, dest)\r
4372      ChessSquare piece;\r
4373      int square_color, x, y;\r
4374      Drawable dest;\r
4375 {\r
4376     if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;\r
4377     switch (square_color) {\r
4378       case 1: /* light */\r
4379         XCopyPlane(xDisplay, *pieceToSolid(piece),\r
4380                    dest, (int) piece < (int) BlackPawn\r
4381                    ? wlPieceGC : blPieceGC, 0, 0,\r
4382                    squareSize, squareSize, x, y, 1);\r
4383         break;\r
4384       case 0: /* dark */\r
4385         XCopyPlane(xDisplay, *pieceToSolid(piece),\r
4386                    dest, (int) piece < (int) BlackPawn\r
4387                    ? wdPieceGC : bdPieceGC, 0, 0,\r
4388                    squareSize, squareSize, x, y, 1);\r
4389         break;\r
4390       case 2: /* neutral */\r
4391       default:\r
4392         XCopyPlane(xDisplay, *pieceToSolid(piece),\r
4393                    dest, (int) piece < (int) BlackPawn\r
4394                    ? wjPieceGC : bjPieceGC, 0, 0,\r
4395                    squareSize, squareSize, x, y, 1);\r
4396         break;\r
4397     }\r
4398 }\r
4399 \r
4400 static void colorDrawPieceImage(piece, square_color, x, y, dest)\r
4401      ChessSquare piece;\r
4402      int square_color, x, y;\r
4403      Drawable dest;\r
4404 {\r
4405     int kind;\r
4406 \r
4407     switch (square_color) {\r
4408       case 1: /* light */\r
4409       case 2: /* neutral */\r
4410       default:\r
4411         if ((int)piece < (int) BlackPawn) {\r
4412             kind = 0;\r
4413         } else {\r
4414             kind = 2;\r
4415             piece -= BlackPawn;\r
4416         }\r
4417         break;\r
4418       case 0: /* dark */\r
4419         if ((int)piece < (int) BlackPawn) {\r
4420             kind = 1;\r
4421         } else {\r
4422             kind = 3;\r
4423             piece -= BlackPawn;\r
4424         }\r
4425         break;\r
4426     }\r
4427     XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],\r
4428               dest, wlPieceGC, 0, 0,\r
4429               squareSize, squareSize, x, y);            \r
4430 }\r
4431 \r
4432 typedef void (*DrawFunc)();\r
4433 \r
4434 DrawFunc ChooseDrawFunc()\r
4435 {\r
4436     if (appData.monoMode) {\r
4437         if (DefaultDepth(xDisplay, xScreen) == 1) {\r
4438             return monoDrawPiece_1bit;\r
4439         } else {\r
4440             return monoDrawPiece;\r
4441         }\r
4442     } else {\r
4443         if (useImages)\r
4444           return colorDrawPieceImage;\r
4445         else\r
4446           return colorDrawPiece;\r
4447     }\r
4448 }\r
4449 \r
4450 /* [HR] determine square color depending on chess variant. */\r
4451 static int SquareColor(row, column)\r
4452      int row, column;\r
4453 {\r
4454     int square_color;\r
4455 \r
4456     if (gameInfo.variant == VariantXiangqi) {\r
4457         if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {\r
4458             square_color = 1;\r
4459         } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {\r
4460             square_color = 0;\r
4461         } else if (row <= 4) {\r
4462             square_color = 0;\r
4463         } else {\r
4464             square_color = 1;\r
4465         }\r
4466     } else {\r
4467         square_color = ((column + row) % 2) == 1;\r
4468     }\r
4469 \r
4470     /* [hgm] holdings: next line makes all holdings squares light */\r
4471     if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;\r
4472  \r
4473     return square_color;\r
4474 }\r
4475 \r
4476 void DrawSquare(row, column, piece, do_flash)\r
4477      int row, column, do_flash;\r
4478      ChessSquare piece;\r
4479 {\r
4480     int square_color, x, y, direction, font_ascent, font_descent;\r
4481     int i;\r
4482     char string[2];\r
4483     XCharStruct overall;\r
4484     DrawFunc drawfunc;\r
4485     int flash_delay;\r
4486 \r
4487     if(gameInfo.variant == VariantShogi) { // [HGM] shogi: in shogi Q is used for Lance
4488         if(piece == WhiteQueen) piece = WhiteLance; else
4489         if(piece == BlackQueen) piece = BlackLance;
4490     }
4491 #ifdef GOTHIC
4492     else if(gameInfo.variant == VariantGothic) { // [HGM] shogi: in Gothic Chancelor has alternative look
4493         if(piece == WhiteMarshall) piece = WhiteSilver; else
4494         if(piece == BlackMarshall) piece = BlackSilver;
4495     }
4496 #endif
4497
4498     /* Calculate delay in milliseconds (2-delays per complete flash) */\r
4499     flash_delay = 500 / appData.flashRate;\r
4500         \r
4501     if (flipView) {\r
4502         x = lineGap + ((BOARD_WIDTH-1)-column) * \r
4503           (squareSize + lineGap);\r
4504         y = lineGap + row * (squareSize + lineGap);\r
4505     } else {\r
4506         x = lineGap + column * (squareSize + lineGap);\r
4507         y = lineGap + ((BOARD_HEIGHT-1)-row) * \r
4508           (squareSize + lineGap);\r
4509     }\r
4510   \r
4511     square_color = SquareColor(row, column);\r
4512     \r
4513     if ( // [HGM] holdings: blank out area between board and holdings\r
4514                  column == BOARD_LEFT-1 ||  column == BOARD_RGHT\r
4515               || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)\r
4516                   || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {\r
4517                         BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4518 \r
4519                         // [HGM] print piece counts next to holdings
4520                         string[1] = NULLCHAR;\r
4521                         if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {\r
4522                             string[0] = '0' + piece;\r
4523                             XTextExtents(countFontStruct, string, 1, &direction, \r
4524                                  &font_ascent, &font_descent, &overall);\r
4525                             if (appData.monoMode) {\r
4526                                 XDrawImageString(xDisplay, xBoardWindow, countGC,\r
4527                                                  x + squareSize - overall.width - 2, \r
4528                                                  y + font_ascent + 1, string, 1);\r
4529                             } else {\r
4530                                 XDrawString(xDisplay, xBoardWindow, countGC,\r
4531                                             x + squareSize - overall.width - 2, \r
4532                                             y + font_ascent + 1, string, 1);\r
4533                             }\r
4534                         }\r
4535                         if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {\r
4536                             string[0] = '0' + piece;\r
4537                             XTextExtents(countFontStruct, string, 1, &direction, \r
4538                                          &font_ascent, &font_descent, &overall);\r
4539                             if (appData.monoMode) {\r
4540                                 XDrawImageString(xDisplay, xBoardWindow, countGC,\r
4541                                                  x + 2, y + font_ascent + 1, string, 1);\r
4542                             } else {\r
4543                                 XDrawString(xDisplay, xBoardWindow, countGC,\r
4544                                             x + 2, y + font_ascent + 1, string, 1);\r
4545                             }       \r
4546                         }   \r
4547     } else {\r
4548             if (piece == EmptySquare || appData.blindfold) {\r
4549                         BlankSquare(x, y, square_color, piece, xBoardWindow);\r
4550             } else {\r
4551                         drawfunc = ChooseDrawFunc();\r
4552                         if (do_flash && appData.flashCount > 0) {\r
4553                             for (i=0; i<appData.flashCount; ++i) {\r
4554 \r
4555                                         drawfunc(piece, square_color, x, y, xBoardWindow);\r
4556                                         XSync(xDisplay, False);\r
4557                                         do_flash_delay(flash_delay);\r
4558 \r
4559                                         BlankSquare(x, y, square_color, piece, xBoardWindow);\r
4560                                         XSync(xDisplay, False);\r
4561                                         do_flash_delay(flash_delay);\r
4562                             }\r
4563                         }\r
4564                         drawfunc(piece, square_color, x, y, xBoardWindow);\r
4565         }\r
4566         }\r
4567         \r
4568     string[1] = NULLCHAR;\r
4569     if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4570                 && column >= BOARD_LEFT && column < BOARD_RGHT) {\r
4571         string[0] = 'a' + column - BOARD_LEFT;\r
4572         XTextExtents(coordFontStruct, string, 1, &direction, \r
4573                      &font_ascent, &font_descent, &overall);\r
4574         if (appData.monoMode) {\r
4575             XDrawImageString(xDisplay, xBoardWindow, coordGC,\r
4576                              x + squareSize - overall.width - 2, \r
4577                              y + squareSize - font_descent - 1, string, 1);\r
4578         } else {\r
4579             XDrawString(xDisplay, xBoardWindow, coordGC,\r
4580                         x + squareSize - overall.width - 2, \r
4581                         y + squareSize - font_descent - 1, string, 1);\r
4582         }\r
4583     }\r
4584     if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {\r
4585         string[0] = ONE + row;\r
4586         XTextExtents(coordFontStruct, string, 1, &direction, \r
4587                      &font_ascent, &font_descent, &overall);\r
4588         if (appData.monoMode) {\r
4589             XDrawImageString(xDisplay, xBoardWindow, coordGC,\r
4590                              x + 2, y + font_ascent + 1, string, 1);\r
4591         } else {\r
4592             XDrawString(xDisplay, xBoardWindow, coordGC,\r
4593                         x + 2, y + font_ascent + 1, string, 1);\r
4594         }           \r
4595     }   \r
4596 }\r
4597 \r
4598 \r
4599 /* Why is this needed on some versions of X? */\r
4600 void EventProc(widget, unused, event)\r
4601      Widget widget;\r
4602      caddr_t unused;\r
4603      XEvent *event;\r
4604 {\r
4605     if (!XtIsRealized(widget))\r
4606       return;\r
4607 \r
4608     switch (event->type) {\r
4609       case Expose:\r
4610         if (event->xexpose.count > 0) return;  /* no clipping is done */\r
4611         XDrawPosition(widget, True, NULL);\r
4612         break;\r
4613       default:\r
4614         return;\r
4615     }\r
4616 }\r
4617 /* end why */\r
4618 \r
4619 void DrawPosition(fullRedraw, board)\r
4620      /*Boolean*/int fullRedraw;\r
4621      Board board;\r
4622 {\r
4623     XDrawPosition(boardWidget, fullRedraw, board);\r
4624 }\r
4625 \r
4626 /* Returns 1 if there are "too many" differences between b1 and b2\r
4627    (i.e. more than 1 move was made) */\r
4628 static int too_many_diffs(b1, b2)\r
4629      Board b1, b2;\r
4630 {\r
4631     int i, j;\r
4632     int c = 0;\r
4633   \r
4634     for (i=0; i<BOARD_HEIGHT; ++i) {\r
4635         for (j=0; j<BOARD_WIDTH; ++j) {\r
4636             if (b1[i][j] != b2[i][j]) {\r
4637                 if (++c > 4)    /* Castling causes 4 diffs */\r
4638                   return 1;\r
4639             }\r
4640         }\r
4641     }\r
4642 \r
4643     return 0;\r
4644 }\r
4645 \r
4646 /* Matrix describing castling maneuvers */\r
4647 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */\r
4648 static int castling_matrix[4][5] = {\r
4649     { 0, 0, 4, 3, 2 },          /* 0-0-0, white */\r
4650     { 0, 7, 4, 5, 6 },          /* 0-0,   white */\r
4651     { 7, 0, 4, 3, 2 },          /* 0-0-0, black */\r
4652     { 7, 7, 4, 5, 6 }           /* 0-0,   black */\r
4653 };\r
4654 \r
4655 /* Checks whether castling occurred. If it did, *rrow and *rcol\r
4656    are set to the destination (row,col) of the rook that moved.\r
4657    \r
4658    Returns 1 if castling occurred, 0 if not.\r
4659    \r
4660    Note: Only handles a max of 1 castling move, so be sure\r
4661    to call too_many_diffs() first.\r
4662    */\r
4663 static int check_castle_draw(newb, oldb, rrow, rcol)\r
4664      Board newb, oldb;\r
4665      int *rrow, *rcol;\r
4666 {\r
4667     int i, *r, j;\r
4668     int match;\r
4669 \r
4670     /* For each type of castling... */\r
4671     for (i=0; i<4; ++i) {\r
4672         r = castling_matrix[i];\r
4673 \r
4674         /* Check the 4 squares involved in the castling move */\r
4675         match = 0;\r
4676         for (j=1; j<=4; ++j) {\r
4677             if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {\r
4678                 match = 1;\r
4679                 break;\r
4680             }\r
4681         }\r
4682 \r
4683         if (!match) {\r
4684             /* All 4 changed, so it must be a castling move */\r
4685             *rrow = r[0];\r
4686             *rcol = r[3];\r
4687             return 1;\r
4688         }\r
4689     }\r
4690     return 0;\r
4691 }\r
4692 \r
4693 static int damage[BOARD_SIZE][BOARD_SIZE];\r
4694 \r
4695 /*\r
4696  * event handler for redrawing the board\r
4697  */\r
4698 void XDrawPosition(w, repaint, board)\r
4699      Widget w;\r
4700      /*Boolean*/int repaint;\r
4701      Board board;\r
4702 {\r
4703     int i, j, do_flash;\r
4704     static int lastFlipView = 0;\r
4705     static int lastBoardValid = 0;\r
4706     static Board lastBoard;\r
4707     Arg args[16];\r
4708     int rrow, rcol;\r
4709     \r
4710     if (board == NULL) {\r
4711         if (!lastBoardValid) return;\r
4712         board = lastBoard;\r
4713     }\r
4714     if (!lastBoardValid || lastFlipView != flipView) {\r
4715         XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));\r
4716         XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),\r
4717                     args, 1);\r
4718     }\r
4719 \r
4720     /*\r
4721      * It would be simpler to clear the window with XClearWindow()\r
4722      * but this causes a very distracting flicker.\r
4723      */\r
4724     \r
4725     if (!repaint && lastBoardValid && lastFlipView == flipView) {\r
4726 \r
4727         /* If too much changes (begin observing new game, etc.), don't\r
4728            do flashing */\r
4729         do_flash = too_many_diffs(board, lastBoard) ? 0 : 1;\r
4730 \r
4731         /* Special check for castling so we don't flash both the king\r
4732            and the rook (just flash the king). */\r
4733         if (do_flash) {\r
4734             if (check_castle_draw(board, lastBoard, &rrow, &rcol)) {\r
4735                 /* Draw rook with NO flashing. King will be drawn flashing later */\r
4736                 DrawSquare(rrow, rcol, board[rrow][rcol], 0);\r
4737                 lastBoard[rrow][rcol] = board[rrow][rcol];\r
4738             }\r
4739         }\r
4740 \r
4741         /* First pass -- Draw (newly) empty squares and repair damage. \r
4742            This prevents you from having a piece show up twice while it \r
4743            is flashing on its new square */\r
4744         for (i = 0; i < BOARD_HEIGHT; i++)\r
4745           for (j = 0; j < BOARD_WIDTH; j++)\r
4746             if ((board[i][j] != lastBoard[i][j] && board[i][j] == EmptySquare)\r
4747                 || damage[i][j]) {\r
4748                 DrawSquare(i, j, board[i][j], 0);\r
4749                 damage[i][j] = False;\r
4750             }\r
4751 \r
4752         /* Second pass -- Draw piece(s) in new position and flash them */\r
4753         for (i = 0; i < BOARD_HEIGHT; i++)\r
4754           for (j = 0; j < BOARD_WIDTH; j++)\r
4755             if (board[i][j] != lastBoard[i][j]) {\r
4756                 DrawSquare(i, j, board[i][j], do_flash);          \r
4757             }\r
4758     } else {\r
4759         if (lineGap > 0)\r
4760           XDrawSegments(xDisplay, xBoardWindow, lineGC,\r
4761                         gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);\r
4762         \r
4763         for (i = 0; i < BOARD_HEIGHT; i++)\r
4764           for (j = 0; j < BOARD_WIDTH; j++) {\r
4765               DrawSquare(i, j, board[i][j], 0);\r
4766               damage[i][j] = False;\r
4767           }\r
4768     }\r
4769 \r
4770     CopyBoard(lastBoard, board);\r
4771     lastBoardValid = 1;\r
4772     lastFlipView = flipView;\r
4773 \r
4774     /* Draw highlights */\r
4775     if (pm1X >= 0 && pm1Y >= 0) {\r
4776       drawHighlight(pm1X, pm1Y, prelineGC);\r
4777     }\r
4778     if (pm2X >= 0 && pm2Y >= 0) {\r
4779       drawHighlight(pm2X, pm2Y, prelineGC);\r
4780     }\r
4781     if (hi1X >= 0 && hi1Y >= 0) {\r
4782       drawHighlight(hi1X, hi1Y, highlineGC);\r
4783     }\r
4784     if (hi2X >= 0 && hi2Y >= 0) {\r
4785       drawHighlight(hi2X, hi2Y, highlineGC);\r
4786     }\r
4787 \r
4788     /* If piece being dragged around board, must redraw that too */\r
4789     DrawDragPiece();\r
4790 \r
4791     XSync(xDisplay, False);\r
4792 }\r
4793 \r
4794 \r
4795 /*\r
4796  * event handler for redrawing the board\r
4797  */\r
4798 void DrawPositionProc(w, event, prms, nprms)\r
4799      Widget w;\r
4800      XEvent *event;\r
4801      String *prms;\r
4802      Cardinal *nprms;\r
4803 {\r
4804     XDrawPosition(w, True, NULL);\r
4805 }\r
4806 \r
4807 \r
4808 /*\r
4809  * event handler for parsing user moves\r
4810  */\r
4811 // [HGM] This routine will need quite some reworking. Although the backend still supports the old\r
4812 //       way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform\r
4813 //       it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it\r
4814 //       should be made to use the new way, of calling UserMoveTest early  to determine the legality of the\r
4815 //       move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),\r
4816 //       and at the end FinishMove() to perform the move after optional promotion popups.\r
4817 //       For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.\r
4818 void HandleUserMove(w, event, prms, nprms)\r
4819      Widget w;\r
4820      XEvent *event;\r
4821      String *prms;\r
4822      Cardinal *nprms;\r
4823 {\r
4824     int x, y;\r
4825     Boolean saveAnimate;\r
4826     static int second = 0;\r
4827         \r
4828     if (w != boardWidget || errorExitStatus != -1) return;\r
4829 \r
4830     if (event->type == ButtonPress) ErrorPopDown();\r
4831 \r
4832     if (promotionUp) {\r
4833         if (event->type == ButtonPress) {\r
4834             XtPopdown(promotionShell);\r
4835             XtDestroyWidget(promotionShell);\r
4836             promotionUp = False;\r
4837             ClearHighlights();\r
4838             fromX = fromY = -1;\r
4839         } else {\r
4840             return;\r
4841         }\r
4842     }\r
4843     \r
4844     x = EventToSquare(event->xbutton.x, BOARD_WIDTH);\r
4845     y = EventToSquare(event->xbutton.y, BOARD_HEIGHT);\r
4846     if (!flipView && y >= 0) {\r
4847         y = BOARD_HEIGHT - 1 - y;\r
4848     }\r
4849     if (flipView && x >= 0) {\r
4850         x = BOARD_WIDTH - 1 - x;\r
4851     }\r
4852 \r
4853     /* [HGM] holdings: next 5 lines: ignore all clicks between board and holdings */\r
4854     if(event->type == ButtonPress\r
4855             && ( x == BOARD_LEFT-1 || x == BOARD_RGHT\r
4856               || x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize\r
4857               || x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize) )\r
4858         return;\r
4859 \r
4860     if (fromX == -1) {\r
4861         if (event->type == ButtonPress) {\r
4862             /* First square */ \r
4863             if (OKToStartUserMove(x, y)) {\r
4864                 fromX = x;\r
4865                 fromY = y;\r
4866                 second = 0;\r
4867                 DragPieceBegin(event->xbutton.x, event->xbutton.y);\r
4868                 if (appData.highlightDragging) {\r
4869                     SetHighlights(x, y, -1, -1);\r
4870                 }\r
4871             } \r
4872         }\r
4873         return;\r
4874     }\r
4875 \r
4876     /* fromX != -1 */\r
4877     if (event->type == ButtonPress && gameMode != EditPosition &&\r
4878         x >= 0 && y >= 0) {\r
4879         ChessSquare fromP;\r
4880         ChessSquare toP;\r
4881 \r
4882         /* Check if clicking again on the same color piece */\r
4883         fromP = boards[currentMove][fromY][fromX];\r
4884         toP = boards[currentMove][y][x];\r
4885         if ((WhitePawn <= fromP && fromP < WhiteKing && // [HGM] this test should go, as UserMoveTest now does it.\r
4886              WhitePawn <= toP && toP <= WhiteKing) ||   //       For now I made it less critical by exempting King\r
4887             (BlackPawn <= fromP && fromP < BlackKing && //       moves, to not interfere with FRC castlings.\r
4888              BlackPawn <= toP && toP <= BlackKing)) {\r
4889             /* Clicked again on same color piece -- changed his mind */\r
4890             second = (x == fromX && y == fromY);\r
4891             if (appData.highlightDragging) {\r
4892                 SetHighlights(x, y, -1, -1);\r
4893             } else {\r
4894                 ClearHighlights();\r
4895             }\r
4896             if (OKToStartUserMove(x, y)) {\r
4897                 fromX = x;\r
4898                 fromY = y;\r
4899                 DragPieceBegin(event->xbutton.x, event->xbutton.y);\r
4900             }\r
4901             return;\r
4902         }\r
4903     }\r
4904 \r
4905     if (event->type == ButtonRelease && x == fromX && y == fromY) {\r
4906         DragPieceEnd(event->xbutton.x, event->xbutton.y);\r
4907         if (appData.animateDragging) {\r
4908             /* Undo animation damage if any */\r
4909             DrawPosition(FALSE, NULL);\r
4910         }\r
4911         if (second) {\r
4912             /* Second up/down in same square; just abort move */\r
4913             second = 0;\r
4914             fromX = fromY = -1;\r
4915             ClearHighlights();\r
4916             gotPremove = 0;\r
4917             ClearPremoveHighlights();\r
4918         } else {\r
4919             /* First upclick in same square; start click-click mode */\r
4920             SetHighlights(x, y, -1, -1);\r
4921         }\r
4922         return;\r
4923     }   \r
4924 \r
4925     /* Completed move */\r
4926     toX = x;\r
4927     toY = y;\r
4928     saveAnimate = appData.animate;\r
4929     if (event->type == ButtonPress) {\r
4930         /* Finish clickclick move */\r
4931         if (appData.animate || appData.highlightLastMove) {\r
4932             SetHighlights(fromX, fromY, toX, toY);\r
4933         } else {\r
4934             ClearHighlights();\r
4935         }\r
4936     } else {\r
4937         /* Finish drag move */\r
4938         if (appData.highlightLastMove) {\r
4939             SetHighlights(fromX, fromY, toX, toY);\r
4940         } else {\r
4941             ClearHighlights();\r
4942         }\r
4943         DragPieceEnd(event->xbutton.x, event->xbutton.y);\r
4944         /* Don't animate move and drag both */\r
4945         appData.animate = FALSE;\r
4946     }\r
4947     if (IsPromotion(fromX, fromY, toX, toY)) {\r
4948         if (appData.alwaysPromoteToQueen) {\r
4949             UserMoveEvent(fromX, fromY, toX, toY, 'q');\r
4950             if (!appData.highlightLastMove || gotPremove) ClearHighlights();\r
4951             if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);\r
4952             fromX = fromY = -1;\r
4953         } else {\r
4954             SetHighlights(fromX, fromY, toX, toY);\r
4955             PromotionPopUp();\r
4956         }\r
4957     } else {\r
4958         UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR);\r
4959         if (!appData.highlightLastMove || gotPremove) ClearHighlights();\r
4960         if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);\r
4961         fromX = fromY = -1;\r
4962     }\r
4963     appData.animate = saveAnimate;\r
4964     if (appData.animate || appData.animateDragging) {\r
4965         /* Undo animation damage if needed */\r
4966         DrawPosition(FALSE, NULL);\r
4967     }\r
4968 }\r
4969 \r
4970 void AnimateUserMove (Widget w, XEvent * event,\r
4971                       String * params, Cardinal * nParams)\r
4972 {\r
4973     DragPieceMove(event->xmotion.x, event->xmotion.y);\r
4974 }\r
4975 \r
4976 Widget CommentCreate(name, text, mutable, callback, lines)\r
4977      char *name, *text;\r
4978      int /*Boolean*/ mutable;\r
4979      XtCallbackProc callback;\r
4980      int lines;\r
4981 {\r
4982     Arg args[16];\r
4983     Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;\r
4984     Dimension bw_width;\r
4985     int j;\r
4986 \r
4987     j = 0;\r
4988     XtSetArg(args[j], XtNwidth, &bw_width);  j++;\r
4989     XtGetValues(boardWidget, args, j);\r
4990 \r
4991     j = 0;\r
4992     XtSetArg(args[j], XtNresizable, True);  j++;\r
4993 #if TOPLEVEL\r
4994     shell =\r
4995       XtCreatePopupShell(name, topLevelShellWidgetClass,\r
4996                          shellWidget, args, j);\r
4997 #else\r
4998     shell =\r
4999       XtCreatePopupShell(name, transientShellWidgetClass,\r
5000                          shellWidget, args, j);\r
5001 #endif\r
5002     layout =\r
5003       XtCreateManagedWidget(layoutName, formWidgetClass, shell,\r
5004                             layoutArgs, XtNumber(layoutArgs));\r
5005     form =\r
5006       XtCreateManagedWidget("form", formWidgetClass, layout,\r
5007                             formArgs, XtNumber(formArgs));\r
5008 \r
5009     j = 0;\r
5010     if (mutable) {\r
5011         XtSetArg(args[j], XtNeditType, XawtextEdit);  j++;\r
5012         XtSetArg(args[j], XtNuseStringInPlace, False);  j++;\r
5013     }\r
5014     XtSetArg(args[j], XtNstring, text);  j++;\r
5015     XtSetArg(args[j], XtNtop, XtChainTop);  j++;\r
5016     XtSetArg(args[j], XtNbottom, XtChainBottom);  j++;\r
5017     XtSetArg(args[j], XtNleft, XtChainLeft);  j++;\r
5018     XtSetArg(args[j], XtNright, XtChainRight);  j++;\r
5019     XtSetArg(args[j], XtNresizable, True);  j++;\r
5020     XtSetArg(args[j], XtNwidth, bw_width);  j++; /*force wider than buttons*/\r
5021 #if 0\r
5022     XtSetArg(args[j], XtNscrollVertical, XawtextScrollWhenNeeded);  j++;\r
5023 #else\r
5024     /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */\r
5025     XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways);  j++;\r
5026 #endif\r
5027     XtSetArg(args[j], XtNautoFill, True);  j++;\r
5028     XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;\r
5029     edit =\r
5030       XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);\r
5031 \r
5032     if (mutable) {\r
5033         j = 0;\r
5034         XtSetArg(args[j], XtNfromVert, edit);  j++;\r
5035         XtSetArg(args[j], XtNtop, XtChainBottom); j++;\r
5036         XtSetArg(args[j], XtNbottom, XtChainBottom); j++;\r
5037         XtSetArg(args[j], XtNleft, XtChainLeft); j++;\r
5038         XtSetArg(args[j], XtNright, XtChainLeft); j++;\r
5039         b_ok =\r
5040           XtCreateManagedWidget("ok", commandWidgetClass, form, args, j);\r
5041         XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);\r
5042 \r
5043         j = 0;\r
5044         XtSetArg(args[j], XtNfromVert, edit);  j++;\r
5045         XtSetArg(args[j], XtNfromHoriz, b_ok);  j++;\r
5046         XtSetArg(args[j], XtNtop, XtChainBottom); j++;\r
5047         XtSetArg(args[j], XtNbottom, XtChainBottom); j++;\r
5048         XtSetArg(args[j], XtNleft, XtChainLeft); j++;\r
5049         XtSetArg(args[j], XtNright, XtChainLeft); j++;\r
5050         b_cancel =\r
5051           XtCreateManagedWidget("cancel", commandWidgetClass, form, args, j);\r
5052         XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);\r
5053 \r
5054         j = 0;\r
5055         XtSetArg(args[j], XtNfromVert, edit);  j++;\r
5056         XtSetArg(args[j], XtNfromHoriz, b_cancel);  j++;\r
5057         XtSetArg(args[j], XtNtop, XtChainBottom); j++;\r
5058         XtSetArg(args[j], XtNbottom, XtChainBottom); j++;\r
5059         XtSetArg(args[j], XtNleft, XtChainLeft); j++;\r
5060         XtSetArg(args[j], XtNright, XtChainLeft); j++;\r
5061         b_clear =\r
5062           XtCreateManagedWidget("clear", commandWidgetClass, form, args, j);\r
5063         XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);\r
5064     } else {\r
5065         j = 0;\r
5066         XtSetArg(args[j], XtNfromVert, edit);  j++;\r
5067         XtSetArg(args[j], XtNtop, XtChainBottom); j++;\r
5068         XtSetArg(args[j], XtNbottom, XtChainBottom); j++;\r
5069         XtSetArg(args[j], XtNleft, XtChainLeft); j++;\r
5070         XtSetArg(args[j], XtNright, XtChainLeft); j++;\r
5071         b_close =\r
5072           XtCreateManagedWidget("close", commandWidgetClass, form, args, j);\r
5073         XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);\r
5074 \r
5075         j = 0;\r
5076         XtSetArg(args[j], XtNfromVert, edit);  j++;\r
5077         XtSetArg(args[j], XtNfromHoriz, b_close);  j++;\r
5078         XtSetArg(args[j], XtNtop, XtChainBottom); j++;\r
5079         XtSetArg(args[j], XtNbottom, XtChainBottom); j++;\r
5080         XtSetArg(args[j], XtNleft, XtChainLeft); j++;\r
5081         XtSetArg(args[j], XtNright, XtChainLeft); j++;\r
5082         b_edit =\r
5083           XtCreateManagedWidget("edit", commandWidgetClass, form, args, j);\r
5084         XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);\r
5085     }\r
5086 \r
5087     XtRealizeWidget(shell);\r
5088 \r
5089     if (commentX == -1) {\r
5090         int xx, yy;\r
5091         Window junk;\r
5092         Dimension pw_height;\r
5093         Dimension ew_height;\r
5094 \r
5095         j = 0;\r
5096         XtSetArg(args[j], XtNheight, &ew_height);  j++;\r
5097         XtGetValues(edit, args, j);\r
5098 \r
5099         j = 0;\r
5100         XtSetArg(args[j], XtNheight, &pw_height);  j++;\r
5101         XtGetValues(shell, args, j);\r
5102         commentH = pw_height + (lines - 1) * ew_height;\r
5103         commentW = bw_width - 16;\r
5104 \r
5105         XSync(xDisplay, False);\r
5106 #ifdef NOTDEF\r
5107         /* This code seems to tickle an X bug if it is executed too soon\r
5108            after xboard starts up.  The coordinates get transformed as if\r
5109            the main window was positioned at (0, 0).\r
5110            */\r
5111         XtTranslateCoords(shellWidget,\r
5112                           (bw_width - commentW) / 2, 0 - commentH / 2,\r
5113                           &commentX, &commentY);\r
5114 #else  /*!NOTDEF*/\r
5115         XTranslateCoordinates(xDisplay, XtWindow(shellWidget),\r
5116                               RootWindowOfScreen(XtScreen(shellWidget)),\r
5117                               (bw_width - commentW) / 2, 0 - commentH / 2,\r
5118                               &xx, &yy, &junk);\r
5119         commentX = xx;\r
5120         commentY = yy;\r
5121 #endif /*!NOTDEF*/\r
5122         if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/\r
5123     }\r
5124     j = 0;\r
5125     XtSetArg(args[j], XtNheight, commentH);  j++;\r
5126     XtSetArg(args[j], XtNwidth, commentW);  j++;\r
5127     XtSetArg(args[j], XtNx, commentX);  j++;\r
5128     XtSetArg(args[j], XtNy, commentY);  j++;\r
5129     XtSetValues(shell, args, j);\r
5130     XtSetKeyboardFocus(shell, edit);\r
5131 \r
5132     return shell;\r
5133 }\r
5134 \r
5135 /* Used for analysis window and ICS input window */\r
5136 Widget MiscCreate(name, text, mutable, callback, lines)\r
5137      char *name, *text;\r
5138      int /*Boolean*/ mutable;\r
5139      XtCallbackProc callback;\r
5140      int lines;\r
5141 {\r
5142     Arg args[16];\r
5143     Widget shell, layout, form, edit;\r
5144     Position x, y;\r
5145     Dimension bw_width, pw_height, ew_height, w, h;\r
5146     int j;\r
5147     int xx, yy;\r
5148     Window junk;\r
5149 \r
5150     j = 0;\r
5151     XtSetArg(args[j], XtNresizable, True);  j++;\r
5152 #if TOPLEVEL\r
5153     shell =\r
5154       XtCreatePopupShell(name, topLevelShellWidgetClass,\r
5155                          shellWidget, args, j);\r
5156 #else\r
5157     shell =\r
5158       XtCreatePopupShell(name, transientShellWidgetClass,\r
5159                          shellWidget, args, j);\r
5160 #endif\r
5161     layout =\r
5162       XtCreateManagedWidget(layoutName, formWidgetClass, shell,\r
5163                             layoutArgs, XtNumber(layoutArgs));\r
5164     form =\r
5165       XtCreateManagedWidget("form", formWidgetClass, layout,\r
5166                             formArgs, XtNumber(formArgs));\r
5167 \r
5168     j = 0;\r
5169     if (mutable) {\r
5170         XtSetArg(args[j], XtNeditType, XawtextEdit);  j++;\r
5171         XtSetArg(args[j], XtNuseStringInPlace, False);  j++;\r
5172     }\r
5173     XtSetArg(args[j], XtNstring, text);  j++;\r
5174     XtSetArg(args[j], XtNtop, XtChainTop);  j++;\r
5175     XtSetArg(args[j], XtNbottom, XtChainBottom);  j++;\r
5176     XtSetArg(args[j], XtNleft, XtChainLeft);  j++;\r
5177     XtSetArg(args[j], XtNright, XtChainRight);  j++;\r
5178     XtSetArg(args[j], XtNresizable, True);  j++;\r
5179 #if 0\r
5180     XtSetArg(args[j], XtNscrollVertical, XawtextScrollWhenNeeded);  j++;\r
5181 #else\r
5182     /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */\r
5183     XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways);  j++;\r
5184 #endif\r
5185     XtSetArg(args[j], XtNautoFill, True);  j++;\r
5186     XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;\r
5187     edit =\r
5188       XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);\r
5189 \r
5190     XtRealizeWidget(shell);\r
5191 \r
5192     j = 0;\r
5193     XtSetArg(args[j], XtNwidth, &bw_width);  j++;\r
5194     XtGetValues(boardWidget, args, j);\r
5195 \r
5196     j = 0;\r
5197     XtSetArg(args[j], XtNheight, &ew_height);  j++;\r
5198     XtGetValues(edit, args, j);\r
5199 \r
5200     j = 0;\r
5201     XtSetArg(args[j], XtNheight, &pw_height);  j++;\r
5202     XtGetValues(shell, args, j);\r
5203     h = pw_height + (lines - 1) * ew_height;\r
5204     w = bw_width - 16;\r
5205 \r
5206     XSync(xDisplay, False);\r
5207 #ifdef NOTDEF\r
5208     /* This code seems to tickle an X bug if it is executed too soon\r
5209        after xboard starts up.  The coordinates get transformed as if\r
5210        the main window was positioned at (0, 0).\r
5211     */\r
5212     XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);\r
5213 #else  /*!NOTDEF*/\r
5214     XTranslateCoordinates(xDisplay, XtWindow(shellWidget),\r
5215                           RootWindowOfScreen(XtScreen(shellWidget)),\r
5216                           (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);\r
5217 #endif /*!NOTDEF*/\r
5218     x = xx;\r
5219     y = yy;\r
5220     if (y < 0) y = 0; /*avoid positioning top offscreen*/\r
5221 \r
5222     j = 0;\r
5223     XtSetArg(args[j], XtNheight, h);  j++;\r
5224     XtSetArg(args[j], XtNwidth, w);  j++;\r
5225     XtSetArg(args[j], XtNx, x);  j++;\r
5226     XtSetArg(args[j], XtNy, y);  j++;\r
5227     XtSetValues(shell, args, j);\r
5228 \r
5229     return shell;\r
5230 }\r
5231 \r
5232 \r
5233 static int savedIndex;  /* gross that this is global */\r
5234 \r
5235 void EditCommentPopUp(index, title, text)\r
5236      int index;\r
5237      char *title, *text;\r
5238 {\r
5239     Widget edit;\r
5240     Arg args[16];\r
5241     int j;\r
5242 \r
5243     savedIndex = index;\r
5244     if (text == NULL) text = "";\r
5245 \r
5246     if (editShell == NULL) {\r
5247         editShell =\r
5248           CommentCreate(title, text, True, EditCommentCallback, 4); \r
5249         XtRealizeWidget(editShell);\r
5250         CatchDeleteWindow(editShell, "EditCommentPopDown");\r
5251     } else {\r
5252         edit = XtNameToWidget(editShell, "*form.text");\r
5253         j = 0;\r
5254         XtSetArg(args[j], XtNstring, text); j++;\r
5255         XtSetValues(edit, args, j);\r
5256         j = 0;\r
5257         XtSetArg(args[j], XtNiconName, (XtArgVal) title);   j++;\r
5258         XtSetArg(args[j], XtNtitle, (XtArgVal) title);      j++;\r
5259         XtSetValues(editShell, args, j);\r
5260     }\r
5261 \r
5262     XtPopup(editShell, XtGrabNone);\r
5263 \r
5264     editUp = True;\r
5265     j = 0;\r
5266     XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;\r
5267     XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),\r
5268                 args, j);\r
5269 }\r
5270 \r
5271 void EditCommentCallback(w, client_data, call_data)\r
5272      Widget w;\r
5273      XtPointer client_data, call_data;\r
5274 {\r
5275     String name, val;\r
5276     Arg args[16];\r
5277     int j;\r
5278     Widget edit;\r
5279 \r
5280     j = 0;\r
5281     XtSetArg(args[j], XtNlabel, &name);  j++;\r
5282     XtGetValues(w, args, j);\r
5283 \r
5284     if (strcmp(name, "ok") == 0) {\r
5285         edit = XtNameToWidget(editShell, "*form.text");\r
5286         j = 0;\r
5287         XtSetArg(args[j], XtNstring, &val); j++;\r
5288         XtGetValues(edit, args, j);\r
5289         ReplaceComment(savedIndex, val);\r
5290         EditCommentPopDown();\r
5291     } else if (strcmp(name, "cancel") == 0) {\r
5292         EditCommentPopDown();\r
5293     } else if (strcmp(name, "clear") == 0) {\r
5294         edit = XtNameToWidget(editShell, "*form.text");\r
5295         XtCallActionProc(edit, "select-all", NULL, NULL, 0);\r
5296         XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);\r
5297     }\r
5298 }\r
5299 \r
5300 void EditCommentPopDown()\r
5301 {\r
5302     Arg args[16];\r
5303     int j;\r
5304 \r
5305     if (!editUp) return;\r
5306     j = 0;\r
5307     XtSetArg(args[j], XtNx, &commentX); j++;\r
5308     XtSetArg(args[j], XtNy, &commentY); j++;\r
5309     XtSetArg(args[j], XtNheight, &commentH); j++;\r
5310     XtSetArg(args[j], XtNwidth, &commentW); j++;\r
5311     XtGetValues(editShell, args, j);\r
5312     XtPopdown(editShell);\r
5313     editUp = False;\r
5314     j = 0;\r
5315     XtSetArg(args[j], XtNleftBitmap, None); j++;\r
5316     XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),\r
5317                 args, j);\r
5318 }\r
5319 \r
5320 void ICSInputBoxPopUp()\r
5321 {\r
5322     Widget edit;\r
5323     Arg args[16];\r
5324     int j;\r
5325     char *title = "ICS Input";\r
5326     XtTranslations tr;\r
5327         \r
5328     if (ICSInputShell == NULL) {\r
5329         ICSInputShell = MiscCreate(title, "", True, NULL, 1);\r
5330         tr = XtParseTranslationTable(ICSInputTranslations);\r
5331         edit = XtNameToWidget(ICSInputShell, "*form.text");\r
5332         XtOverrideTranslations(edit, tr);\r
5333         XtRealizeWidget(ICSInputShell);\r
5334         CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");\r
5335         \r
5336     } else {\r
5337         edit = XtNameToWidget(ICSInputShell, "*form.text");\r
5338         j = 0;\r
5339         XtSetArg(args[j], XtNstring, ""); j++;\r
5340         XtSetValues(edit, args, j);\r
5341         j = 0;\r
5342         XtSetArg(args[j], XtNiconName, (XtArgVal) title);   j++;\r
5343         XtSetArg(args[j], XtNtitle, (XtArgVal) title);      j++;\r
5344         XtSetValues(ICSInputShell, args, j);\r
5345     }\r
5346 \r
5347     XtPopup(ICSInputShell, XtGrabNone);\r
5348     XtSetKeyboardFocus(ICSInputShell, edit);\r
5349 \r
5350     ICSInputBoxUp = True;\r
5351     j = 0;\r
5352     XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;\r
5353     XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),\r
5354                 args, j);\r
5355 }\r
5356 \r
5357 void ICSInputSendText()\r
5358 {\r
5359     Widget edit;\r
5360     int j;\r
5361     Arg args[16];\r
5362     String val;\r
5363   \r
5364     edit = XtNameToWidget(ICSInputShell, "*form.text");\r
5365     j = 0;\r
5366     XtSetArg(args[j], XtNstring, &val); j++;\r
5367     XtGetValues(edit, args, j);\r
5368     SendMultiLineToICS(val);\r
5369     XtCallActionProc(edit, "select-all", NULL, NULL, 0);\r
5370     XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);\r
5371 }\r
5372 \r
5373 void ICSInputBoxPopDown()\r
5374 {\r
5375     Arg args[16];\r
5376     int j;\r
5377 \r
5378     if (!ICSInputBoxUp) return;\r
5379     j = 0;\r
5380     XtPopdown(ICSInputShell);\r
5381     ICSInputBoxUp = False;\r
5382     j = 0;\r
5383     XtSetArg(args[j], XtNleftBitmap, None); j++;\r
5384     XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),\r
5385                 args, j);\r
5386 }\r
5387 \r
5388 void CommentPopUp(title, text)\r
5389      char *title, *text;\r
5390 {\r
5391     Arg args[16];\r
5392     int j;\r
5393     Widget edit;\r
5394 \r
5395     if (commentShell == NULL) {\r
5396         commentShell =\r
5397           CommentCreate(title, text, False, CommentCallback, 4);\r
5398         XtRealizeWidget(commentShell);\r
5399         CatchDeleteWindow(commentShell, "CommentPopDown");\r
5400     } else {\r
5401         edit = XtNameToWidget(commentShell, "*form.text");\r
5402         j = 0;\r
5403         XtSetArg(args[j], XtNstring, text); j++;\r
5404         XtSetValues(edit, args, j);\r
5405         j = 0;\r
5406         XtSetArg(args[j], XtNiconName, (XtArgVal) title);   j++;\r
5407         XtSetArg(args[j], XtNtitle, (XtArgVal) title);      j++;\r
5408         XtSetValues(commentShell, args, j);\r
5409     }\r
5410 \r
5411     XtPopup(commentShell, XtGrabNone);\r
5412     XSync(xDisplay, False);\r
5413 \r
5414     commentUp = True;\r
5415 }\r
5416 \r
5417 void AnalysisPopUp(title, text)\r
5418      char *title, *text;\r
5419 {\r
5420     Arg args[16];\r
5421     int j;\r
5422     Widget edit;\r
5423 \r
5424     if (analysisShell == NULL) {\r
5425         analysisShell = MiscCreate(title, text, False, NULL, 4);\r
5426         XtRealizeWidget(analysisShell);\r
5427         CatchDeleteWindow(analysisShell, "AnalysisPopDown");\r
5428 \r
5429     } else {\r
5430         edit = XtNameToWidget(analysisShell, "*form.text");\r
5431         j = 0;\r
5432         XtSetArg(args[j], XtNstring, text); j++;\r
5433         XtSetValues(edit, args, j);\r
5434         j = 0;\r
5435         XtSetArg(args[j], XtNiconName, (XtArgVal) title);   j++;\r
5436         XtSetArg(args[j], XtNtitle, (XtArgVal) title);      j++;\r
5437         XtSetValues(analysisShell, args, j);\r
5438     }\r
5439 \r
5440     if (!analysisUp) {\r
5441         XtPopup(analysisShell, XtGrabNone);\r
5442     }\r
5443     XSync(xDisplay, False);\r
5444 \r
5445     analysisUp = True;\r
5446 }\r
5447 \r
5448 void CommentCallback(w, client_data, call_data)\r
5449      Widget w;\r
5450      XtPointer client_data, call_data;\r
5451 {\r
5452     String name;\r
5453     Arg args[16];\r
5454     int j;\r
5455 \r
5456     j = 0;\r
5457     XtSetArg(args[j], XtNlabel, &name);  j++;\r
5458     XtGetValues(w, args, j);\r
5459 \r
5460     if (strcmp(name, "close") == 0) {\r
5461         CommentPopDown();\r
5462     } else if (strcmp(name, "edit") == 0) {\r
5463         CommentPopDown();\r
5464         EditCommentEvent();\r
5465     }\r
5466 }\r
5467 \r
5468 \r
5469 void CommentPopDown()\r
5470 {\r
5471     Arg args[16];\r
5472     int j;\r
5473 \r
5474     if (!commentUp) return;\r
5475     j = 0;\r
5476     XtSetArg(args[j], XtNx, &commentX); j++;\r
5477     XtSetArg(args[j], XtNy, &commentY); j++;\r
5478     XtSetArg(args[j], XtNwidth, &commentW); j++;\r
5479     XtSetArg(args[j], XtNheight, &commentH); j++;\r
5480     XtGetValues(commentShell, args, j);\r
5481     XtPopdown(commentShell);\r
5482     XSync(xDisplay, False);\r
5483     commentUp = False;\r
5484 }\r
5485 \r
5486 void AnalysisPopDown()\r
5487 {\r
5488     if (!analysisUp) return;\r
5489     XtPopdown(analysisShell);\r
5490     XSync(xDisplay, False);\r
5491     analysisUp = False;\r
5492 }\r
5493 \r
5494 \r
5495 void FileNamePopUp(label, def, proc, openMode)\r
5496      char *label;\r
5497      char *def;\r
5498      FileProc proc;\r
5499      char *openMode;\r
5500 {\r
5501     Arg args[16];\r
5502     Widget popup, layout, dialog, edit;\r
5503     Window root, child;\r
5504     int x, y, i;\r
5505     int win_x, win_y;\r
5506     unsigned int mask;\r
5507     \r
5508     fileProc = proc;            /* I can't see a way not */\r
5509     fileOpenMode = openMode;    /*   to use globals here */\r
5510     \r
5511     i = 0;\r
5512     XtSetArg(args[i], XtNresizable, True); i++;\r
5513     XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;\r
5514     fileNameShell = popup =\r
5515       XtCreatePopupShell("File name prompt", transientShellWidgetClass,\r
5516                          shellWidget, args, i);\r
5517     \r
5518     layout =\r
5519       XtCreateManagedWidget(layoutName, formWidgetClass, popup,\r
5520                             layoutArgs, XtNumber(layoutArgs));\r
5521   \r
5522     i = 0;\r
5523     XtSetArg(args[i], XtNlabel, label); i++;\r
5524     XtSetArg(args[i], XtNvalue, def); i++;\r
5525     XtSetArg(args[i], XtNborderWidth, 0); i++;\r
5526     dialog = XtCreateManagedWidget("fileName", dialogWidgetClass,\r
5527                                    layout, args, i);\r
5528     \r
5529     XawDialogAddButton(dialog, "ok", FileNameCallback, (XtPointer) dialog);\r
5530     XawDialogAddButton(dialog, "cancel", FileNameCallback,\r
5531                        (XtPointer) dialog);\r
5532     \r
5533     XtRealizeWidget(popup);\r
5534     CatchDeleteWindow(popup, "FileNamePopDown");\r
5535     \r
5536     XQueryPointer(xDisplay, xBoardWindow, &root, &child,\r
5537                   &x, &y, &win_x, &win_y, &mask);\r
5538     \r
5539     XtSetArg(args[0], XtNx, x - 10);\r
5540     XtSetArg(args[1], XtNy, y - 30);\r
5541     XtSetValues(popup, args, 2);\r
5542     \r
5543     XtPopup(popup, XtGrabExclusive);\r
5544     filenameUp = True;\r
5545     \r
5546     edit = XtNameToWidget(dialog, "*value");\r
5547     XtSetKeyboardFocus(popup, edit);\r
5548 }\r
5549 \r
5550 void FileNamePopDown()\r
5551 {\r
5552     if (!filenameUp) return;\r
5553     XtPopdown(fileNameShell);\r
5554     XtDestroyWidget(fileNameShell);\r
5555     filenameUp = False;\r
5556     ModeHighlight();\r
5557 }\r
5558 \r
5559 void FileNameCallback(w, client_data, call_data)\r
5560      Widget w;\r
5561      XtPointer client_data, call_data;\r
5562 {\r
5563     String name;\r
5564     Arg args[16];\r
5565     \r
5566     XtSetArg(args[0], XtNlabel, &name);\r
5567     XtGetValues(w, args, 1);\r
5568     \r
5569     if (strcmp(name, "cancel") == 0) {\r
5570         FileNamePopDown();\r
5571         return;\r
5572     }\r
5573     \r
5574     FileNameAction(w, NULL, NULL, NULL);\r
5575 }\r
5576 \r
5577 void FileNameAction(w, event, prms, nprms)\r
5578      Widget w;\r
5579      XEvent *event;\r
5580      String *prms;\r
5581      Cardinal *nprms;\r
5582 {\r
5583     char buf[MSG_SIZ];\r
5584     String name;\r
5585     FILE *f;\r
5586     char *p, *fullname;\r
5587     int index;\r
5588 \r
5589     name = XawDialogGetValueString(w = XtParent(w));\r
5590     \r
5591     if ((name != NULL) && (*name != NULLCHAR)) {\r
5592         strcpy(buf, name);\r
5593         XtPopdown(w = XtParent(XtParent(w)));\r
5594         XtDestroyWidget(w);\r
5595         filenameUp = False;\r
5596 \r
5597         p = strrchr(buf, ' ');\r
5598         if (p == NULL) {\r
5599             index = 0;\r
5600         } else {\r
5601             *p++ = NULLCHAR;\r
5602             index = atoi(p);\r
5603         }\r
5604         fullname = ExpandPathName(buf);\r
5605         if (!fullname) {\r
5606             ErrorPopUp("Error", "Can't open file", FALSE);\r
5607         }\r
5608         else {\r
5609             f = fopen(fullname, fileOpenMode);\r
5610             if (f == NULL) {\r
5611                 DisplayError("Failed to open file", errno);\r
5612             } else {\r
5613                 (void) (*fileProc)(f, index, buf);\r
5614             }\r
5615         }\r
5616         ModeHighlight();\r
5617         return;\r
5618     }\r
5619     \r
5620     XtPopdown(w = XtParent(XtParent(w)));\r
5621     XtDestroyWidget(w);\r
5622     filenameUp = False;\r
5623     ModeHighlight();\r
5624 }\r
5625 \r
5626 void PromotionPopUp()\r
5627 {\r
5628     Arg args[16];\r
5629     Widget dialog, layout;\r
5630     Position x, y;\r
5631     Dimension bw_width, pw_width;\r
5632     int j;\r
5633 \r
5634     j = 0;\r
5635     XtSetArg(args[j], XtNwidth, &bw_width); j++;\r
5636     XtGetValues(boardWidget, args, j);\r
5637     \r
5638     j = 0;\r
5639     XtSetArg(args[j], XtNresizable, True); j++;\r
5640     promotionShell =\r
5641       XtCreatePopupShell("Promotion", transientShellWidgetClass,\r
5642                          shellWidget, args, j);\r
5643     layout =\r
5644       XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,\r
5645                             layoutArgs, XtNumber(layoutArgs));\r
5646     \r
5647     j = 0;\r
5648     XtSetArg(args[j], XtNlabel, "Promote pawn to what?"); j++;\r
5649     XtSetArg(args[j], XtNborderWidth, 0); j++;\r
5650     dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,\r
5651                                    layout, args, j);\r
5652     \r
5653     XawDialogAddButton(dialog, "Queen", PromotionCallback, \r
5654                        (XtPointer) dialog);\r
5655     XawDialogAddButton(dialog, "Rook", PromotionCallback, \r
5656                        (XtPointer) dialog);\r
5657     XawDialogAddButton(dialog, "Bishop", PromotionCallback, \r
5658                        (XtPointer) dialog);\r
5659     XawDialogAddButton(dialog, "Knight", PromotionCallback, \r
5660                        (XtPointer) dialog);\r
5661     if (!appData.testLegality || gameInfo.variant == VariantSuicide ||\r
5662         gameInfo.variant == VariantGiveaway) {\r
5663       XawDialogAddButton(dialog, "King", PromotionCallback, \r
5664                          (XtPointer) dialog);\r
5665     }\r
5666     XawDialogAddButton(dialog, "cancel", PromotionCallback, \r
5667                        (XtPointer) dialog);\r
5668     \r
5669     XtRealizeWidget(promotionShell);\r
5670     CatchDeleteWindow(promotionShell, "PromotionPopDown");\r
5671     \r
5672     j = 0;\r
5673     XtSetArg(args[j], XtNwidth, &pw_width); j++;\r
5674     XtGetValues(promotionShell, args, j);\r
5675     \r
5676     XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,\r
5677                       lineGap + squareSize/3 +\r
5678                       ((toY == BOARD_HEIGHT-1) ^ (flipView) ?\r
5679                        0 : 6*(squareSize + lineGap)), &x, &y);\r
5680     \r
5681     j = 0;\r
5682     XtSetArg(args[j], XtNx, x); j++;\r
5683     XtSetArg(args[j], XtNy, y); j++;\r
5684     XtSetValues(promotionShell, args, j);\r
5685     \r
5686     XtPopup(promotionShell, XtGrabNone);\r
5687     \r
5688     promotionUp = True;\r
5689 }\r
5690 \r
5691 void PromotionPopDown()\r
5692 {\r
5693     if (!promotionUp) return;\r
5694     XtPopdown(promotionShell);\r
5695     XtDestroyWidget(promotionShell);\r
5696     promotionUp = False;\r
5697 }\r
5698 \r
5699 void PromotionCallback(w, client_data, call_data)\r
5700      Widget w;\r
5701      XtPointer client_data, call_data;\r
5702 {\r
5703     String name;\r
5704     Arg args[16];\r
5705     int promoChar;\r
5706     \r
5707     XtSetArg(args[0], XtNlabel, &name);\r
5708     XtGetValues(w, args, 1);\r
5709     \r
5710     PromotionPopDown();\r
5711     \r
5712     if (fromX == -1) return;\r
5713     \r
5714     if (strcmp(name, "cancel") == 0) {\r
5715         fromX = fromY = -1;\r
5716         ClearHighlights();\r
5717         return;\r
5718     } else if (strcmp(name, "Knight") == 0) {\r
5719         promoChar = 'n';\r
5720     } else {\r
5721         promoChar = ToLower(name[0]);\r
5722     }\r
5723 \r
5724     UserMoveEvent(fromX, fromY, toX, toY, promoChar);\r
5725 \r
5726     if (!appData.highlightLastMove || gotPremove) ClearHighlights();\r
5727     if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);\r
5728     fromX = fromY = -1;\r
5729 }\r
5730 \r
5731 \r
5732 void ErrorCallback(w, client_data, call_data)\r
5733      Widget w;\r
5734      XtPointer client_data, call_data;\r
5735 {\r
5736     errorUp = False;\r
5737     XtPopdown(w = XtParent(XtParent(XtParent(w))));\r
5738     XtDestroyWidget(w);\r
5739     if (errorExitStatus != -1) ExitEvent(errorExitStatus);\r
5740 }\r
5741 \r
5742 \r
5743 void ErrorPopDown()\r
5744 {\r
5745     if (!errorUp) return;\r
5746     errorUp = False;\r
5747     XtPopdown(errorShell);\r
5748     XtDestroyWidget(errorShell);\r
5749     if (errorExitStatus != -1) ExitEvent(errorExitStatus);\r
5750 }\r
5751 \r
5752 void ErrorPopUp(title, label, modal)\r
5753      char *title, *label;\r
5754      int modal;\r
5755 {\r
5756     Arg args[16];\r
5757     Widget dialog, layout;\r
5758     Position x, y;\r
5759     int xx, yy;\r
5760     Window junk;\r
5761     Dimension bw_width, pw_width;\r
5762     Dimension pw_height;\r
5763     int i;\r
5764     \r
5765     i = 0;\r
5766     XtSetArg(args[i], XtNresizable, True);  i++;\r
5767     XtSetArg(args[i], XtNtitle, title); i++;\r
5768     errorShell = \r
5769       XtCreatePopupShell("errorpopup", transientShellWidgetClass,\r
5770                          shellWidget, args, i);\r
5771     layout =\r
5772       XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,\r
5773                             layoutArgs, XtNumber(layoutArgs));\r
5774     \r
5775     i = 0;\r
5776     XtSetArg(args[i], XtNlabel, label); i++;\r
5777     XtSetArg(args[i], XtNborderWidth, 0); i++;\r
5778     dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,\r
5779                                    layout, args, i);\r
5780     \r
5781     XawDialogAddButton(dialog, "ok", ErrorCallback, (XtPointer) dialog);\r
5782     \r
5783     XtRealizeWidget(errorShell);\r
5784     CatchDeleteWindow(errorShell, "ErrorPopDown");\r
5785     \r
5786     i = 0;\r
5787     XtSetArg(args[i], XtNwidth, &bw_width);  i++;\r
5788     XtGetValues(boardWidget, args, i);\r
5789     i = 0;\r
5790     XtSetArg(args[i], XtNwidth, &pw_width);  i++;\r
5791     XtSetArg(args[i], XtNheight, &pw_height);  i++;\r
5792     XtGetValues(errorShell, args, i);\r
5793 \r
5794 #ifdef NOTDEF\r
5795     /* This code seems to tickle an X bug if it is executed too soon\r
5796        after xboard starts up.  The coordinates get transformed as if\r
5797        the main window was positioned at (0, 0).\r
5798        */\r
5799     XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,\r
5800                       0 - pw_height + squareSize / 3, &x, &y);\r
5801 #else\r
5802     XTranslateCoordinates(xDisplay, XtWindow(boardWidget),\r
5803                           RootWindowOfScreen(XtScreen(boardWidget)),\r
5804                           (bw_width - pw_width) / 2,\r
5805                           0 - pw_height + squareSize / 3, &xx, &yy, &junk);\r
5806     x = xx;\r
5807     y = yy;\r
5808 #endif\r
5809     if (y < 0) y = 0; /*avoid positioning top offscreen*/\r
5810 \r
5811     i = 0;\r
5812     XtSetArg(args[i], XtNx, x);  i++;\r
5813     XtSetArg(args[i], XtNy, y);  i++;\r
5814     XtSetValues(errorShell, args, i);\r
5815 \r
5816     errorUp = True;\r
5817     XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);\r
5818 }\r
5819 \r
5820 /* Disable all user input other than deleting the window */\r
5821 static int frozen = 0;\r
5822 void FreezeUI()\r
5823 {\r
5824   if (frozen) return;\r
5825   /* Grab by a widget that doesn't accept input */\r
5826   XtAddGrab(messageWidget, TRUE, FALSE);\r
5827   frozen = 1;\r
5828 }\r
5829 \r
5830 /* Undo a FreezeUI */\r
5831 void ThawUI()\r
5832 {\r
5833   if (!frozen) return;\r
5834   XtRemoveGrab(messageWidget);\r
5835   frozen = 0;\r
5836 }\r
5837 \r
5838 char *ModeToWidgetName(mode)\r
5839      GameMode mode;\r
5840 {\r
5841     switch (mode) {\r
5842       case BeginningOfGame:\r
5843         if (appData.icsActive)\r
5844           return "menuMode.ICS Client";\r
5845         else if (appData.noChessProgram ||\r
5846                  *appData.cmailGameName != NULLCHAR)\r
5847           return "menuMode.Edit Game";\r
5848         else\r
5849           return "menuMode.Machine Black";\r
5850       case MachinePlaysBlack:\r
5851         return "menuMode.Machine Black";\r
5852       case MachinePlaysWhite:\r
5853         return "menuMode.Machine White";\r
5854       case AnalyzeMode:\r
5855         return "menuMode.Analysis Mode";\r
5856       case AnalyzeFile:\r
5857         return "menuMode.Analyze File";\r
5858       case TwoMachinesPlay:\r
5859         return "menuMode.Two Machines";\r
5860       case EditGame:\r
5861         return "menuMode.Edit Game";\r
5862       case PlayFromGameFile:\r
5863         return "menuFile.Load Game";\r
5864       case EditPosition:\r
5865         return "menuMode.Edit Position";\r
5866       case Training:\r
5867         return "menuMode.Training";\r
5868       case IcsPlayingWhite:\r
5869       case IcsPlayingBlack:\r
5870       case IcsObserving:\r
5871       case IcsIdle:\r
5872       case IcsExamining:\r
5873         return "menuMode.ICS Client";\r
5874       default:\r
5875       case EndOfGame:\r
5876         return NULL;\r
5877     }\r
5878 }     \r
5879 \r
5880 void ModeHighlight()\r
5881 {\r
5882     Arg args[16];\r
5883     static int oldPausing = FALSE;\r
5884     static GameMode oldmode = (GameMode) -1;\r
5885     char *wname;\r
5886     \r
5887     if (!boardWidget || !XtIsRealized(boardWidget)) return;\r
5888 \r
5889     if (pausing != oldPausing) {\r
5890         oldPausing = pausing;\r
5891         if (pausing) {\r
5892             XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);\r
5893         } else {\r
5894             XtSetArg(args[0], XtNleftBitmap, None);\r
5895         }\r
5896         XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),\r
5897                     args, 1);\r
5898 \r
5899         if (appData.showButtonBar) {\r
5900 #if 0\r
5901           if (pausing) {\r
5902             XtSetArg(args[0], XtNbackground, buttonForegroundPixel);\r
5903             XtSetArg(args[1], XtNforeground, buttonBackgroundPixel);\r
5904           } else {\r
5905             XtSetArg(args[0], XtNbackground, buttonBackgroundPixel);\r
5906             XtSetArg(args[1], XtNforeground, buttonForegroundPixel);\r
5907           }\r
5908 #else\r
5909           /* Always toggle, don't set.  Previous code messes up when\r
5910              invoked while the button is pressed, as releasing it\r
5911              toggles the state again. */\r
5912           {\r
5913             Pixel oldbg, oldfg;\r
5914             XtSetArg(args[0], XtNbackground, &oldbg);\r
5915             XtSetArg(args[1], XtNforeground, &oldfg);\r
5916             XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),\r
5917                         args, 2);\r
5918             XtSetArg(args[0], XtNbackground, oldfg);\r
5919             XtSetArg(args[1], XtNforeground, oldbg);\r
5920           }\r
5921 #endif\r
5922           XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);\r
5923         }\r
5924     }\r
5925 \r
5926     wname = ModeToWidgetName(oldmode);\r
5927     if (wname != NULL) {\r
5928         XtSetArg(args[0], XtNleftBitmap, None);\r
5929         XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);\r
5930     }\r
5931     wname = ModeToWidgetName(gameMode);\r
5932     if (wname != NULL) {\r
5933         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);\r
5934         XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);\r
5935     }\r
5936     oldmode = gameMode;\r
5937 \r
5938     /* Maybe all the enables should be handled here, not just this one */\r
5939     XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),\r
5940                    gameMode == Training || gameMode == PlayFromGameFile);\r
5941 }\r
5942 \r
5943 \r
5944 /*\r
5945  * Button/menu procedures\r
5946  */\r
5947 void ResetProc(w, event, prms, nprms)\r
5948      Widget w;\r
5949      XEvent *event;\r
5950      String *prms;\r
5951      Cardinal *nprms;\r
5952 {\r
5953     ResetGameEvent();\r
5954     AnalysisPopDown();\r
5955 }\r
5956 \r
5957 int LoadGamePopUp(f, gameNumber, title)\r
5958      FILE *f;\r
5959      int gameNumber;\r
5960      char *title;\r
5961 {\r
5962     cmailMsgLoaded = FALSE;\r
5963     if (gameNumber == 0) {\r
5964         int error = GameListBuild(f);\r
5965         if (error) {\r
5966             DisplayError("Cannot build game list", error);\r
5967         } else if (!ListEmpty(&gameList) &&\r
5968                    ((ListGame *) gameList.tailPred)->number > 1) {\r
5969             GameListPopUp(f, title);\r
5970             return TRUE;\r
5971         }\r
5972         GameListDestroy();\r
5973         gameNumber = 1;\r
5974     }\r
5975     return LoadGame(f, gameNumber, title, FALSE);\r
5976 }\r
5977 \r
5978 void LoadGameProc(w, event, prms, nprms)\r
5979      Widget w;\r
5980      XEvent *event;\r
5981      String *prms;\r
5982      Cardinal *nprms;\r
5983 {\r
5984     if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {\r
5985         Reset(FALSE, TRUE);\r
5986     }\r
5987     FileNamePopUp("Load game file name?", "", LoadGamePopUp, "rb");\r
5988 }\r
5989 \r
5990 void LoadNextGameProc(w, event, prms, nprms)\r
5991      Widget w;\r
5992      XEvent *event;\r
5993      String *prms;\r
5994      Cardinal *nprms;\r
5995 {\r
5996     ReloadGame(1);\r
5997 }\r
5998 \r
5999 void LoadPrevGameProc(w, event, prms, nprms)\r
6000      Widget w;\r
6001      XEvent *event;\r
6002      String *prms;\r
6003      Cardinal *nprms;\r
6004 {\r
6005     ReloadGame(-1);\r
6006 }\r
6007 \r
6008 void ReloadGameProc(w, event, prms, nprms)\r
6009      Widget w;\r
6010      XEvent *event;\r
6011      String *prms;\r
6012      Cardinal *nprms;\r
6013 {\r
6014     ReloadGame(0);\r
6015 }\r
6016 \r
6017 void LoadNextPositionProc(w, event, prms, nprms)\r
6018      Widget w;\r
6019      XEvent *event;\r
6020      String *prms;\r
6021      Cardinal *nprms;\r
6022 {\r
6023     ReloadPosition(1);\r
6024 }\r
6025 \r
6026 void LoadPrevPositionProc(w, event, prms, nprms)\r
6027      Widget w;\r
6028      XEvent *event;\r
6029      String *prms;\r
6030      Cardinal *nprms;\r
6031 {\r
6032     ReloadPosition(-1);\r
6033 }\r
6034 \r
6035 void ReloadPositionProc(w, event, prms, nprms)\r
6036      Widget w;\r
6037      XEvent *event;\r
6038      String *prms;\r
6039      Cardinal *nprms;\r
6040 {\r
6041     ReloadPosition(0);\r
6042 }\r
6043 \r
6044 void LoadPositionProc(w, event, prms, nprms)\r
6045      Widget w;\r
6046      XEvent *event;\r
6047      String *prms;\r
6048      Cardinal *nprms;\r
6049 {\r
6050     if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {\r
6051         Reset(FALSE, TRUE);\r
6052     }\r
6053     FileNamePopUp("Load position file name?", "", LoadPosition, "rb");\r
6054 }\r
6055 \r
6056 void SaveGameProc(w, event, prms, nprms)\r
6057      Widget w;\r
6058      XEvent *event;\r
6059      String *prms;\r
6060      Cardinal *nprms;\r
6061 {\r
6062     FileNamePopUp("Save game file name?",\r
6063                   DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),\r
6064                   SaveGame, "a");\r
6065 }\r
6066 \r
6067 void SavePositionProc(w, event, prms, nprms)\r
6068      Widget w;\r
6069      XEvent *event;\r
6070      String *prms;\r
6071      Cardinal *nprms;\r
6072 {\r
6073     FileNamePopUp("Save position file name?",\r
6074                   DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),\r
6075                   SavePosition, "a");\r
6076 }\r
6077 \r
6078 void ReloadCmailMsgProc(w, event, prms, nprms)\r
6079      Widget w;\r
6080      XEvent *event;\r
6081      String *prms;\r
6082      Cardinal *nprms;\r
6083 {\r
6084     ReloadCmailMsgEvent(FALSE);\r
6085 }\r
6086 \r
6087 void MailMoveProc(w, event, prms, nprms)\r
6088      Widget w;\r
6089      XEvent *event;\r
6090      String *prms;\r
6091      Cardinal *nprms;\r
6092 {\r
6093     MailMoveEvent();\r
6094 }\r
6095 \r
6096 /* this variable is shared between CopyPositionProc and SendPositionSelection */\r
6097 static char *selected_fen_position=NULL;\r
6098 \r
6099 static Boolean\r
6100 SendPositionSelection(Widget w, Atom *selection, Atom *target,\r
6101                  Atom *type_return, XtPointer *value_return,\r
6102                  unsigned long *length_return, int *format_return)\r
6103 {\r
6104   char *selection_tmp;\r
6105 \r
6106   if (!selected_fen_position) return False; /* should never happen */\r
6107   if (*target == XA_STRING){\r
6108     /* note: since no XtSelectionDoneProc was registered, Xt will\r
6109      * automatically call XtFree on the value returned.  So have to\r
6110      * make a copy of it allocated with XtMalloc */\r
6111     selection_tmp= XtMalloc(strlen(selected_fen_position)+16);\r
6112     strcpy(selection_tmp, selected_fen_position);\r
6113 \r
6114     *value_return=selection_tmp;\r
6115     *length_return=strlen(selection_tmp);\r
6116     *type_return=XA_STRING;\r
6117     *format_return = 8; /* bits per byte */\r
6118     return True;\r
6119   } else {\r
6120     return False;\r
6121   } \r
6122 }\r
6123 \r
6124 /* note: when called from menu all parameters are NULL, so no clue what the\r
6125  * Widget which was clicked on was, or what the click event was\r
6126  */\r
6127 void CopyPositionProc(w, event, prms, nprms)\r
6128   Widget w;\r
6129   XEvent *event;\r
6130   String *prms;\r
6131   Cardinal *nprms;\r
6132   {\r
6133     int ret;\r
6134 \r
6135     if (selected_fen_position) free(selected_fen_position);\r
6136     selected_fen_position = (char *)PositionToFEN(currentMove,1);\r
6137     if (!selected_fen_position) return;\r
6138     ret = XtOwnSelection(menuBarWidget, XA_PRIMARY,\r
6139                          CurrentTime,\r
6140                          SendPositionSelection,\r
6141                          NULL/* lose_ownership_proc */ ,\r
6142                          NULL/* transfer_done_proc */);\r
6143     if (!ret) {\r
6144       free(selected_fen_position);\r
6145       selected_fen_position=NULL;\r
6146     }\r
6147   }\r
6148 \r
6149 /* function called when the data to Paste is ready */\r
6150 static void\r
6151 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,\r
6152            Atom *type, XtPointer value, unsigned long *len, int *format)\r
6153 {\r
6154   char *fenstr=value;\r
6155   if (value==NULL || *len==0) return; /* nothing had been selected to copy */\r
6156   fenstr[*len]='\0'; /* normally this string is terminated, but be safe */\r
6157   EditPositionPasteFEN(fenstr);\r
6158   XtFree(value);\r
6159 }\r
6160 \r
6161 /* called when Paste Position button is pressed,\r
6162  * all parameters will be NULL */\r
6163 void PastePositionProc(w, event, prms, nprms)\r
6164   Widget w;\r
6165   XEvent *event;\r
6166   String *prms;\r
6167   Cardinal *nprms;\r
6168 {\r
6169     XtGetSelectionValue(menuBarWidget, XA_PRIMARY, XA_STRING,\r
6170       /* (XtSelectionCallbackProc) */ PastePositionCB,\r
6171       NULL, /* client_data passed to PastePositionCB */\r
6172 \r
6173       /* better to use the time field from the event that triggered the\r
6174        * call to this function, but that isn't trivial to get\r
6175        */\r
6176       CurrentTime\r
6177     );\r
6178     return;\r
6179 }\r
6180 \r
6181 static Boolean\r
6182 SendGameSelection(Widget w, Atom *selection, Atom *target,\r
6183                   Atom *type_return, XtPointer *value_return,\r
6184                   unsigned long *length_return, int *format_return)\r
6185 {\r
6186   char *selection_tmp;\r
6187 \r
6188   if (*target == XA_STRING){\r
6189     FILE* f = fopen(gameCopyFilename, "r");\r
6190     long len;\r
6191     size_t count;\r
6192     if (f == NULL) return False;\r
6193     fseek(f, 0, 2);\r
6194     len = ftell(f);\r
6195     rewind(f);\r
6196     selection_tmp = XtMalloc(len + 1);\r
6197     count = fread(selection_tmp, 1, len, f);\r
6198     if (len != count) {\r
6199       XtFree(selection_tmp);\r
6200       return False;\r
6201     }\r
6202     selection_tmp[len] = NULLCHAR;\r
6203     *value_return = selection_tmp;\r
6204     *length_return = len;\r
6205     *type_return = XA_STRING;\r
6206     *format_return = 8; /* bits per byte */\r
6207     return True;\r
6208   } else {\r
6209     return False;\r
6210   } \r
6211 }\r
6212 \r
6213 /* note: when called from menu all parameters are NULL, so no clue what the\r
6214  * Widget which was clicked on was, or what the click event was\r
6215  */\r
6216 void CopyGameProc(w, event, prms, nprms)\r
6217   Widget w;\r
6218   XEvent *event;\r
6219   String *prms;\r
6220   Cardinal *nprms;\r
6221 {\r
6222   int ret;\r
6223 \r
6224   ret = SaveGameToFile(gameCopyFilename, FALSE);\r
6225   if (!ret) return;\r
6226 \r
6227   ret = XtOwnSelection(menuBarWidget, XA_PRIMARY,\r
6228                        CurrentTime,\r
6229                        SendGameSelection,\r
6230                        NULL/* lose_ownership_proc */ ,\r
6231                        NULL/* transfer_done_proc */);\r
6232 }\r
6233 \r
6234 /* function called when the data to Paste is ready */\r
6235 static void\r
6236 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,\r
6237             Atom *type, XtPointer value, unsigned long *len, int *format)\r
6238 {\r
6239   FILE* f;\r
6240   if (value == NULL || *len == 0) {\r
6241     return; /* nothing had been selected to copy */\r
6242   }\r
6243   f = fopen(gamePasteFilename, "w");\r
6244   if (f == NULL) {\r
6245     DisplayError("Can't open temp file", errno);\r
6246     return;\r
6247   }\r
6248   fwrite(value, 1, *len, f);\r
6249   fclose(f);\r
6250   XtFree(value);\r
6251   LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);\r
6252 }\r
6253 \r
6254 /* called when Paste Game button is pressed,\r
6255  * all parameters will be NULL */\r
6256 void PasteGameProc(w, event, prms, nprms)\r
6257   Widget w;\r
6258   XEvent *event;\r
6259   String *prms;\r
6260   Cardinal *nprms;\r
6261 {\r
6262     XtGetSelectionValue(menuBarWidget, XA_PRIMARY, XA_STRING,\r
6263       /* (XtSelectionCallbackProc) */ PasteGameCB,\r
6264       NULL, /* client_data passed to PasteGameCB */\r
6265 \r
6266       /* better to use the time field from the event that triggered the\r
6267        * call to this function, but that isn't trivial to get\r
6268        */\r
6269       CurrentTime\r
6270     );\r
6271     return;\r
6272 }\r
6273 \r
6274 \r
6275 void AutoSaveGame()\r
6276 {\r
6277     SaveGameProc(NULL, NULL, NULL, NULL);\r
6278 }\r
6279 \r
6280 \r
6281 void QuitProc(w, event, prms, nprms)\r
6282      Widget w;\r
6283      XEvent *event;\r
6284      String *prms;\r
6285      Cardinal *nprms;\r
6286 {\r
6287     ExitEvent(0);\r
6288 }\r
6289 \r
6290 void PauseProc(w, event, prms, nprms)\r
6291      Widget w;\r
6292      XEvent *event;\r
6293      String *prms;\r
6294      Cardinal *nprms;\r
6295 {\r
6296     PauseEvent();\r
6297 }\r
6298 \r
6299 \r
6300 void MachineBlackProc(w, event, prms, nprms)\r
6301      Widget w;\r
6302      XEvent *event;\r
6303      String *prms;\r
6304      Cardinal *nprms;\r
6305 {\r
6306     MachineBlackEvent();\r
6307 }\r
6308 \r
6309 void MachineWhiteProc(w, event, prms, nprms)\r
6310      Widget w;\r
6311      XEvent *event;\r
6312      String *prms;\r
6313      Cardinal *nprms;\r
6314 {\r
6315     MachineWhiteEvent();\r
6316 }\r
6317 \r
6318 void AnalyzeModeProc(w, event, prms, nprms)\r
6319      Widget w;\r
6320      XEvent *event;\r
6321      String *prms;\r
6322      Cardinal *nprms;\r
6323 {\r
6324     if (!first.analysisSupport) {\r
6325       char buf[MSG_SIZ];\r
6326       sprintf(buf, "%s does not support analysis", first.tidy);\r
6327       DisplayError(buf, 0);\r
6328       return;\r
6329     }\r
6330     if (!appData.showThinking)\r
6331       ShowThinkingProc(w,event,prms,nprms);\r
6332 \r
6333     AnalyzeModeEvent();\r
6334 }\r
6335 \r
6336 void AnalyzeFileProc(w, event, prms, nprms)\r
6337      Widget w;\r
6338      XEvent *event;\r
6339      String *prms;\r
6340      Cardinal *nprms;\r
6341 {\r
6342     if (!first.analysisSupport) {\r
6343       char buf[MSG_SIZ];\r
6344       sprintf(buf, "%s does not support analysis", first.tidy);\r
6345       DisplayError(buf, 0);\r
6346       return;\r
6347     }\r
6348     Reset(FALSE, TRUE);\r
6349 \r
6350     if (!appData.showThinking)\r
6351       ShowThinkingProc(w,event,prms,nprms);\r
6352 \r
6353     AnalyzeFileEvent();\r
6354     FileNamePopUp("File to analyze", "", LoadGamePopUp, "rb");\r
6355     AnalysisPeriodicEvent(1);\r
6356 }\r
6357 \r
6358 void TwoMachinesProc(w, event, prms, nprms)\r
6359      Widget w;\r
6360      XEvent *event;\r
6361      String *prms;\r
6362      Cardinal *nprms;\r
6363 {\r
6364     TwoMachinesEvent();\r
6365 }\r
6366 \r
6367 void IcsClientProc(w, event, prms, nprms)\r
6368      Widget w;\r
6369      XEvent *event;\r
6370      String *prms;\r
6371      Cardinal *nprms;\r
6372 {\r
6373     IcsClientEvent();\r
6374 }\r
6375 \r
6376 void EditGameProc(w, event, prms, nprms)\r
6377      Widget w;\r
6378      XEvent *event;\r
6379      String *prms;\r
6380      Cardinal *nprms;\r
6381 {\r
6382     EditGameEvent();\r
6383 }\r
6384 \r
6385 void EditPositionProc(w, event, prms, nprms)\r
6386      Widget w;\r
6387      XEvent *event;\r
6388      String *prms;\r
6389      Cardinal *nprms;\r
6390 {\r
6391     EditPositionEvent();\r
6392 }\r
6393 \r
6394 void TrainingProc(w, event, prms, nprms)\r
6395      Widget w;\r
6396      XEvent *event;\r
6397      String *prms;\r
6398      Cardinal *nprms;\r
6399 {\r
6400     TrainingEvent();\r
6401 }\r
6402 \r
6403 void EditCommentProc(w, event, prms, nprms)\r
6404      Widget w;\r
6405      XEvent *event;\r
6406      String *prms;\r
6407      Cardinal *nprms;\r
6408 {\r
6409     if (editUp) {\r
6410         EditCommentPopDown();\r
6411     } else {\r
6412         EditCommentEvent();\r
6413     }\r
6414 }\r
6415 \r
6416 void IcsInputBoxProc(w, event, prms, nprms)\r
6417      Widget w;\r
6418      XEvent *event;\r
6419      String *prms;\r
6420      Cardinal *nprms;\r
6421 {\r
6422     if (ICSInputBoxUp) {\r
6423         ICSInputBoxPopDown();\r
6424     } else {\r
6425         ICSInputBoxPopUp();\r
6426     }\r
6427 }\r
6428 \r
6429 void AcceptProc(w, event, prms, nprms)\r
6430      Widget w;\r
6431      XEvent *event;\r
6432      String *prms;\r
6433      Cardinal *nprms;\r
6434 {\r
6435     AcceptEvent();\r
6436 }\r
6437 \r
6438 void DeclineProc(w, event, prms, nprms)\r
6439      Widget w;\r
6440      XEvent *event;\r
6441      String *prms;\r
6442      Cardinal *nprms;\r
6443 {\r
6444     DeclineEvent();\r
6445 }\r
6446 \r
6447 void RematchProc(w, event, prms, nprms)\r
6448      Widget w;\r
6449      XEvent *event;\r
6450      String *prms;\r
6451      Cardinal *nprms;\r
6452 {\r
6453     RematchEvent();\r
6454 }\r
6455 \r
6456 void CallFlagProc(w, event, prms, nprms)\r
6457      Widget w;\r
6458      XEvent *event;\r
6459      String *prms;\r
6460      Cardinal *nprms;\r
6461 {\r
6462     CallFlagEvent();\r
6463 }\r
6464 \r
6465 void DrawProc(w, event, prms, nprms)\r
6466      Widget w;\r
6467      XEvent *event;\r
6468      String *prms;\r
6469      Cardinal *nprms;\r
6470 {\r
6471     DrawEvent();\r
6472 }\r
6473 \r
6474 void AbortProc(w, event, prms, nprms)\r
6475      Widget w;\r
6476      XEvent *event;\r
6477      String *prms;\r
6478      Cardinal *nprms;\r
6479 {\r
6480     AbortEvent();\r
6481 }\r
6482 \r
6483 void AdjournProc(w, event, prms, nprms)\r
6484      Widget w;\r
6485      XEvent *event;\r
6486      String *prms;\r
6487      Cardinal *nprms;\r
6488 {\r
6489     AdjournEvent();\r
6490 }\r
6491 \r
6492 void ResignProc(w, event, prms, nprms)\r
6493      Widget w;\r
6494      XEvent *event;\r
6495      String *prms;\r
6496      Cardinal *nprms;\r
6497 {\r
6498     ResignEvent();\r
6499 }\r
6500 \r
6501 void EnterKeyProc(w, event, prms, nprms)\r
6502      Widget w;\r
6503      XEvent *event;\r
6504      String *prms;\r
6505      Cardinal *nprms;\r
6506 {\r
6507     if (ICSInputBoxUp == True)\r
6508       ICSInputSendText();\r
6509 }\r
6510 \r
6511 void StopObservingProc(w, event, prms, nprms)\r
6512      Widget w;\r
6513      XEvent *event;\r
6514      String *prms;\r
6515      Cardinal *nprms;\r
6516 {\r
6517     StopObservingEvent();\r
6518 }\r
6519 \r
6520 void StopExaminingProc(w, event, prms, nprms)\r
6521      Widget w;\r
6522      XEvent *event;\r
6523      String *prms;\r
6524      Cardinal *nprms;\r
6525 {\r
6526     StopExaminingEvent();\r
6527 }\r
6528 \r
6529 \r
6530 void ForwardProc(w, event, prms, nprms)\r
6531      Widget w;\r
6532      XEvent *event;\r
6533      String *prms;\r
6534      Cardinal *nprms;\r
6535 {\r
6536     ForwardEvent();\r
6537 }\r
6538 \r
6539 \r
6540 void BackwardProc(w, event, prms, nprms)\r
6541      Widget w;\r
6542      XEvent *event;\r
6543      String *prms;\r
6544      Cardinal *nprms;\r
6545 {\r
6546     BackwardEvent();\r
6547 }\r
6548 \r
6549 void ToStartProc(w, event, prms, nprms)\r
6550      Widget w;\r
6551      XEvent *event;\r
6552      String *prms;\r
6553      Cardinal *nprms;\r
6554 {\r
6555     ToStartEvent();\r
6556 }\r
6557 \r
6558 void ToEndProc(w, event, prms, nprms)\r
6559      Widget w;\r
6560      XEvent *event;\r
6561      String *prms;\r
6562      Cardinal *nprms;\r
6563 {\r
6564     ToEndEvent();\r
6565 }\r
6566 \r
6567 void RevertProc(w, event, prms, nprms)\r
6568      Widget w;\r
6569      XEvent *event;\r
6570      String *prms;\r
6571      Cardinal *nprms;\r
6572 {\r
6573     RevertEvent();\r
6574 }\r
6575 \r
6576 void TruncateGameProc(w, event, prms, nprms)\r
6577      Widget w;\r
6578      XEvent *event;\r
6579      String *prms;\r
6580      Cardinal *nprms;\r
6581 {\r
6582     TruncateGameEvent();\r
6583 }\r
6584 void RetractMoveProc(w, event, prms, nprms)\r
6585      Widget w;\r
6586      XEvent *event;\r
6587      String *prms;\r
6588      Cardinal *nprms;\r
6589 {\r
6590     RetractMoveEvent();\r
6591 }\r
6592 \r
6593 void MoveNowProc(w, event, prms, nprms)\r
6594      Widget w;\r
6595      XEvent *event;\r
6596      String *prms;\r
6597      Cardinal *nprms;\r
6598 {\r
6599     MoveNowEvent();\r
6600 }\r
6601 \r
6602 \r
6603 void AlwaysQueenProc(w, event, prms, nprms)\r
6604      Widget w;\r
6605      XEvent *event;\r
6606      String *prms;\r
6607      Cardinal *nprms;\r
6608 {\r
6609     Arg args[16];\r
6610 \r
6611     appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;\r
6612 \r
6613     if (appData.alwaysPromoteToQueen) {\r
6614         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);\r
6615     } else {\r
6616         XtSetArg(args[0], XtNleftBitmap, None);\r
6617     }\r
6618     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),\r
6619                 args, 1);\r
6620 }\r
6621 \r
6622 void AnimateDraggingProc(w, event, prms, nprms)\r
6623      Widget w;\r
6624      XEvent *event;\r
6625      String *prms;\r
6626      Cardinal *nprms;\r
6627 {\r
6628     Arg args[16];\r
6629 \r
6630     appData.animateDragging = !appData.animateDragging;\r
6631 \r
6632     if (appData.animateDragging) {\r
6633         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);\r
6634         CreateAnimVars();\r
6635     } else {\r
6636         XtSetArg(args[0], XtNleftBitmap, None);\r
6637     }\r
6638     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),\r
6639                 args, 1);\r
6640 }\r
6641 \r
6642 void AnimateMovingProc(w, event, prms, nprms)\r
6643      Widget w;\r
6644      XEvent *event;\r
6645      String *prms;\r
6646      Cardinal *nprms;\r
6647 {\r
6648     Arg args[16];\r
6649 \r
6650     appData.animate = !appData.animate;\r
6651 \r
6652     if (appData.animate) {\r
6653         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);\r
6654         CreateAnimVars();\r
6655     } else {\r
6656         XtSetArg(args[0], XtNleftBitmap, None);\r
6657     }\r
6658     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),\r
6659                 args, 1);\r
6660 }\r
6661 \r
6662 void AutocommProc(w, event, prms, nprms)\r
6663      Widget w;\r
6664      XEvent *event;\r
6665      String *prms;\r
6666      Cardinal *nprms;\r
6667 {\r
6668     Arg args[16];\r
6669 \r
6670     appData.autoComment = !appData.autoComment;\r
6671 \r
6672     if (appData.autoComment) {\r
6673         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);\r
6674     } else {\r
6675         XtSetArg(args[0], XtNleftBitmap, None);\r
6676     }\r
6677     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),\r
6678                 args, 1);\r
6679 }\r
6680 \r
6681 \r
6682 void AutoflagProc(w, event, prms, nprms)\r
6683      Widget w;\r
6684      XEvent *event;\r
6685      String *prms;\r
6686      Cardinal *nprms;\r
6687 {\r
6688     Arg args[16];\r
6689 \r
6690     appData.autoCallFlag = !appData.autoCallFlag;\r
6691 \r
6692     if (appData.autoCallFlag) {\r
6693         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);\r
6694     } else {\r
6695         XtSetArg(args[0], XtNleftBitmap, None);\r
6696     }\r
6697     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),\r
6698                 args, 1);\r
6699 }\r
6700 \r
6701 void AutoflipProc(w, event, prms, nprms)\r
6702      Widget w;\r
6703      XEvent *event;\r
6704      String *prms;\r
6705      Cardinal *nprms;\r
6706 {\r
6707     Arg args[16];\r
6708 \r
6709     appData.autoFlipView = !appData.autoFlipView;\r
6710 \r
6711     if (appData.autoFlipView) {\r
6712         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);\r
6713     } else {\r
6714         XtSetArg(args[0], XtNleftBitmap, None);\r
6715     }\r
6716     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),\r
6717                 args, 1);\r
6718 }\r
6719 \r
6720 void AutobsProc(w, event, prms, nprms)\r
6721      Widget w;\r
6722      XEvent *event;\r
6723      String *prms;\r
6724      Cardinal *nprms;\r
6725 {\r
6726     Arg args[16];\r
6727 \r
6728     appData.autoObserve = !appData.autoObserve;\r
6729 \r
6730     if (appData.autoObserve) {\r
6731         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);\r
6732     } else {\r
6733         XtSetArg(args[0], XtNleftBitmap, None);\r
6734     }\r
6735     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),\r
6736                 args, 1);\r
6737 }\r
6738 \r
6739 void AutoraiseProc(w, event, prms, nprms)\r
6740      Widget w;\r
6741      XEvent *event;\r
6742      String *prms;\r
6743      Cardinal *nprms;\r
6744 {\r
6745     Arg args[16];\r
6746 \r
6747     appData.autoRaiseBoard = !appData.autoRaiseBoard;\r
6748 \r
6749     if (appData.autoRaiseBoard) {\r
6750         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);\r
6751     } else {\r
6752         XtSetArg(args[0], XtNleftBitmap, None);\r
6753     }\r
6754     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),\r
6755                 args, 1);\r
6756 }\r
6757 \r
6758 void AutosaveProc(w, event, prms, nprms)\r
6759      Widget w;\r
6760      XEvent *event;\r
6761      String *prms;\r
6762      Cardinal *nprms;\r
6763 {\r
6764     Arg args[16];\r
6765 \r
6766     appData.autoSaveGames = !appData.autoSaveGames;\r
6767 \r
6768     if (appData.autoSaveGames) {\r
6769         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);\r
6770     } else {\r
6771         XtSetArg(args[0], XtNleftBitmap, None);\r
6772     }\r
6773     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),\r
6774                 args, 1);\r
6775 }\r
6776 \r
6777 void BlindfoldProc(w, event, prms, nprms)\r
6778      Widget w;\r
6779      XEvent *event;\r
6780      String *prms;\r
6781      Cardinal *nprms;\r
6782 {\r
6783     Arg args[16];\r
6784 \r
6785     appData.blindfold = !appData.blindfold;\r
6786 \r
6787     if (appData.blindfold) {\r
6788         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);\r
6789     } else {\r
6790         XtSetArg(args[0], XtNleftBitmap, None);\r
6791     }\r
6792     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),\r
6793                 args, 1);\r
6794 \r
6795     DrawPosition(True, NULL);\r
6796 }\r
6797 \r
6798 void TestLegalityProc(w, event, prms, nprms)\r
6799      Widget w;\r
6800      XEvent *event;\r
6801      String *prms;\r
6802      Cardinal *nprms;\r
6803 {\r
6804     Arg args[16];\r
6805 \r
6806     appData.testLegality = !appData.testLegality;\r
6807 \r
6808     if (appData.testLegality) {\r
6809         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);\r
6810     } else {\r
6811         XtSetArg(args[0], XtNleftBitmap, None);\r
6812     }\r
6813     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),\r
6814                 args, 1);\r
6815 }\r
6816 \r
6817 \r
6818 void FlashMovesProc(w, event, prms, nprms)\r
6819      Widget w;\r
6820      XEvent *event;\r
6821      String *prms;\r
6822      Cardinal *nprms;\r
6823 {\r
6824     Arg args[16];\r
6825 \r
6826     if (appData.flashCount == 0) {\r
6827         appData.flashCount = 3;\r
6828     } else {\r
6829         appData.flashCount = -appData.flashCount;\r
6830     }\r
6831 \r
6832     if (appData.flashCount > 0) {\r
6833         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);\r
6834     } else {\r
6835         XtSetArg(args[0], XtNleftBitmap, None);\r
6836     }\r
6837     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),\r
6838                 args, 1);\r
6839 }\r
6840 \r
6841 void FlipViewProc(w, event, prms, nprms)\r
6842      Widget w;\r
6843      XEvent *event;\r
6844      String *prms;\r
6845      Cardinal *nprms;\r
6846 {\r
6847     flipView = !flipView;\r
6848     DrawPosition(True, NULL);\r
6849 }\r
6850 \r
6851 void GetMoveListProc(w, event, prms, nprms)\r
6852      Widget w;\r
6853      XEvent *event;\r
6854      String *prms;\r
6855      Cardinal *nprms;\r
6856 {\r
6857     Arg args[16];\r
6858 \r
6859     appData.getMoveList = !appData.getMoveList;\r
6860 \r
6861     if (appData.getMoveList) {\r
6862         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);\r
6863         GetMoveListEvent();\r
6864     } else {\r
6865         XtSetArg(args[0], XtNleftBitmap, None);\r
6866     }\r
6867     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),\r
6868                 args, 1);\r
6869 }\r
6870 \r
6871 #if HIGHDRAG\r
6872 void HighlightDraggingProc(w, event, prms, nprms)\r
6873      Widget w;\r
6874      XEvent *event;\r
6875      String *prms;\r
6876      Cardinal *nprms;\r
6877 {\r
6878     Arg args[16];\r
6879 \r
6880     appData.highlightDragging = !appData.highlightDragging;\r
6881 \r
6882     if (appData.highlightDragging) {\r
6883         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);\r
6884     } else {\r
6885         XtSetArg(args[0], XtNleftBitmap, None);\r
6886     }\r
6887     XtSetValues(XtNameToWidget(menuBarWidget,\r
6888                                "menuOptions.Highlight Dragging"), args, 1);\r
6889 }\r
6890 #endif\r
6891 \r
6892 void HighlightLastMoveProc(w, event, prms, nprms)\r
6893      Widget w;\r
6894      XEvent *event;\r
6895      String *prms;\r
6896      Cardinal *nprms;\r
6897 {\r
6898     Arg args[16];\r
6899 \r
6900     appData.highlightLastMove = !appData.highlightLastMove;\r
6901 \r
6902     if (appData.highlightLastMove) {\r
6903         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);\r
6904     } else {\r
6905         XtSetArg(args[0], XtNleftBitmap, None);\r
6906     }\r
6907     XtSetValues(XtNameToWidget(menuBarWidget,\r
6908                                "menuOptions.Highlight Last Move"), args, 1);\r
6909 }\r
6910 \r
6911 void IcsAlarmProc(w, event, prms, nprms)\r
6912      Widget w;\r
6913      XEvent *event;\r
6914      String *prms;\r
6915      Cardinal *nprms;\r
6916 {\r
6917     Arg args[16];\r
6918 \r
6919     appData.icsAlarm = !appData.icsAlarm;\r
6920 \r
6921     if (appData.icsAlarm) {\r
6922         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);\r
6923     } else {\r
6924         XtSetArg(args[0], XtNleftBitmap, None);\r
6925     }\r
6926     XtSetValues(XtNameToWidget(menuBarWidget,\r
6927                                "menuOptions.ICS Alarm"), args, 1);\r
6928 }\r
6929 \r
6930 void MoveSoundProc(w, event, prms, nprms)\r
6931      Widget w;\r
6932      XEvent *event;\r
6933      String *prms;\r
6934      Cardinal *nprms;\r
6935 {\r
6936     Arg args[16];\r
6937 \r
6938     appData.ringBellAfterMoves = !appData.ringBellAfterMoves;\r
6939 \r
6940     if (appData.ringBellAfterMoves) {\r
6941         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);\r
6942     } else {\r
6943         XtSetArg(args[0], XtNleftBitmap, None);\r
6944     }\r
6945     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),\r
6946                 args, 1);\r
6947 }\r
6948 \r
6949 \r
6950 void OldSaveStyleProc(w, event, prms, nprms)\r
6951      Widget w;\r
6952      XEvent *event;\r
6953      String *prms;\r
6954      Cardinal *nprms;\r
6955 {\r
6956     Arg args[16];\r
6957 \r
6958     appData.oldSaveStyle = !appData.oldSaveStyle;\r
6959 \r
6960     if (appData.oldSaveStyle) {\r
6961         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);\r
6962     } else {\r
6963         XtSetArg(args[0], XtNleftBitmap, None);\r
6964     }\r
6965     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),\r
6966                 args, 1);\r
6967 }\r
6968 \r
6969 void PeriodicUpdatesProc(w, event, prms, nprms)\r
6970      Widget w;\r
6971      XEvent *event;\r
6972      String *prms;\r
6973      Cardinal *nprms;\r
6974 {\r
6975     Arg args[16];\r
6976 \r
6977     PeriodicUpdatesEvent(!appData.periodicUpdates);\r
6978         \r
6979     if (appData.periodicUpdates) {\r
6980         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);\r
6981     } else {\r
6982         XtSetArg(args[0], XtNleftBitmap, None);\r
6983     }\r
6984     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),\r
6985                 args, 1);\r
6986 }\r
6987 \r
6988 void PonderNextMoveProc(w, event, prms, nprms)\r
6989      Widget w;\r
6990      XEvent *event;\r
6991      String *prms;\r
6992      Cardinal *nprms;\r
6993 {\r
6994     Arg args[16];\r
6995 \r
6996     PonderNextMoveEvent(!appData.ponderNextMove);\r
6997 \r
6998     if (appData.ponderNextMove) {\r
6999         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);\r
7000     } else {\r
7001         XtSetArg(args[0], XtNleftBitmap, None);\r
7002     }\r
7003     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),\r
7004                 args, 1);\r
7005 }\r
7006 \r
7007 void PopupExitMessageProc(w, event, prms, nprms)\r
7008      Widget w;\r
7009      XEvent *event;\r
7010      String *prms;\r
7011      Cardinal *nprms;\r
7012 {\r
7013     Arg args[16];\r
7014 \r
7015     appData.popupExitMessage = !appData.popupExitMessage;\r
7016 \r
7017     if (appData.popupExitMessage) {\r
7018         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);\r
7019     } else {\r
7020         XtSetArg(args[0], XtNleftBitmap, None);\r
7021     }\r
7022     XtSetValues(XtNameToWidget(menuBarWidget,\r
7023                                "menuOptions.Popup Exit Message"), args, 1);\r
7024 }\r
7025 \r
7026 void PopupMoveErrorsProc(w, event, prms, nprms)\r
7027      Widget w;\r
7028      XEvent *event;\r
7029      String *prms;\r
7030      Cardinal *nprms;\r
7031 {\r
7032     Arg args[16];\r
7033 \r
7034     appData.popupMoveErrors = !appData.popupMoveErrors;\r
7035 \r
7036     if (appData.popupMoveErrors) {\r
7037         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);\r
7038     } else {\r
7039         XtSetArg(args[0], XtNleftBitmap, None);\r
7040     }\r
7041     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),\r
7042                 args, 1);\r
7043 }\r
7044 \r
7045 void PremoveProc(w, event, prms, nprms)\r
7046      Widget w;\r
7047      XEvent *event;\r
7048      String *prms;\r
7049      Cardinal *nprms;\r
7050 {\r
7051     Arg args[16];\r
7052 \r
7053     appData.premove = !appData.premove;\r
7054 \r
7055     if (appData.premove) {\r
7056         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);\r
7057     } else {\r
7058         XtSetArg(args[0], XtNleftBitmap, None);\r
7059     }\r
7060     XtSetValues(XtNameToWidget(menuBarWidget,\r
7061                                "menuOptions.Premove"), args, 1);\r
7062 }\r
7063 \r
7064 void QuietPlayProc(w, event, prms, nprms)\r
7065      Widget w;\r
7066      XEvent *event;\r
7067      String *prms;\r
7068      Cardinal *nprms;\r
7069 {\r
7070     Arg args[16];\r
7071 \r
7072     appData.quietPlay = !appData.quietPlay;\r
7073 \r
7074     if (appData.quietPlay) {\r
7075         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);\r
7076     } else {\r
7077         XtSetArg(args[0], XtNleftBitmap, None);\r
7078     }\r
7079     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),\r
7080                 args, 1);\r
7081 }\r
7082 \r
7083 void ShowCoordsProc(w, event, prms, nprms)\r
7084      Widget w;\r
7085      XEvent *event;\r
7086      String *prms;\r
7087      Cardinal *nprms;\r
7088 {\r
7089     Arg args[16];\r
7090 \r
7091     appData.showCoords = !appData.showCoords;\r
7092 \r
7093     if (appData.showCoords) {\r
7094         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);\r
7095     } else {\r
7096         XtSetArg(args[0], XtNleftBitmap, None);\r
7097     }\r
7098     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),\r
7099                 args, 1);\r
7100 \r
7101     DrawPosition(True, NULL);\r
7102 }\r
7103 \r
7104 void ShowThinkingProc(w, event, prms, nprms)\r
7105      Widget w;\r
7106      XEvent *event;\r
7107      String *prms;\r
7108      Cardinal *nprms;\r
7109 {\r
7110     Arg args[16];\r
7111 \r
7112     appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
7113     ShowThinkingEvent();\r
7114 #if 0
7115     // [HGM] thinking: currently no suc menu item; replaced by Hide Thinking (From Human)\r
7116     if (appData.showThinking) {\r
7117         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);\r
7118     } else {\r
7119         XtSetArg(args[0], XtNleftBitmap, None);\r
7120     }\r
7121     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Thinking"),\r
7122                 args, 1);
7123 #endif\r
7124 }\r
7125 \r
7126 void HideThinkingProc(w, event, prms, nprms)\r
7127      Widget w;\r
7128      XEvent *event;\r
7129      String *prms;\r
7130      Cardinal *nprms;\r
7131 {\r
7132     Arg args[16];\r
7133 \r
7134     appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
7135     ShowThinkingEvent();\r
7136 \r
7137     if (appData.hideThinkingFromHuman) {\r
7138         XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);\r
7139     } else {\r
7140         XtSetArg(args[0], XtNleftBitmap, None);\r
7141     }\r
7142     XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),\r
7143                 args, 1);\r
7144 }\r
7145 \r
7146 void InfoProc(w, event, prms, nprms)\r
7147      Widget w;\r
7148      XEvent *event;\r
7149      String *prms;\r
7150      Cardinal *nprms;\r
7151 {\r
7152     char buf[MSG_SIZ];\r
7153     sprintf(buf, "xterm -e info --directory %s --directory . -f %s &",\r
7154             INFODIR, INFOFILE);\r
7155     system(buf);\r
7156 }\r
7157 \r
7158 void ManProc(w, event, prms, nprms)\r
7159      Widget w;\r
7160      XEvent *event;\r
7161      String *prms;\r
7162      Cardinal *nprms;\r
7163 {\r
7164     char buf[MSG_SIZ];\r
7165     String name;\r
7166     if (nprms && *nprms > 0)\r
7167       name = prms[0];\r
7168     else\r
7169       name = "xboard";\r
7170     sprintf(buf, "xterm -e man %s &", name);\r
7171     system(buf);\r
7172 }\r
7173 \r
7174 void HintProc(w, event, prms, nprms)\r
7175      Widget w;\r
7176      XEvent *event;\r
7177      String *prms;\r
7178      Cardinal *nprms;\r
7179 {\r
7180     HintEvent();\r
7181 }\r
7182 \r
7183 void BookProc(w, event, prms, nprms)\r
7184      Widget w;\r
7185      XEvent *event;\r
7186      String *prms;\r
7187      Cardinal *nprms;\r
7188 {\r
7189     BookEvent();\r
7190 }\r
7191 \r
7192 void AboutProc(w, event, prms, nprms)\r
7193      Widget w;\r
7194      XEvent *event;\r
7195      String *prms;\r
7196      Cardinal *nprms;\r
7197 {\r
7198     char buf[MSG_SIZ];\r
7199 #if ZIPPY\r
7200     char *zippy = " (with Zippy code)";\r
7201 #else\r
7202     char *zippy = "";\r
7203 #endif\r
7204     sprintf(buf, "%s%s\n\n%s\n%s\n%s\n%s\n\n%s%s\n%s",\r
7205             programVersion, zippy,\r
7206             "Copyright 1991 Digital Equipment Corporation",\r
7207             "Enhancements Copyright 1992-2001 Free Software Foundation",
7208             "Enhancements Copyright 2005 Alessandro Scotti",\r
7209             "Enhancements Copyright 2007-2008 H.G.Muller",\r
7210             PRODUCT, " is free software and carries NO WARRANTY;",\r
7211             "see the file COPYING for more information.");\r
7212     ErrorPopUp("About XBoard", buf, FALSE);\r
7213 }\r
7214 \r
7215 void DebugProc(w, event, prms, nprms)\r
7216      Widget w;\r
7217      XEvent *event;\r
7218      String *prms;\r
7219      Cardinal *nprms;\r
7220 {\r
7221     appData.debugMode = !appData.debugMode;\r
7222 }\r
7223 \r
7224 void AboutGameProc(w, event, prms, nprms)\r
7225      Widget w;\r
7226      XEvent *event;\r
7227      String *prms;\r
7228      Cardinal *nprms;\r
7229 {\r
7230     AboutGameEvent();\r
7231 }\r
7232 \r
7233 void NothingProc(w, event, prms, nprms)\r
7234      Widget w;\r
7235      XEvent *event;\r
7236      String *prms;\r
7237      Cardinal *nprms;\r
7238 {\r
7239     return;\r
7240 }\r
7241 \r
7242 void Iconify(w, event, prms, nprms)\r
7243      Widget w;\r
7244      XEvent *event;\r
7245      String *prms;\r
7246      Cardinal *nprms;\r
7247 {\r
7248     Arg args[16];\r
7249     \r
7250     fromX = fromY = -1;\r
7251     XtSetArg(args[0], XtNiconic, True);\r
7252     XtSetValues(shellWidget, args, 1);\r
7253 }\r
7254 \r
7255 void DisplayMessage(message, extMessage)\r
7256      char *message, *extMessage;\r
7257 {\r
7258     char buf[MSG_SIZ];\r
7259     Arg arg;\r
7260     \r
7261     if (extMessage) {\r
7262         if (*message) {\r
7263             sprintf(buf, "%s  %s", message, extMessage);\r
7264             message = buf;\r
7265         } else {\r
7266             message = extMessage;\r
7267         }\r
7268     }\r
7269     XtSetArg(arg, XtNlabel, message);\r
7270     XtSetValues(messageWidget, &arg, 1);\r
7271 }\r
7272 \r
7273 void DisplayTitle(text)\r
7274      char *text;\r
7275 {\r
7276     Arg args[16];\r
7277     int i;\r
7278     char title[MSG_SIZ];\r
7279     char icon[MSG_SIZ];\r
7280 \r
7281     if (text == NULL) text = "";\r
7282 \r
7283     if (appData.titleInWindow) {\r
7284         i = 0;\r
7285         XtSetArg(args[i], XtNlabel, text);   i++;\r
7286         XtSetValues(titleWidget, args, i);\r
7287     }\r
7288 \r
7289     if (*text != NULLCHAR) {\r
7290         strcpy(icon, text);\r
7291         strcpy(title, text);\r
7292     } else if (appData.icsActive) {\r
7293         sprintf(icon, "%s", appData.icsHost);\r
7294         sprintf(title, "%s: %s", programName, appData.icsHost);\r
7295     } else if (appData.cmailGameName[0] != NULLCHAR) {\r
7296         sprintf(icon, "%s", "CMail");\r
7297         sprintf(title, "%s: %s", programName, "CMail");\r
7298 #ifdef GOTHIC
7299     // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7300     } else if (gameInfo.variant == VariantGothic) {\r
7301         strcpy(icon, programName);\r
7302         strcpy(title, GOTHIC);\r
7303 #endif
7304 #ifdef FALCON
7305     } else if (gameInfo.variant == VariantFalcon) {\r
7306         strcpy(icon, programName);\r
7307         strcpy(title, FALCON);\r
7308 #endif
7309     } else if (appData.noChessProgram) {\r
7310         strcpy(icon, programName);\r
7311         strcpy(title, programName);\r
7312     } else {\r
7313         strcpy(icon, first.tidy);\r
7314         sprintf(title, "%s: %s", programName, first.tidy);\r
7315     }\r
7316     i = 0;\r
7317     XtSetArg(args[i], XtNiconName, (XtArgVal) icon);    i++;\r
7318     XtSetArg(args[i], XtNtitle, (XtArgVal) title);      i++;\r
7319     XtSetValues(shellWidget, args, i);\r
7320 }\r
7321 \r
7322 \r
7323 void DisplayError(message, error)\r
7324      String message;\r
7325      int error;\r
7326 {\r
7327     char buf[MSG_SIZ];\r
7328 \r
7329     if (error == 0) {\r
7330         if (appData.debugMode || appData.matchMode) {\r
7331             fprintf(stderr, "%s: %s\n", programName, message);\r
7332         }\r
7333     } else {\r
7334         if (appData.debugMode || appData.matchMode) {\r
7335             fprintf(stderr, "%s: %s: %s\n",\r
7336                     programName, message, strerror(error));\r
7337         }\r
7338         sprintf(buf, "%s: %s", message, strerror(error));\r
7339         message = buf;\r
7340     }   \r
7341     ErrorPopUp("Error", message, FALSE);\r
7342 }\r
7343 \r
7344 \r
7345 void DisplayMoveError(message)\r
7346      String message;\r
7347 {\r
7348     fromX = fromY = -1;\r
7349     ClearHighlights();\r
7350     DrawPosition(FALSE, NULL);\r
7351     if (appData.debugMode || appData.matchMode) {\r
7352         fprintf(stderr, "%s: %s\n", programName, message);\r
7353     }\r
7354     if (appData.popupMoveErrors) {\r
7355         ErrorPopUp("Error", message, FALSE);\r
7356     } else {\r
7357         DisplayMessage(message, "");\r
7358     }\r
7359 }\r
7360 \r
7361 \r
7362 void DisplayFatalError(message, error, status)\r
7363      String message;\r
7364      int error, status;\r
7365 {\r
7366     char buf[MSG_SIZ];\r
7367 \r
7368     errorExitStatus = status;\r
7369     if (error == 0) {\r
7370         fprintf(stderr, "%s: %s\n", programName, message);\r
7371     } else {\r
7372         fprintf(stderr, "%s: %s: %s\n",\r
7373                 programName, message, strerror(error));\r
7374         sprintf(buf, "%s: %s", message, strerror(error));\r
7375         message = buf;\r
7376     }\r
7377     if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {\r
7378       ErrorPopUp(status ? "Fatal Error" : "Exiting", message, TRUE);\r
7379     } else {\r
7380       ExitEvent(status);\r
7381     }\r
7382 }\r
7383 \r
7384 void DisplayInformation(message)\r
7385      String message;\r
7386 {\r
7387     ErrorPopDown();\r
7388     ErrorPopUp("Information", message, TRUE);\r
7389 }\r
7390 \r
7391 void DisplayNote(message)\r
7392      String message;\r
7393 {\r
7394     ErrorPopDown();\r
7395     ErrorPopUp("Note", message, FALSE);\r
7396 }\r
7397 \r
7398 static int\r
7399 NullXErrorCheck(dpy, error_event)\r
7400      Display *dpy;\r
7401      XErrorEvent *error_event;\r
7402 {\r
7403     return 0;\r
7404 }\r
7405 \r
7406 void DisplayIcsInteractionTitle(message)\r
7407      String message;\r
7408 {\r
7409   if (oldICSInteractionTitle == NULL) {\r
7410     /* Magic to find the old window title, adapted from vim */\r
7411     char *wina = getenv("WINDOWID");\r
7412     if (wina != NULL) {\r
7413       Window win = (Window) atoi(wina);\r
7414       Window root, parent, *children;\r
7415       unsigned int nchildren;\r
7416       int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);\r
7417       for (;;) {\r
7418         if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;\r
7419         if (!XQueryTree(xDisplay, win, &root, &parent,\r
7420                         &children, &nchildren)) break;\r
7421         if (children) XFree((void *)children);\r
7422         if (parent == root || parent == 0) break;\r
7423         win = parent;\r
7424       }\r
7425       XSetErrorHandler(oldHandler);\r
7426     }\r
7427     if (oldICSInteractionTitle == NULL) {\r
7428       oldICSInteractionTitle = "xterm"; \r
7429     }\r
7430   }  \r
7431   printf("\033]0;%s\007", message);\r
7432   fflush(stdout);\r
7433 }\r
7434 \r
7435 char pendingReplyPrefix[MSG_SIZ];\r
7436 ProcRef pendingReplyPR;\r
7437 \r
7438 void AskQuestionProc(w, event, prms, nprms)\r
7439      Widget w;\r
7440      XEvent *event;\r
7441      String *prms;\r
7442      Cardinal *nprms;\r
7443 {\r
7444     if (*nprms != 4) {\r
7445         fprintf(stderr, "AskQuestionProc needed 4 parameters, got %d\n",\r
7446                 *nprms);\r
7447         return;\r
7448     }\r
7449     AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);\r
7450 }\r
7451 \r
7452 void AskQuestionPopDown()\r
7453 {\r
7454     if (!askQuestionUp) return;\r
7455     XtPopdown(askQuestionShell);\r
7456     XtDestroyWidget(askQuestionShell);\r
7457     askQuestionUp = False;\r
7458 }\r
7459 \r
7460 void AskQuestionReplyAction(w, event, prms, nprms)\r
7461      Widget w;\r
7462      XEvent *event;\r
7463      String *prms;\r
7464      Cardinal *nprms;\r
7465 {\r
7466     char buf[MSG_SIZ];\r
7467     int err;\r
7468     String reply;\r
7469 \r
7470     reply = XawDialogGetValueString(w = XtParent(w));\r
7471     strcpy(buf, pendingReplyPrefix);\r
7472     if (*buf) strcat(buf, " ");\r
7473     strcat(buf, reply);\r
7474     strcat(buf, "\n");\r
7475     OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);\r
7476     AskQuestionPopDown();\r
7477 \r
7478     if (err) DisplayFatalError("Error writing to chess program", err, 0);\r
7479 }\r
7480 \r
7481 void AskQuestionCallback(w, client_data, call_data)\r
7482      Widget w;\r
7483      XtPointer client_data, call_data;\r
7484 {\r
7485     String name;\r
7486     Arg args[16];\r
7487 \r
7488     XtSetArg(args[0], XtNlabel, &name);\r
7489     XtGetValues(w, args, 1);\r
7490     \r
7491     if (strcmp(name, "cancel") == 0) {\r
7492         AskQuestionPopDown();\r
7493     } else {\r
7494         AskQuestionReplyAction(w, NULL, NULL, NULL);\r
7495     }\r
7496 }\r
7497 \r
7498 void AskQuestion(title, question, replyPrefix, pr)\r
7499      char *title, *question, *replyPrefix;\r
7500      ProcRef pr;\r
7501 {\r
7502     Arg args[16];\r
7503     Widget popup, layout, dialog, edit;\r
7504     Window root, child;\r
7505     int x, y, i;\r
7506     int win_x, win_y;\r
7507     unsigned int mask;\r
7508     \r
7509     strcpy(pendingReplyPrefix, replyPrefix);\r
7510     pendingReplyPR = pr;\r
7511     \r
7512     i = 0;\r
7513     XtSetArg(args[i], XtNresizable, True); i++;\r
7514     XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;\r
7515     askQuestionShell = popup =\r
7516       XtCreatePopupShell(title, transientShellWidgetClass,\r
7517                          shellWidget, args, i);\r
7518     \r
7519     layout =\r
7520       XtCreateManagedWidget(layoutName, formWidgetClass, popup,\r
7521                             layoutArgs, XtNumber(layoutArgs));\r
7522   \r
7523     i = 0;\r
7524     XtSetArg(args[i], XtNlabel, question); i++;\r
7525     XtSetArg(args[i], XtNvalue, ""); i++;\r
7526     XtSetArg(args[i], XtNborderWidth, 0); i++;\r
7527     dialog = XtCreateManagedWidget("question", dialogWidgetClass,\r
7528                                    layout, args, i);\r
7529     \r
7530     XawDialogAddButton(dialog, "enter", AskQuestionCallback,\r
7531                        (XtPointer) dialog);\r
7532     XawDialogAddButton(dialog, "cancel", AskQuestionCallback,\r
7533                        (XtPointer) dialog);\r
7534 \r
7535     XtRealizeWidget(popup);\r
7536     CatchDeleteWindow(popup, "AskQuestionPopDown");\r
7537     \r
7538     XQueryPointer(xDisplay, xBoardWindow, &root, &child,\r
7539                   &x, &y, &win_x, &win_y, &mask);\r
7540     \r
7541     XtSetArg(args[0], XtNx, x - 10);\r
7542     XtSetArg(args[1], XtNy, y - 30);\r
7543     XtSetValues(popup, args, 2);\r
7544     \r
7545     XtPopup(popup, XtGrabExclusive);\r
7546     askQuestionUp = True;\r
7547     \r
7548     edit = XtNameToWidget(dialog, "*value");\r
7549     XtSetKeyboardFocus(popup, edit);\r
7550 }\r
7551 \r
7552 \r
7553 void\r
7554 PlaySound(name)\r
7555      char *name;\r
7556 {\r
7557   if (*name == NULLCHAR) {\r
7558     return;\r
7559   } else if (strcmp(name, "$") == 0) {\r
7560     putc(BELLCHAR, stderr);\r
7561   } else {\r
7562     char buf[2048];\r
7563     sprintf(buf, "%s '%s' &", appData.soundProgram, name);\r
7564     system(buf);\r
7565   }\r
7566 }\r
7567 \r
7568 void\r
7569 RingBell()\r
7570 {\r
7571   PlaySound(appData.soundMove);\r
7572 }\r
7573 \r
7574 void\r
7575 PlayIcsWinSound()\r
7576 {\r
7577   PlaySound(appData.soundIcsWin);\r
7578 }\r
7579 \r
7580 void\r
7581 PlayIcsLossSound()\r
7582 {\r
7583   PlaySound(appData.soundIcsLoss);\r
7584 }\r
7585 \r
7586 void\r
7587 PlayIcsDrawSound()\r
7588 {\r
7589   PlaySound(appData.soundIcsDraw);\r
7590 }\r
7591 \r
7592 void\r
7593 PlayIcsUnfinishedSound()\r
7594 {\r
7595   PlaySound(appData.soundIcsUnfinished);\r
7596 }\r
7597 \r
7598 void\r
7599 PlayAlarmSound()\r
7600 {\r
7601   PlaySound(appData.soundIcsAlarm);\r
7602 }\r
7603 \r
7604 void\r
7605 EchoOn()\r
7606 {\r
7607     system("stty echo");\r
7608 }\r
7609 \r
7610 void\r
7611 EchoOff()\r
7612 {\r
7613     system("stty -echo");\r
7614 }\r
7615 \r
7616 void\r
7617 Colorize(cc, continuation)\r
7618      ColorClass cc;\r
7619      int continuation;\r
7620 {\r
7621     char buf[MSG_SIZ];\r
7622     int count, outCount, error;\r
7623 \r
7624     if (textColors[(int)cc].bg > 0) {\r
7625         if (textColors[(int)cc].fg > 0) {\r
7626             sprintf(buf, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,\r
7627                     textColors[(int)cc].fg, textColors[(int)cc].bg);\r
7628         } else {\r
7629             sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,\r
7630                     textColors[(int)cc].bg);\r
7631         }\r
7632     } else {\r
7633         if (textColors[(int)cc].fg > 0) {\r
7634             sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,\r
7635                     textColors[(int)cc].fg);\r
7636         } else {\r
7637             sprintf(buf, "\033[0;%dm", textColors[(int)cc].attr);\r
7638         }\r
7639     }\r
7640     count = strlen(buf);\r
7641     outCount = OutputToProcess(NoProc, buf, count, &error);\r
7642     if (outCount < count) {\r
7643         DisplayFatalError("Error writing to display", error, 1);\r
7644     }\r
7645 \r
7646     if (continuation) return;\r
7647     switch (cc) {\r
7648     case ColorShout:\r
7649       PlaySound(appData.soundShout);\r
7650       break;\r
7651     case ColorSShout:\r
7652       PlaySound(appData.soundSShout);\r
7653       break;\r
7654     case ColorChannel1:\r
7655       PlaySound(appData.soundChannel1);\r
7656       break;\r
7657     case ColorChannel:\r
7658       PlaySound(appData.soundChannel);\r
7659       break;\r
7660     case ColorKibitz:\r
7661       PlaySound(appData.soundKibitz);\r
7662       break;\r
7663     case ColorTell:\r
7664       PlaySound(appData.soundTell);\r
7665       break;\r
7666     case ColorChallenge:\r
7667       PlaySound(appData.soundChallenge);\r
7668       break;\r
7669     case ColorRequest:\r
7670       PlaySound(appData.soundRequest);\r
7671       break;\r
7672     case ColorSeek:\r
7673       PlaySound(appData.soundSeek);\r
7674       break;\r
7675     case ColorNormal:\r
7676     case ColorNone:\r
7677     default:\r
7678       break;\r
7679     }\r
7680 }\r
7681 \r
7682 char *UserName()\r
7683 {\r
7684     return getpwuid(getuid())->pw_name;\r
7685 }\r
7686 \r
7687 static char *ExpandPathName(path)\r
7688      char *path;\r
7689 {\r
7690     static char static_buf[2000];\r
7691     char *d, *s, buf[2000];\r
7692     struct passwd *pwd;\r
7693   \r
7694     s = path;\r
7695     d = static_buf;\r
7696 \r
7697     while (*s && isspace(*s))\r
7698       ++s;\r
7699 \r
7700     if (!*s) {\r
7701         *d = 0;\r
7702         return static_buf;\r
7703     }\r
7704 \r
7705     if (*s == '~') {\r
7706         if (*(s+1) == '/') {\r
7707             strcpy(d, getpwuid(getuid())->pw_dir);\r
7708             strcat(d, s+1);\r
7709         }\r
7710         else {\r
7711             strcpy(buf, s+1);\r
7712             *strchr(buf, '/') = 0;\r
7713             pwd = getpwnam(buf);\r
7714             if (!pwd)\r
7715               {\r
7716                   fprintf(stderr, "ERROR: Unknown user %s (in path %s)\n",\r
7717                           buf, path);\r
7718                   return NULL;\r
7719               }\r
7720             strcpy(d, pwd->pw_dir);\r
7721             strcat(d, strchr(s+1, '/'));\r
7722         }\r
7723     }\r
7724     else\r
7725       strcpy(d, s);\r
7726 \r
7727     return static_buf;\r
7728 }  \r
7729 \r
7730 char *HostName()\r
7731 {\r
7732     static char host_name[MSG_SIZ];\r
7733     \r
7734 #if HAVE_GETHOSTNAME\r
7735     gethostname(host_name, MSG_SIZ);\r
7736     return host_name;\r
7737 #else  /* not HAVE_GETHOSTNAME */\r
7738 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H\r
7739     sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);\r
7740     return host_name;\r
7741 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */\r
7742     return "localhost";\r
7743 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */\r
7744 #endif /* not HAVE_GETHOSTNAME */\r
7745 }\r
7746 \r
7747 XtIntervalId delayedEventTimerXID = 0;\r
7748 DelayedEventCallback delayedEventCallback = 0;\r
7749 \r
7750 void\r
7751 FireDelayedEvent()\r
7752 {\r
7753     delayedEventTimerXID = 0;\r
7754     delayedEventCallback();\r
7755 }\r
7756 \r
7757 void\r
7758 ScheduleDelayedEvent(cb, millisec)\r
7759      DelayedEventCallback cb; long millisec;\r
7760 {\r
7761     delayedEventCallback = cb;\r
7762     delayedEventTimerXID =\r
7763       XtAppAddTimeOut(appContext, millisec,\r
7764                       (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);\r
7765 }\r
7766 \r
7767 DelayedEventCallback\r
7768 GetDelayedEvent()\r
7769 {\r
7770   if (delayedEventTimerXID) {\r
7771     return delayedEventCallback;\r
7772   } else {\r
7773     return NULL;\r
7774   }\r
7775 }\r
7776 \r
7777 void\r
7778 CancelDelayedEvent()\r
7779 {\r
7780   if (delayedEventTimerXID) {\r
7781     XtRemoveTimeOut(delayedEventTimerXID);\r
7782     delayedEventTimerXID = 0;\r
7783   }\r
7784 }\r
7785 \r
7786 XtIntervalId loadGameTimerXID = 0;\r
7787 \r
7788 int LoadGameTimerRunning()\r
7789 {\r
7790     return loadGameTimerXID != 0;\r
7791 }\r
7792 \r
7793 int StopLoadGameTimer()\r
7794 {\r
7795     if (loadGameTimerXID != 0) {\r
7796         XtRemoveTimeOut(loadGameTimerXID);\r
7797         loadGameTimerXID = 0;\r
7798         return TRUE;\r
7799     } else {\r
7800         return FALSE;\r
7801     }\r
7802 }\r
7803 \r
7804 void\r
7805 LoadGameTimerCallback(arg, id)\r
7806      XtPointer arg;\r
7807      XtIntervalId *id;\r
7808 {\r
7809     loadGameTimerXID = 0;\r
7810     AutoPlayGameLoop();\r
7811 }\r
7812 \r
7813 void\r
7814 StartLoadGameTimer(millisec)\r
7815      long millisec;\r
7816 {\r
7817     loadGameTimerXID =\r
7818       XtAppAddTimeOut(appContext, millisec,\r
7819                       (XtTimerCallbackProc) LoadGameTimerCallback,\r
7820                       (XtPointer) 0);\r
7821 }\r
7822 \r
7823 XtIntervalId analysisClockXID = 0;\r
7824 \r
7825 void\r
7826 AnalysisClockCallback(arg, id)\r
7827      XtPointer arg;\r
7828      XtIntervalId *id;\r
7829 {\r
7830     if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {\r
7831         AnalysisPeriodicEvent(0);\r
7832         StartAnalysisClock();\r
7833     }\r
7834 }\r
7835 \r
7836 void\r
7837 StartAnalysisClock()\r
7838 {\r
7839     analysisClockXID =\r
7840       XtAppAddTimeOut(appContext, 2000,\r
7841                       (XtTimerCallbackProc) AnalysisClockCallback,\r
7842                       (XtPointer) 0);\r
7843 }\r
7844 \r
7845 XtIntervalId clockTimerXID = 0;\r
7846 \r
7847 int ClockTimerRunning()\r
7848 {\r
7849     return clockTimerXID != 0;\r
7850 }\r
7851 \r
7852 int StopClockTimer()\r
7853 {\r
7854     if (clockTimerXID != 0) {\r
7855         XtRemoveTimeOut(clockTimerXID);\r
7856         clockTimerXID = 0;\r
7857         return TRUE;\r
7858     } else {\r
7859         return FALSE;\r
7860     }\r
7861 }\r
7862 \r
7863 void\r
7864 ClockTimerCallback(arg, id)\r
7865      XtPointer arg;\r
7866      XtIntervalId *id;\r
7867 {\r
7868     clockTimerXID = 0;\r
7869     DecrementClocks();\r
7870 }\r
7871 \r
7872 void\r
7873 StartClockTimer(millisec)\r
7874      long millisec;\r
7875 {\r
7876     clockTimerXID =\r
7877       XtAppAddTimeOut(appContext, millisec,\r
7878                       (XtTimerCallbackProc) ClockTimerCallback,\r
7879                       (XtPointer) 0);\r
7880 }\r
7881 \r
7882 void\r
7883 DisplayTimerLabel(w, color, timer, highlight)\r
7884      Widget w;\r
7885      char *color;\r
7886      long timer;\r
7887      int highlight;\r
7888 {\r
7889     char buf[MSG_SIZ];\r
7890     Arg args[16];\r
7891     \r
7892     if (appData.clockMode) {\r
7893         sprintf(buf, "%s: %s", color, TimeString(timer));\r
7894         XtSetArg(args[0], XtNlabel, buf);\r
7895     } else {\r
7896         sprintf(buf, "%s  ", color);\r
7897         XtSetArg(args[0], XtNlabel, buf);\r
7898     }\r
7899     \r
7900     if (highlight) {\r
7901         XtSetArg(args[1], XtNbackground, timerForegroundPixel);\r
7902         XtSetArg(args[2], XtNforeground, timerBackgroundPixel);\r
7903     } else {\r
7904         XtSetArg(args[1], XtNbackground, timerBackgroundPixel);\r
7905         XtSetArg(args[2], XtNforeground, timerForegroundPixel);\r
7906     }\r
7907     \r
7908     XtSetValues(w, args, 3);\r
7909 }\r
7910 \r
7911 void\r
7912 DisplayWhiteClock(timeRemaining, highlight)\r
7913      long timeRemaining;\r
7914      int highlight;\r
7915 {\r
7916     Arg args[16];\r
7917     DisplayTimerLabel(whiteTimerWidget, "White", timeRemaining, highlight);\r
7918     if (highlight && iconPixmap == bIconPixmap) {\r
7919         iconPixmap = wIconPixmap;\r
7920         XtSetArg(args[0], XtNiconPixmap, iconPixmap);\r
7921         XtSetValues(shellWidget, args, 1);\r
7922     }\r
7923 }\r
7924 \r
7925 void\r
7926 DisplayBlackClock(timeRemaining, highlight)\r
7927      long timeRemaining;\r
7928      int highlight;\r
7929 {\r
7930     Arg args[16];\r
7931     DisplayTimerLabel(blackTimerWidget, "Black", timeRemaining, highlight);\r
7932     if (highlight && iconPixmap == wIconPixmap) {\r
7933         iconPixmap = bIconPixmap;\r
7934         XtSetArg(args[0], XtNiconPixmap, iconPixmap);\r
7935         XtSetValues(shellWidget, args, 1);\r
7936     }\r
7937 }\r
7938 \r
7939 #define CPNone 0\r
7940 #define CPReal 1\r
7941 #define CPComm 2\r
7942 #define CPSock 3\r
7943 #define CPLoop 4\r
7944 typedef int CPKind;\r
7945 \r
7946 typedef struct {\r
7947     CPKind kind;\r
7948     int pid;\r
7949     int fdTo, fdFrom;  \r
7950 } ChildProc;\r
7951 \r
7952 \r
7953 int StartChildProcess(cmdLine, dir, pr)\r
7954      char *cmdLine; \r
7955      char *dir;\r
7956      ProcRef *pr;\r
7957 {\r
7958     char *argv[64], *p;\r
7959     int i, pid;\r
7960     int to_prog[2], from_prog[2];\r
7961     ChildProc *cp;\r
7962     char buf[MSG_SIZ];\r
7963     \r
7964     if (appData.debugMode) {\r
7965         fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);\r
7966     }\r
7967 \r
7968     /* We do NOT feed the cmdLine to the shell; we just\r
7969        parse it into blank-separated arguments in the\r
7970        most simple-minded way possible.\r
7971        */\r
7972     i = 0;\r
7973     strcpy(buf, cmdLine);\r
7974     p = buf;\r
7975     for (;;) {\r
7976         argv[i++] = p;\r
7977         p = strchr(p, ' ');\r
7978         if (p == NULL) break;\r
7979         *p++ = NULLCHAR;\r
7980     }\r
7981     argv[i] = NULL;\r
7982 \r
7983     SetUpChildIO(to_prog, from_prog);\r
7984 \r
7985     if ((pid = fork()) == 0) {\r
7986         /* Child process */
7987         // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1\r
7988         close(to_prog[1]);     // first close the unused pipe ends\r
7989         close(from_prog[0]);\r
7990         dup2(to_prog[0], 0);   // to_prog was created first, nd is the only one to use 0 or 1\r
7991         dup2(from_prog[1], 1);\r
7992         if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original\r
7993         close(from_prog[1]);                   // and closing again loses one of the pipes!\r
7994         if(fileno(stderr) >= 2) // better safe than sorry...
7995                 dup2(1, fileno(stderr)); /* force stderr to the pipe */\r
7996 \r
7997         if (dir[0] != NULLCHAR && chdir(dir) != 0) {\r
7998             perror(dir);\r
7999             exit(1);\r
8000         }\r
8001 \r
8002         execvp(argv[0], argv);\r
8003         \r
8004         /* If we get here, exec failed */\r
8005         perror(argv[0]);\r
8006         exit(1);\r
8007     }\r
8008     \r
8009     /* Parent process */\r
8010     close(to_prog[0]);\r
8011     close(from_prog[1]);\r
8012     \r
8013     cp = (ChildProc *) calloc(1, sizeof(ChildProc));\r
8014     cp->kind = CPReal;\r
8015     cp->pid = pid;\r
8016     cp->fdFrom = from_prog[0];\r
8017     cp->fdTo = to_prog[1];\r
8018     *pr = (ProcRef) cp;\r
8019     return 0;\r
8020 }\r
8021 \r
8022 void\r
8023 DestroyChildProcess(pr, signal)\r
8024      ProcRef pr;\r
8025      int signal;\r
8026 {\r
8027     ChildProc *cp = (ChildProc *) pr;\r
8028 \r
8029     if (cp->kind != CPReal) return;\r
8030     cp->kind = CPNone;\r
8031     if (signal) {\r
8032       kill(cp->pid, SIGTERM);\r
8033     }\r
8034     /* Process is exiting either because of the kill or because of\r
8035        a quit command sent by the backend; either way, wait for it to die.\r
8036     */\r
8037     wait((int *) 0);\r
8038     close(cp->fdFrom);\r
8039     close(cp->fdTo);\r
8040 }\r
8041 \r
8042 void\r
8043 InterruptChildProcess(pr)\r
8044      ProcRef pr;\r
8045 {\r
8046     ChildProc *cp = (ChildProc *) pr;\r
8047 \r
8048     if (cp->kind != CPReal) return;\r
8049     (void) kill(cp->pid, SIGINT); /* stop it thinking */\r
8050 }\r
8051 \r
8052 int OpenTelnet(host, port, pr)\r
8053      char *host;\r
8054      char *port;\r
8055      ProcRef *pr;\r
8056 {\r
8057     char cmdLine[MSG_SIZ];\r
8058 \r
8059     if (port[0] == NULLCHAR) {\r
8060         sprintf(cmdLine, "%s %s", appData.telnetProgram, host);\r
8061     } else {\r
8062         sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);\r
8063     }\r
8064     return StartChildProcess(cmdLine, "", pr);\r
8065 }\r
8066 \r
8067 int OpenTCP(host, port, pr)\r
8068      char *host;\r
8069      char *port;\r
8070      ProcRef *pr;\r
8071 {\r
8072 #if OMIT_SOCKETS\r
8073     DisplayFatalError("Socket support is not configured in", 0, 2);\r
8074 #else  /* !OMIT_SOCKETS */\r
8075     int s;\r
8076     struct sockaddr_in sa;\r
8077     struct hostent     *hp;\r
8078     unsigned short uport;\r
8079     ChildProc *cp;\r
8080 \r
8081     if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {\r
8082         return errno;\r
8083     }\r
8084 \r
8085     memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));\r
8086     sa.sin_family = AF_INET;\r
8087     sa.sin_addr.s_addr = INADDR_ANY;\r
8088     uport = (unsigned short) 0;\r
8089     sa.sin_port = htons(uport);\r
8090     if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {\r
8091         return errno;\r
8092     }\r
8093 \r
8094     memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));\r
8095     if (!(hp = gethostbyname(host))) {\r
8096         int b0, b1, b2, b3;\r
8097         if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {\r
8098             hp = (struct hostent *) calloc(1, sizeof(struct hostent));\r
8099             hp->h_addrtype = AF_INET;\r
8100             hp->h_length = 4;\r
8101             hp->h_addr_list = (char **) calloc(2, sizeof(char *));\r
8102             hp->h_addr_list[0] = (char *) malloc(4);\r
8103             hp->h_addr_list[0][0] = b0;\r
8104             hp->h_addr_list[0][1] = b1;\r
8105             hp->h_addr_list[0][2] = b2;\r
8106             hp->h_addr_list[0][3] = b3;\r
8107         } else {\r
8108             return ENOENT;\r
8109         }\r
8110     }\r
8111     sa.sin_family = hp->h_addrtype;\r
8112     uport = (unsigned short) atoi(port);\r
8113     sa.sin_port = htons(uport);\r
8114     memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);\r
8115 \r
8116     if (connect(s, (struct sockaddr *) &sa, \r
8117                 sizeof(struct sockaddr_in)) < 0) {\r
8118         return errno;\r
8119     }\r
8120 \r
8121     cp = (ChildProc *) calloc(1, sizeof(ChildProc));\r
8122     cp->kind = CPSock;\r
8123     cp->pid = 0;\r
8124     cp->fdFrom = s;\r
8125     cp->fdTo = s;\r
8126     *pr = (ProcRef) cp;\r
8127 \r
8128 #endif /* !OMIT_SOCKETS */\r
8129 \r
8130     return 0;\r
8131 }\r
8132 \r
8133 int OpenCommPort(name, pr)\r
8134      char *name;\r
8135      ProcRef *pr;\r
8136 {\r
8137     int fd;\r
8138     ChildProc *cp;\r
8139 \r
8140     fd = open(name, 2, 0);\r
8141     if (fd < 0) return errno;\r
8142 \r
8143     cp = (ChildProc *) calloc(1, sizeof(ChildProc));\r
8144     cp->kind = CPComm;\r
8145     cp->pid = 0;\r
8146     cp->fdFrom = fd;\r
8147     cp->fdTo = fd;\r
8148     *pr = (ProcRef) cp;\r
8149 \r
8150     return 0;\r
8151 }\r
8152 \r
8153 int OpenLoopback(pr)\r
8154      ProcRef *pr;\r
8155 {\r
8156     ChildProc *cp;\r
8157     int to[2], from[2];\r
8158 \r
8159     SetUpChildIO(to, from);\r
8160 \r
8161     cp = (ChildProc *) calloc(1, sizeof(ChildProc));\r
8162     cp->kind = CPLoop;\r
8163     cp->pid = 0;\r
8164     cp->fdFrom = to[0];         /* note not from[0]; we are doing a loopback */\r
8165     cp->fdTo = to[1];\r
8166     *pr = (ProcRef) cp;\r
8167 \r
8168     return 0;\r
8169 }\r
8170 \r
8171 int OpenRcmd(host, user, cmd, pr)\r
8172      char *host, *user, *cmd;\r
8173      ProcRef *pr;\r
8174 {\r
8175     DisplayFatalError("internal rcmd not implemented for Unix", 0, 1);\r
8176     return -1;\r
8177 }    \r
8178 \r
8179 #define INPUT_SOURCE_BUF_SIZE 8192\r
8180 \r
8181 typedef struct {\r
8182     CPKind kind;\r
8183     int fd;\r
8184     int lineByLine;\r
8185     char *unused;\r
8186     InputCallback func;\r
8187     XtInputId xid;\r
8188     char buf[INPUT_SOURCE_BUF_SIZE];\r
8189     VOIDSTAR closure;\r
8190 } InputSource;\r
8191 \r
8192 void\r
8193 DoInputCallback(closure, source, xid) \r
8194      caddr_t closure;\r
8195      int *source;\r
8196      XtInputId *xid;\r
8197 {\r
8198     InputSource *is = (InputSource *) closure;\r
8199     int count;\r
8200     int error;\r
8201     char *p, *q;\r
8202 \r
8203     if (is->lineByLine) {\r
8204         count = read(is->fd, is->unused,\r
8205                      INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));\r
8206         if (count <= 0) {\r
8207             (is->func)(is, is->closure, is->buf, count, count ? errno : 0);\r
8208             return;\r
8209         }\r
8210         is->unused += count;\r
8211         p = is->buf;\r
8212         while (p < is->unused) {\r
8213             q = memchr(p, '\n', is->unused - p);\r
8214             if (q == NULL) break;\r
8215             q++;\r
8216             (is->func)(is, is->closure, p, q - p, 0);\r
8217             p = q;\r
8218         }\r
8219         q = is->buf;\r
8220         while (p < is->unused) {\r
8221             *q++ = *p++;\r
8222         }\r
8223         is->unused = q;\r
8224     } else {\r
8225         count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);\r
8226         if (count == -1)\r
8227           error = errno;\r
8228         else\r
8229           error = 0;\r
8230         (is->func)(is, is->closure, is->buf, count, error);\r
8231     }   \r
8232 }\r
8233 \r
8234 InputSourceRef AddInputSource(pr, lineByLine, func, closure)\r
8235      ProcRef pr;\r
8236      int lineByLine;\r
8237      InputCallback func;\r
8238      VOIDSTAR closure;\r
8239 {\r
8240     InputSource *is;\r
8241     ChildProc *cp = (ChildProc *) pr;\r
8242 \r
8243     is = (InputSource *) calloc(1, sizeof(InputSource));\r
8244     is->lineByLine = lineByLine;\r
8245     is->func = func;\r
8246     if (pr == NoProc) {\r
8247         is->kind = CPReal;\r
8248         is->fd = fileno(stdin);\r
8249     } else {\r
8250         is->kind = cp->kind;\r
8251         is->fd = cp->fdFrom;\r
8252     }\r
8253     if (lineByLine) {\r
8254         is->unused = is->buf;\r
8255     }\r
8256     \r
8257     is->xid = XtAppAddInput(appContext, is->fd,\r
8258                             (XtPointer) (XtInputReadMask),\r
8259                             (XtInputCallbackProc) DoInputCallback,\r
8260                             (XtPointer) is);\r
8261     is->closure = closure;\r
8262     return (InputSourceRef) is;\r
8263 }\r
8264 \r
8265 void\r
8266 RemoveInputSource(isr)\r
8267      InputSourceRef isr;\r
8268 {\r
8269     InputSource *is = (InputSource *) isr;\r
8270 \r
8271     if (is->xid == 0) return;\r
8272     XtRemoveInput(is->xid);\r
8273     is->xid = 0;\r
8274 }\r
8275 \r
8276 int OutputToProcess(pr, message, count, outError)\r
8277      ProcRef pr;\r
8278      char *message;\r
8279      int count;\r
8280      int *outError;\r
8281 {\r
8282     ChildProc *cp = (ChildProc *) pr;\r
8283     int outCount;\r
8284 \r
8285     if (pr == NoProc)\r
8286       outCount = fwrite(message, 1, count, stdout);\r
8287     else\r
8288       outCount = write(cp->fdTo, message, count);\r
8289 \r
8290     if (outCount == -1)\r
8291       *outError = errno;\r
8292     else\r
8293       *outError = 0;\r
8294 \r
8295     return outCount;\r
8296 }\r
8297 \r
8298 /* Output message to process, with "ms" milliseconds of delay\r
8299    between each character. This is needed when sending the logon\r
8300    script to ICC, which for some reason doesn't like the\r
8301    instantaneous send. */\r
8302 int OutputToProcessDelayed(pr, message, count, outError, msdelay)\r
8303      ProcRef pr;\r
8304      char *message;\r
8305      int count;\r
8306      int *outError;\r
8307      long msdelay;\r
8308 {\r
8309     ChildProc *cp = (ChildProc *) pr;\r
8310     int outCount = 0;\r
8311     int r;\r
8312     \r
8313     while (count--) {\r
8314         r = write(cp->fdTo, message++, 1);\r
8315         if (r == -1) {\r
8316             *outError = errno;\r
8317             return outCount;\r
8318         }\r
8319         ++outCount;\r
8320         if (msdelay >= 0)\r
8321           TimeDelay(msdelay);\r
8322     }\r
8323 \r
8324     return outCount;\r
8325 }\r
8326 \r
8327 /****   Animation code by Hugh Fisher, DCS, ANU.\r
8328 \r
8329         Known problem: if a window overlapping the board is\r
8330         moved away while a piece is being animated underneath,\r
8331         the newly exposed area won't be updated properly.\r
8332         I can live with this.\r
8333 \r
8334         Known problem: if you look carefully at the animation\r
8335         of pieces in mono mode, they are being drawn as solid\r
8336         shapes without interior detail while moving. Fixing\r
8337         this would be a major complication for minimal return.\r
8338 ****/\r
8339 \r
8340 /*      Masks for XPM pieces. Black and white pieces can have\r
8341         different shapes, but in the interest of retaining my\r
8342         sanity pieces must have the same outline on both light\r
8343         and dark squares, and all pieces must use the same\r
8344         background square colors/images.                */\r
8345 \r
8346 static void\r
8347 CreateAnimMasks (pieceDepth)\r
8348      int pieceDepth;\r
8349 {\r
8350   ChessSquare   piece;\r
8351   Pixmap        buf;\r
8352   GC            bufGC, maskGC;\r
8353   int           kind, n;\r
8354   unsigned long plane;\r
8355   XGCValues     values;\r
8356 \r
8357   /* Need a bitmap just to get a GC with right depth */\r
8358   buf = XCreatePixmap(xDisplay, xBoardWindow,\r
8359                         8, 8, 1);\r
8360   values.foreground = 1;\r
8361   values.background = 0;\r
8362   /* Don't use XtGetGC, not read only */\r
8363   maskGC = XCreateGC(xDisplay, buf,\r
8364                     GCForeground | GCBackground, &values);\r
8365   XFreePixmap(xDisplay, buf);\r
8366 \r
8367   buf = XCreatePixmap(xDisplay, xBoardWindow,\r
8368                       squareSize, squareSize, pieceDepth);            \r
8369   values.foreground = XBlackPixel(xDisplay, xScreen);\r
8370   values.background = XWhitePixel(xDisplay, xScreen);\r
8371   bufGC = XCreateGC(xDisplay, buf,\r
8372                     GCForeground | GCBackground, &values);\r
8373 \r
8374   for (piece = WhitePawn; piece <= BlackKing; piece++) {\r
8375     /* Begin with empty mask */\r
8376     xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,\r
8377                                  squareSize, squareSize, 1);\r
8378     XSetFunction(xDisplay, maskGC, GXclear);\r
8379     XFillRectangle(xDisplay, xpmMask[piece], maskGC,\r
8380                    0, 0, squareSize, squareSize);\r
8381                    \r
8382     /* Take a copy of the piece */\r
8383     if (White(piece))\r
8384       kind = 0;\r
8385     else\r
8386       kind = 2;\r
8387     XSetFunction(xDisplay, bufGC, GXcopy);\r
8388     XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],\r
8389               buf, bufGC,\r
8390               0, 0, squareSize, squareSize, 0, 0);\r
8391               \r
8392     /* XOR the background (light) over the piece */\r
8393     XSetFunction(xDisplay, bufGC, GXxor);\r
8394     if (useImageSqs)\r
8395       XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,\r
8396                 0, 0, squareSize, squareSize, 0, 0);\r
8397     else {\r
8398       XSetForeground(xDisplay, bufGC, lightSquareColor);\r
8399       XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);\r
8400     }\r
8401     \r
8402     /* We now have an inverted piece image with the background\r
8403        erased. Construct mask by just selecting all the non-zero\r
8404        pixels - no need to reconstruct the original image.      */\r
8405     XSetFunction(xDisplay, maskGC, GXor);\r
8406     plane = 1;\r
8407     /* Might be quicker to download an XImage and create bitmap\r
8408        data from it rather than this N copies per piece, but it\r
8409        only takes a fraction of a second and there is a much\r
8410        longer delay for loading the pieces.             */\r
8411     for (n = 0; n < pieceDepth; n ++) {\r
8412       XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,\r
8413                  0, 0, squareSize, squareSize,\r
8414                  0, 0, plane);\r
8415       plane = plane << 1;\r
8416     }\r
8417   }\r
8418   /* Clean up */\r
8419   XFreePixmap(xDisplay, buf);\r
8420   XFreeGC(xDisplay, bufGC);\r
8421   XFreeGC(xDisplay, maskGC);\r
8422 }\r
8423 \r
8424 static void\r
8425 InitAnimState (anim, info)\r
8426   AnimState * anim;\r
8427   XWindowAttributes * info;\r
8428 {\r
8429   XtGCMask  mask;\r
8430   XGCValues values;\r
8431   \r
8432   /* Each buffer is square size, same depth as window */\r
8433   anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,\r
8434                         squareSize, squareSize, info->depth);\r
8435   anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,\r
8436                         squareSize, squareSize, info->depth);\r
8437 \r
8438   /* Create a plain GC for blitting */\r
8439   mask = GCForeground | GCBackground | GCFunction |\r
8440          GCPlaneMask | GCGraphicsExposures;\r
8441   values.foreground = XBlackPixel(xDisplay, xScreen);\r
8442   values.background = XWhitePixel(xDisplay, xScreen);\r
8443   values.function   = GXcopy;\r
8444   values.plane_mask = AllPlanes;\r
8445   values.graphics_exposures = False;\r
8446   anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);\r
8447 \r
8448   /* Piece will be copied from an existing context at\r
8449      the start of each new animation/drag. */\r
8450   anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);\r
8451 \r
8452   /* Outline will be a read-only copy of an existing */\r
8453   anim->outlineGC = None;\r
8454 }\r
8455 \r
8456 static void\r
8457 CreateAnimVars ()\r
8458 {\r
8459   static int done = 0;\r
8460   XWindowAttributes info;\r
8461 \r
8462   if (done) return;\r
8463   done = 1;\r
8464   XGetWindowAttributes(xDisplay, xBoardWindow, &info);\r
8465   \r
8466   InitAnimState(&game, &info);\r
8467   InitAnimState(&player, &info);\r
8468   \r
8469   /* For XPM pieces, we need bitmaps to use as masks. */\r
8470   if (useImages)\r
8471     CreateAnimMasks(info.depth);\r
8472 }\r
8473 \r
8474 #ifndef HAVE_USLEEP\r
8475 \r
8476 static Boolean frameWaiting;\r
8477 \r
8478 static RETSIGTYPE FrameAlarm (sig)\r
8479      int sig;\r
8480 {\r
8481   frameWaiting = False;\r
8482   /* In case System-V style signals.  Needed?? */\r
8483   signal(SIGALRM, FrameAlarm);\r
8484 }\r
8485 \r
8486 static void\r
8487 FrameDelay (time)\r
8488      int time;\r
8489 {\r
8490   struct itimerval delay;\r
8491   \r
8492   XSync(xDisplay, False);\r
8493 \r
8494   if (time > 0) {\r
8495     frameWaiting = True;\r
8496     signal(SIGALRM, FrameAlarm);\r
8497     delay.it_interval.tv_sec = \r
8498       delay.it_value.tv_sec = time / 1000;\r
8499     delay.it_interval.tv_usec = \r
8500       delay.it_value.tv_usec = (time % 1000) * 1000;\r
8501     setitimer(ITIMER_REAL, &delay, NULL);\r
8502 #if 0\r
8503     /* Ugh -- busy-wait! --tpm */\r
8504     while (frameWaiting); \r
8505 #else\r
8506     while (frameWaiting) pause();\r
8507 #endif\r
8508     delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;\r
8509     delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;\r
8510     setitimer(ITIMER_REAL, &delay, NULL);\r
8511   }\r
8512 }\r
8513 \r
8514 #else\r
8515 \r
8516 static void\r
8517 FrameDelay (time)\r
8518      int time;\r
8519 {\r
8520   XSync(xDisplay, False);\r
8521   if (time > 0)\r
8522     usleep(time * 1000);\r
8523 }\r
8524 \r
8525 #endif\r
8526 \r
8527 /*      Convert board position to corner of screen rect and color       */\r
8528 \r
8529 static void\r
8530 ScreenSquare(column, row, pt, color)\r
8531      int column; int row; XPoint * pt; int * color;\r
8532 {\r
8533   if (flipView) {\r
8534     pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);\r
8535     pt->y = lineGap + row * (squareSize + lineGap);\r
8536   } else {\r
8537     pt->x = lineGap + column * (squareSize + lineGap);\r
8538     pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);\r
8539   }\r
8540   *color = SquareColor(row, column);\r
8541 }\r
8542 \r
8543 /*      Convert window coords to square                 */\r
8544 \r
8545 static void\r
8546 BoardSquare(x, y, column, row)\r
8547      int x; int y; int * column; int * row;\r
8548 {\r
8549   *column = EventToSquare(x, BOARD_WIDTH);\r
8550   if (flipView && *column >= 0)\r
8551     *column = BOARD_WIDTH - 1 - *column;\r
8552   *row = EventToSquare(y, BOARD_HEIGHT);\r
8553   if (!flipView && *row >= 0)\r
8554     *row = BOARD_HEIGHT - 1 - *row;\r
8555 }\r
8556 \r
8557 /*   Utilities  */\r
8558 \r
8559 #undef Max  /* just in case */\r
8560 #undef Min\r
8561 #define Max(a, b) ((a) > (b) ? (a) : (b))\r
8562 #define Min(a, b) ((a) < (b) ? (a) : (b))\r
8563 \r
8564 static void\r
8565 SetRect(rect, x, y, width, height)\r
8566      XRectangle * rect; int x; int y; int width; int height;\r
8567 {\r
8568   rect->x = x;\r
8569   rect->y = y;\r
8570   rect->width  = width;\r
8571   rect->height = height;\r
8572 }\r
8573 \r
8574 /*      Test if two frames overlap. If they do, return\r
8575         intersection rect within old and location of\r
8576         that rect within new. */\r
8577         \r
8578 static Boolean\r
8579 Intersect(old, new, size, area, pt)\r
8580      XPoint * old; XPoint * new;\r
8581      int size; XRectangle * area; XPoint * pt;\r
8582 {\r
8583   if (old->x > new->x + size || new->x > old->x + size ||\r
8584       old->y > new->y + size || new->y > old->y + size) {\r
8585     return False;\r
8586   } else {\r
8587     SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),\r
8588             size - abs(old->x - new->x), size - abs(old->y - new->y));\r
8589     pt->x = Max(old->x - new->x, 0);\r
8590     pt->y = Max(old->y - new->y, 0);\r
8591     return True;\r
8592   }\r
8593 }\r
8594 \r
8595 /*      For two overlapping frames, return the rect(s)\r
8596         in the old that do not intersect with the new.   */\r
8597         \r
8598 static void\r
8599 CalcUpdateRects(old, new, size, update, nUpdates)\r
8600      XPoint * old; XPoint * new; int size;\r
8601      XRectangle update[]; int * nUpdates;\r
8602 {\r
8603   int        count;\r
8604 \r
8605   /* If old = new (shouldn't happen) then nothing to draw */\r
8606   if (old->x == new->x && old->y == new->y) {\r
8607     *nUpdates = 0;\r
8608     return;\r
8609   }\r
8610   /* Work out what bits overlap. Since we know the rects\r
8611      are the same size we don't need a full intersect calc. */\r
8612   count = 0;\r
8613   /* Top or bottom edge? */\r
8614   if (new->y > old->y) {\r
8615     SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);\r
8616     count ++;\r
8617   } else if (old->y > new->y) {\r
8618     SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),\r
8619                               size, old->y - new->y);\r
8620     count ++;\r
8621   }\r
8622   /* Left or right edge - don't overlap any update calculated above. */\r
8623   if (new->x > old->x) {\r
8624     SetRect(&(update[count]), old->x, Max(new->y, old->y),\r
8625                               new->x - old->x, size - abs(new->y - old->y));\r
8626     count ++;\r
8627   } else if (old->x > new->x) {\r
8628     SetRect(&(update[count]), new->x + size, Max(new->y, old->y),\r
8629                               old->x - new->x, size - abs(new->y - old->y));\r
8630     count ++;\r
8631   }\r
8632   /* Done */\r
8633   *nUpdates = count;\r
8634 }\r
8635 \r
8636 /*      Generate a series of frame coords from start->mid->finish.\r
8637         The movement rate doubles until the half way point is\r
8638         reached, then halves back down to the final destination,\r
8639         which gives a nice slow in/out effect. The algorithmn\r
8640         may seem to generate too many intermediates for short\r
8641         moves, but remember that the purpose is to attract the\r
8642         viewers attention to the piece about to be moved and\r
8643         then to where it ends up. Too few frames would be less\r
8644         noticeable.                                             */\r
8645 \r
8646 static void\r
8647 Tween(start, mid, finish, factor, frames, nFrames)\r
8648      XPoint * start; XPoint * mid;\r
8649      XPoint * finish; int factor;\r
8650      XPoint frames[]; int * nFrames;\r
8651 {\r
8652   int fraction, n, count;\r
8653 \r
8654   count = 0;\r
8655 \r
8656   /* Slow in, stepping 1/16th, then 1/8th, ... */\r
8657   fraction = 1;\r
8658   for (n = 0; n < factor; n++)\r
8659     fraction *= 2;\r
8660   for (n = 0; n < factor; n++) {\r
8661     frames[count].x = start->x + (mid->x - start->x) / fraction;\r
8662     frames[count].y = start->y + (mid->y - start->y) / fraction;\r
8663     count ++;\r
8664     fraction = fraction / 2;\r
8665   }\r
8666   \r
8667   /* Midpoint */\r
8668   frames[count] = *mid;\r
8669   count ++;\r
8670   \r
8671   /* Slow out, stepping 1/2, then 1/4, ... */\r
8672   fraction = 2;\r
8673   for (n = 0; n < factor; n++) {\r
8674     frames[count].x = finish->x - (finish->x - mid->x) / fraction;\r
8675     frames[count].y = finish->y - (finish->y - mid->y) / fraction;\r
8676     count ++;\r
8677     fraction = fraction * 2;\r
8678   }\r
8679   *nFrames = count;\r
8680 }\r
8681 \r
8682 /*      Draw a piece on the screen without disturbing what's there      */\r
8683 \r
8684 static void\r
8685 SelectGCMask(piece, clip, outline, mask)\r
8686      ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;\r
8687 {\r
8688   GC source;\r
8689 \r
8690   /* Bitmap for piece being moved. */\r
8691   if (appData.monoMode) {\r
8692       *mask = *pieceToSolid(piece);\r
8693   } else if (useImages) {\r
8694 #if HAVE_LIBXPM\r
8695       *mask = xpmMask[piece];\r
8696 #else\r
8697       *mask = ximMaskPm[piece%(int)BlackPawn];\r
8698 #endif\r
8699   } else {\r
8700       *mask = *pieceToSolid(piece);\r
8701   }\r
8702 \r
8703   /* GC for piece being moved. Square color doesn't matter, but\r
8704      since it gets modified we make a copy of the original. */\r
8705   if (White(piece)) {\r
8706     if (appData.monoMode)\r
8707       source = bwPieceGC;\r
8708     else\r
8709       source = wlPieceGC;\r
8710   } else {\r
8711     if (appData.monoMode)\r
8712       source = wbPieceGC;\r
8713     else\r
8714       source = blPieceGC;\r
8715   }\r
8716   XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);\r
8717   \r
8718   /* Outline only used in mono mode and is not modified */\r
8719   if (White(piece))\r
8720     *outline = bwPieceGC;\r
8721   else\r
8722     *outline = wbPieceGC;\r
8723 }\r
8724 \r
8725 static void\r
8726 OverlayPiece(piece, clip, outline,  dest)\r
8727      ChessSquare piece; GC clip; GC outline; Drawable dest;\r
8728 {\r
8729   int   kind;\r
8730   \r
8731   if (!useImages) {\r
8732     /* Draw solid rectangle which will be clipped to shape of piece */\r
8733     XFillRectangle(xDisplay, dest, clip,\r
8734                    0, 0, squareSize, squareSize);\r
8735     if (appData.monoMode)\r
8736       /* Also draw outline in contrasting color for black\r
8737          on black / white on white cases                */\r
8738       XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,\r
8739                  0, 0, squareSize, squareSize, 0, 0, 1);\r
8740   } else {\r
8741     /* Copy the piece */\r
8742     if (White(piece))\r
8743       kind = 0;\r
8744     else\r
8745       kind = 2;\r
8746     XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],\r
8747               dest, clip,\r
8748               0, 0, squareSize, squareSize,\r
8749               0, 0);            \r
8750   }\r
8751 }\r
8752 \r
8753 /* Animate the movement of a single piece */\r
8754 \r
8755 static void \r
8756 BeginAnimation(anim, piece, startColor, start)\r
8757      AnimState *anim;\r
8758      ChessSquare piece;\r
8759      int startColor;\r
8760      XPoint * start;\r
8761 {\r
8762   Pixmap mask;\r
8763   \r
8764   /* The old buffer is initialised with the start square (empty) */\r
8765   BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);\r
8766   anim->prevFrame = *start;\r
8767   \r
8768   /* The piece will be drawn using its own bitmap as a matte    */\r
8769   SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);\r
8770   XSetClipMask(xDisplay, anim->pieceGC, mask);\r
8771 }\r
8772 \r
8773 static void\r
8774 AnimationFrame(anim, frame, piece)\r
8775      AnimState *anim;\r
8776      XPoint *frame;\r
8777      ChessSquare piece;\r
8778 {\r
8779   XRectangle updates[4];\r
8780   XRectangle overlap;\r
8781   XPoint     pt;\r
8782   int        count, i;\r
8783   \r
8784   /* Save what we are about to draw into the new buffer */\r
8785   XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,\r
8786             frame->x, frame->y, squareSize, squareSize,\r
8787             0, 0);\r
8788                 \r
8789   /* Erase bits of the previous frame */\r
8790   if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {\r
8791     /* Where the new frame overlapped the previous,\r
8792        the contents in newBuf are wrong. */\r
8793     XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,\r
8794               overlap.x, overlap.y,\r
8795               overlap.width, overlap.height,\r
8796               pt.x, pt.y);\r
8797     /* Repaint the areas in the old that don't overlap new */\r
8798     CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);\r
8799     for (i = 0; i < count; i++)\r
8800       XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,\r
8801                 updates[i].x - anim->prevFrame.x,\r
8802                 updates[i].y - anim->prevFrame.y,\r
8803                 updates[i].width, updates[i].height,\r
8804                 updates[i].x, updates[i].y);\r
8805   } else {\r
8806     /* Easy when no overlap */\r
8807     XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,\r
8808                   0, 0, squareSize, squareSize,\r
8809                   anim->prevFrame.x, anim->prevFrame.y);\r
8810   }\r
8811 \r
8812   /* Save this frame for next time round */\r
8813   XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,\r
8814                 0, 0, squareSize, squareSize,\r
8815                 0, 0);\r
8816   anim->prevFrame = *frame;\r
8817   \r
8818   /* Draw piece over original screen contents, not current,\r
8819      and copy entire rect. Wipes out overlapping piece images. */\r
8820   OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);\r
8821   XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,\r
8822                 0, 0, squareSize, squareSize,\r
8823                 frame->x, frame->y);\r
8824 }\r
8825 \r
8826 static void\r
8827 EndAnimation (anim, finish)\r
8828      AnimState *anim;\r
8829      XPoint *finish;\r
8830 {\r
8831   XRectangle updates[4];\r
8832   XRectangle overlap;\r
8833   XPoint     pt;\r
8834   int        count, i;\r
8835 \r
8836   /* The main code will redraw the final square, so we\r
8837      only need to erase the bits that don't overlap.    */\r
8838   if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {\r
8839     CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);\r
8840     for (i = 0; i < count; i++)\r
8841       XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,\r
8842                 updates[i].x - anim->prevFrame.x,\r
8843                 updates[i].y - anim->prevFrame.y,\r
8844                 updates[i].width, updates[i].height,\r
8845                 updates[i].x, updates[i].y);\r
8846   } else {\r
8847     XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,\r
8848                 0, 0, squareSize, squareSize,\r
8849                 anim->prevFrame.x, anim->prevFrame.y);\r
8850   }\r
8851 }\r
8852 \r
8853 static void\r
8854 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)\r
8855      AnimState *anim;\r
8856      ChessSquare piece; int startColor;\r
8857      XPoint * start; XPoint * finish;\r
8858      XPoint frames[]; int nFrames;\r
8859 {\r
8860   int n;\r
8861 \r
8862   BeginAnimation(anim, piece, startColor, start);\r
8863   for (n = 0; n < nFrames; n++) {\r
8864     AnimationFrame(anim, &(frames[n]), piece);\r
8865     FrameDelay(appData.animSpeed);\r
8866   }\r
8867   EndAnimation(anim, finish);\r
8868 }\r
8869 \r
8870 /* Main control logic for deciding what to animate and how */\r
8871 \r
8872 void\r
8873 AnimateMove(board, fromX, fromY, toX, toY)\r
8874      Board board;\r
8875      int fromX;\r
8876      int fromY;\r
8877      int toX;\r
8878      int toY;\r
8879 {\r
8880   ChessSquare piece;\r
8881   int hop;\r
8882   XPoint      start, finish, mid;\r
8883   XPoint      frames[kFactor * 2 + 1];\r
8884   int         nFrames, startColor, endColor;\r
8885 \r
8886   /* Are we animating? */\r
8887   if (!appData.animate || appData.blindfold)\r
8888     return;\r
8889 \r
8890   if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;\r
8891   piece = board[fromY][fromX];\r
8892   if (piece >= EmptySquare) return;\r
8893 \r
8894 #if DONT_HOP\r
8895   hop = FALSE;\r
8896 #else\r
8897   hop = (piece == WhiteKnight || piece == BlackKnight);\r
8898 #endif\r
8899 \r
8900   if (appData.debugMode) {\r
8901       printf("AnimateMove: piece %d %s from %d,%d to %d,%d \n",\r
8902              piece, hop ? "hops" : "slides", fromX, fromY, toX, toY);\r
8903   }\r
8904 \r
8905   ScreenSquare(fromX, fromY, &start, &startColor);\r
8906   ScreenSquare(toX, toY, &finish, &endColor);\r
8907 \r
8908   if (hop) {\r
8909     /* Knight: make diagonal movement then straight */\r
8910     if (abs(toY - fromY) < abs(toX - fromX)) {\r
8911        mid.x = start.x + (finish.x - start.x) / 2;\r
8912        mid.y = finish.y;\r
8913      } else {\r
8914        mid.x = finish.x;\r
8915        mid.y = start.y + (finish.y - start.y) / 2;\r
8916      }\r
8917   } else {\r
8918     mid.x = start.x + (finish.x - start.x) / 2;\r
8919     mid.y = start.y + (finish.y - start.y) / 2;\r
8920   }\r
8921   \r
8922   /* Don't use as many frames for very short moves */\r
8923   if (abs(toY - fromY) + abs(toX - fromX) <= 2)\r
8924     Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);\r
8925   else\r
8926     Tween(&start, &mid, &finish, kFactor, frames, &nFrames);\r
8927   FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);\r
8928   \r
8929   /* Be sure end square is redrawn */\r
8930   damage[toY][toX] = True;\r
8931 }\r
8932 \r
8933 static void\r
8934 DragPieceBegin(x, y)\r
8935      int x; int y;\r
8936 {\r
8937     int  boardX, boardY, color;\r
8938     XPoint corner;\r
8939 \r
8940     /* Are we animating? */\r
8941     if (!appData.animateDragging || appData.blindfold)\r
8942       return;\r
8943      \r
8944     /* Figure out which square we start in and the\r
8945        mouse position relative to top left corner. */\r
8946     BoardSquare(x, y, &boardX, &boardY);\r
8947     player.startBoardX = boardX;\r
8948     player.startBoardY = boardY;\r
8949     ScreenSquare(boardX, boardY, &corner, &color);\r
8950     player.startSquare  = corner;\r
8951     player.startColor   = color;\r
8952 #if 0\r
8953     /* Start from exactly where the piece is.  This can be confusing\r
8954        if you start dragging far from the center of the square; most\r
8955        or all of the piece can be over a different square from the one\r
8956        the mouse pointer is in. */\r
8957     player.mouseDelta.x = x - corner.x;\r
8958     player.mouseDelta.y = y - corner.y;\r
8959 #else\r
8960     /* As soon as we start dragging, the piece will jump slightly to\r
8961        be centered over the mouse pointer. */\r
8962     player.mouseDelta.x = squareSize/2;\r
8963     player.mouseDelta.y = squareSize/2;\r
8964 #endif\r
8965     /* Initialise animation */\r
8966     player.dragPiece = PieceForSquare(boardX, boardY);\r
8967     /* Sanity check */\r
8968     if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {\r
8969         player.dragActive = True;\r
8970         BeginAnimation(&player, player.dragPiece, color, &corner);\r
8971         /* Mark this square as needing to be redrawn. Note that\r
8972            we don't remove the piece though, since logically (ie\r
8973            as seen by opponent) the move hasn't been made yet. */\r
8974         damage[boardY][boardX] = True;\r
8975     } else {\r
8976         player.dragActive = False;\r
8977     }\r
8978 }\r
8979 \r
8980 static void\r
8981 DragPieceMove(x, y)\r
8982      int x; int y;\r
8983 {\r
8984     XPoint corner;\r
8985 \r
8986     /* Are we animating? */\r
8987     if (!appData.animateDragging || appData.blindfold)\r
8988       return;\r
8989      \r
8990     /* Sanity check */\r
8991     if (! player.dragActive)\r
8992       return;\r
8993     /* Move piece, maintaining same relative position\r
8994        of mouse within square    */\r
8995     corner.x = x - player.mouseDelta.x;\r
8996     corner.y = y - player.mouseDelta.y;\r
8997     AnimationFrame(&player, &corner, player.dragPiece);\r
8998 #if HIGHDRAG\r
8999     if (appData.highlightDragging) {\r
9000         int boardX, boardY;\r
9001         BoardSquare(x, y, &boardX, &boardY);\r
9002         SetHighlights(fromX, fromY, boardX, boardY);\r
9003     }\r
9004 #endif\r
9005 }\r
9006 \r
9007 static void\r
9008 DragPieceEnd(x, y)\r
9009      int x; int y;\r
9010 {\r
9011     int boardX, boardY, color;\r
9012     XPoint corner;\r
9013 \r
9014     /* Are we animating? */\r
9015     if (!appData.animateDragging || appData.blindfold)\r
9016       return;\r
9017      \r
9018     /* Sanity check */\r
9019     if (! player.dragActive)\r
9020       return;\r
9021     /* Last frame in sequence is square piece is\r
9022        placed on, which may not match mouse exactly. */\r
9023     BoardSquare(x, y, &boardX, &boardY);\r
9024     ScreenSquare(boardX, boardY, &corner, &color);\r
9025     EndAnimation(&player, &corner);\r
9026 \r
9027     /* Be sure end square is redrawn */\r
9028     damage[boardY][boardX] = True;\r
9029 \r
9030     /* This prevents weird things happening with fast successive\r
9031        clicks which on my Sun at least can cause motion events\r
9032        without corresponding press/release. */\r
9033     player.dragActive = False;\r
9034 }\r
9035 \r
9036 /* Handle expose event while piece being dragged */\r
9037 \r
9038 static void\r
9039 DrawDragPiece ()\r
9040 {\r
9041   if (!player.dragActive || appData.blindfold)\r
9042     return;\r
9043 \r
9044   /* What we're doing: logically, the move hasn't been made yet,\r
9045      so the piece is still in it's original square. But visually\r
9046      it's being dragged around the board. So we erase the square\r
9047      that the piece is on and draw it at the last known drag point. */\r
9048   BlankSquare(player.startSquare.x, player.startSquare.y,\r
9049                 player.startColor, EmptySquare, xBoardWindow);\r
9050   AnimationFrame(&player, &player.prevFrame, player.dragPiece);\r
9051   damage[player.startBoardY][player.startBoardX] = TRUE;\r
9052 }\r
9053 \r
9054 void\r
9055 SetProgramStats( FrontEndProgramStats * stats )\r
9056 {\r
9057   // [HR] TODO
9058   // [HGM] done, but perhaps backend should call this directly?\r
9059     EngineOutputUpdate( stats );\r
9060 }\r