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