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