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