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