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