2 * xboard.c -- X front end for XBoard
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
8 * 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
10 * The following terms apply to Digital Equipment Corporation's copyright
12 * ------------------------------------------------------------------------
15 * Permission to use, copy, modify, and distribute this software and its
16 * documentation for any purpose and without fee is hereby granted,
17 * provided that the above copyright notice appear in all copies and that
18 * both that copyright notice and this permission notice appear in
19 * supporting documentation, and that the name of Digital not be
20 * used in advertising or publicity pertaining to distribution of the
21 * software without specific, written prior permission.
23 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
30 * ------------------------------------------------------------------------
32 * The following terms apply to the enhanced version of XBoard
33 * distributed by the Free Software Foundation:
34 * ------------------------------------------------------------------------
36 * GNU XBoard is free software: you can redistribute it and/or modify
37 * it under the terms of the GNU General Public License as published by
38 * the Free Software Foundation, either version 3 of the License, or (at
39 * your option) any later version.
41 * GNU XBoard is distributed in the hope that it will be useful, but
42 * WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44 * General Public License for more details.
46 * You should have received a copy of the GNU General Public License
47 * along with this program. If not, see http://www.gnu.org/licenses/. *
49 *------------------------------------------------------------------------
50 ** See the file ChangeLog for a revision history. */
60 #include <sys/types.h>
66 # if HAVE_SYS_SOCKET_H
67 # include <sys/socket.h>
68 # include <netinet/in.h>
70 # else /* not HAVE_SYS_SOCKET_H */
71 # if HAVE_LAN_SOCKET_H
72 # include <lan/socket.h>
74 # include <lan/netdb.h>
75 # else /* not HAVE_LAN_SOCKET_H */
76 # define OMIT_SOCKETS 1
77 # endif /* not HAVE_LAN_SOCKET_H */
78 # endif /* not HAVE_SYS_SOCKET_H */
79 #endif /* !OMIT_SOCKETS */
84 #else /* not STDC_HEADERS */
85 extern char *getenv();
88 # else /* not HAVE_STRING_H */
90 # endif /* not HAVE_STRING_H */
91 #endif /* not STDC_HEADERS */
94 # include <sys/fcntl.h>
95 #else /* not HAVE_SYS_FCNTL_H */
98 # endif /* HAVE_FCNTL_H */
99 #endif /* not HAVE_SYS_FCNTL_H */
101 #if HAVE_SYS_SYSTEMINFO_H
102 # include <sys/systeminfo.h>
103 #endif /* HAVE_SYS_SYSTEMINFO_H */
105 #if TIME_WITH_SYS_TIME
106 # include <sys/time.h>
110 # include <sys/time.h>
121 # include <sys/wait.h>
126 # define NAMLEN(dirent) strlen((dirent)->d_name)
127 # define HAVE_DIR_STRUCT
129 # define dirent direct
130 # define NAMLEN(dirent) (dirent)->d_namlen
132 # include <sys/ndir.h>
133 # define HAVE_DIR_STRUCT
136 # include <sys/dir.h>
137 # define HAVE_DIR_STRUCT
141 # define HAVE_DIR_STRUCT
145 #include <X11/Intrinsic.h>
146 #include <X11/StringDefs.h>
147 #include <X11/Shell.h>
148 #include <X11/cursorfont.h>
149 #include <X11/Xatom.h>
150 #include <X11/Xmu/Atoms.h>
152 #include <X11/Xaw3d/Dialog.h>
153 #include <X11/Xaw3d/Form.h>
154 #include <X11/Xaw3d/List.h>
155 #include <X11/Xaw3d/Label.h>
156 #include <X11/Xaw3d/SimpleMenu.h>
157 #include <X11/Xaw3d/SmeBSB.h>
158 #include <X11/Xaw3d/SmeLine.h>
159 #include <X11/Xaw3d/Box.h>
160 #include <X11/Xaw3d/MenuButton.h>
161 #include <X11/Xaw3d/Text.h>
162 #include <X11/Xaw3d/AsciiText.h>
164 #include <X11/Xaw/Dialog.h>
165 #include <X11/Xaw/Form.h>
166 #include <X11/Xaw/List.h>
167 #include <X11/Xaw/Label.h>
168 #include <X11/Xaw/SimpleMenu.h>
169 #include <X11/Xaw/SmeBSB.h>
170 #include <X11/Xaw/SmeLine.h>
171 #include <X11/Xaw/Box.h>
172 #include <X11/Xaw/MenuButton.h>
173 #include <X11/Xaw/Text.h>
174 #include <X11/Xaw/AsciiText.h>
177 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
182 #include "pixmaps/pixmaps.h"
183 #define IMAGE_EXT "xpm"
185 #define IMAGE_EXT "xim"
186 #include "bitmaps/bitmaps.h"
189 #include "bitmaps/icon_white.bm"
190 #include "bitmaps/icon_black.bm"
191 #include "bitmaps/checkmark.bm"
193 #include "frontend.h"
195 #include "backendz.h"
199 #include "xgamelist.h"
200 #include "xhistory.h"
201 #include "xedittags.h"
204 // must be moved to xengineoutput.h
206 void EngineOutputProc P((Widget w, XEvent *event,
207 String *prms, Cardinal *nprms));
208 void EvalGraphProc P((Widget w, XEvent *event,
209 String *prms, Cardinal *nprms));
216 #define usleep(t) _sleep2(((t)+500)/1000)
220 # define _(s) gettext (s)
221 # define N_(s) gettext_noop (s)
239 int main P((int argc, char **argv));
240 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
241 char *init_path, char *filter, char *mode, int (*show_entry)(), char **name_return));
242 RETSIGTYPE CmailSigHandler P((int sig));
243 RETSIGTYPE IntSigHandler P((int sig));
244 RETSIGTYPE TermSizeSigHandler P((int sig));
245 void CreateGCs P((int redo));
246 void CreateXIMPieces P((void));
247 void CreateXPMPieces P((void));
248 void CreateXPMBoard P((char *s, int n));
249 void CreatePieces P((void));
250 void CreatePieceMenus P((void));
251 Widget CreateMenuBar P((Menu *mb));
252 Widget CreateButtonBar P ((MenuItem *mi));
253 char *FindFont P((char *pattern, int targetPxlSize));
254 void PieceMenuPopup P((Widget w, XEvent *event,
255 String *params, Cardinal *num_params));
256 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
257 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
258 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
259 u_int wreq, u_int hreq));
260 void CreateGrid P((void));
261 int EventToSquare P((int x, int limit));
262 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
263 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
264 void MoveTypeInProc P((Widget widget, caddr_t unused, XEvent *event));
265 void HandleUserMove P((Widget w, XEvent *event,
266 String *prms, Cardinal *nprms));
267 void AnimateUserMove P((Widget w, XEvent * event,
268 String * params, Cardinal * nParams));
269 void HandlePV P((Widget w, XEvent * event,
270 String * params, Cardinal * nParams));
271 void SelectPV P((Widget w, XEvent * event,
272 String * params, Cardinal * nParams));
273 void StopPV P((Widget w, XEvent * event,
274 String * params, Cardinal * nParams));
275 void WhiteClock P((Widget w, XEvent *event,
276 String *prms, Cardinal *nprms));
277 void BlackClock P((Widget w, XEvent *event,
278 String *prms, Cardinal *nprms));
279 void DrawPositionProc P((Widget w, XEvent *event,
280 String *prms, Cardinal *nprms));
281 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
283 void CommentClick P((Widget w, XEvent * event,
284 String * params, Cardinal * nParams));
285 void CommentPopUp P((char *title, char *label));
286 void CommentPopDown P((void));
287 void ICSInputBoxPopUp P((void));
288 void ICSInputBoxPopDown P((void));
289 void FileNamePopUp P((char *label, char *def, char *filter,
290 FileProc proc, char *openMode));
291 void FileNamePopDown P((void));
292 void FileNameCallback P((Widget w, XtPointer client_data,
293 XtPointer call_data));
294 void FileNameAction P((Widget w, XEvent *event,
295 String *prms, Cardinal *nprms));
296 void AskQuestionReplyAction P((Widget w, XEvent *event,
297 String *prms, Cardinal *nprms));
298 void AskQuestionProc P((Widget w, XEvent *event,
299 String *prms, Cardinal *nprms));
300 void AskQuestionPopDown P((void));
301 void PromotionPopDown P((void));
302 void PromotionCallback P((Widget w, XtPointer client_data,
303 XtPointer call_data));
304 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
305 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
306 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
307 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
309 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
311 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
313 void LoadPositionProc P((Widget w, XEvent *event,
314 String *prms, Cardinal *nprms));
315 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
317 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
319 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
321 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
323 void PastePositionProc P((Widget w, XEvent *event, String *prms,
325 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
326 void CopyGameListProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
327 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
328 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
329 void SavePositionProc P((Widget w, XEvent *event,
330 String *prms, Cardinal *nprms));
331 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
332 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
334 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
335 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
336 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
338 void MachineWhiteProc P((Widget w, XEvent *event,
339 String *prms, Cardinal *nprms));
340 void AnalyzeModeProc P((Widget w, XEvent *event,
341 String *prms, Cardinal *nprms));
342 void AnalyzeFileProc P((Widget w, XEvent *event,
343 String *prms, Cardinal *nprms));
344 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
346 void MatchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
347 void MatchOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
348 void IcsClientProc P((Widget w, XEvent *event, String *prms,
350 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
351 void EditPositionProc P((Widget w, XEvent *event,
352 String *prms, Cardinal *nprms));
353 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
354 void EditCommentProc P((Widget w, XEvent *event,
355 String *prms, Cardinal *nprms));
356 void IcsInputBoxProc P((Widget w, XEvent *event,
357 String *prms, Cardinal *nprms));
358 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
359 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
365 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
369 void TypeInProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
370 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
371 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
372 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
373 void StopObservingProc P((Widget w, XEvent *event, String *prms,
375 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
377 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
379 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
380 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
384 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
386 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
388 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
389 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
391 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
393 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
395 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
396 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
397 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
398 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
400 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
401 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
403 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
405 void HighlightArrowProc P((Widget w, XEvent *event, String *prms,
407 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
408 //void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
409 void OneClickProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
410 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
412 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
414 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
416 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
418 //void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
419 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
421 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
423 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
425 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
427 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
428 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
429 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
430 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
431 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
432 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
433 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
434 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
435 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
436 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
437 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void DisplayMove P((int moveNumber));
439 void DisplayTitle P((char *title));
440 void ICSInitScript P((void));
441 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
442 void ErrorPopUp P((char *title, char *text, int modal));
443 void ErrorPopDown P((void));
444 static char *ExpandPathName P((char *path));
445 static void CreateAnimVars P((void));
446 static void DragPieceMove P((int x, int y));
447 static void DrawDragPiece P((void));
448 char *ModeToWidgetName P((GameMode mode));
449 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
450 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
451 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
452 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
453 void OptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
454 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
455 void IcsTextProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
456 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
457 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
458 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
459 void IcsOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
460 void SoundOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
461 void BoardOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
462 void LoadOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
463 void SaveOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
464 void GameListOptionsPopDown P(());
465 void ShufflePopDown P(());
466 void TimeControlPopDown P(());
467 void GenericPopDown P(());
468 void update_ics_width P(());
469 int get_term_width P(());
470 int CopyMemoProc P(());
471 void DrawArrowHighlight P((int fromX, int fromY, int toX,int toY));
472 Boolean IsDrawArrowEnabled P(());
475 * XBoard depends on Xt R4 or higher
477 int xtVersion = XtSpecificationRelease;
482 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
483 jailSquareColor, highlightSquareColor, premoveHighlightColor;
484 Pixel lowTimeWarningColor;
485 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
486 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
487 wjPieceGC, bjPieceGC, prelineGC, countGC;
488 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
489 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
490 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
491 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
492 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
493 ICSInputShell, fileNameShell, askQuestionShell;
494 Widget historyShell, evalGraphShell, gameListShell;
495 int hOffset; // [HGM] dual
496 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
497 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
498 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
499 Font clockFontID, coordFontID, countFontID;
500 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
501 XtAppContext appContext;
503 char *oldICSInteractionTitle;
507 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
509 Position commentX = -1, commentY = -1;
510 Dimension commentW, commentH;
511 typedef unsigned int BoardSize;
513 Boolean chessProgram;
515 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
516 int squareSize, smallLayout = 0, tinyLayout = 0,
517 marginW, marginH, // [HGM] for run-time resizing
518 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
519 ICSInputBoxUp = False, askQuestionUp = False,
520 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
521 errorUp = False, errorExitStatus = -1, lineGap, defaultLineGap;
522 Pixel timerForegroundPixel, timerBackgroundPixel;
523 Pixel buttonForegroundPixel, buttonBackgroundPixel;
524 char *chessDir, *programName, *programVersion,
525 *gameCopyFilename, *gamePasteFilename;
526 Boolean alwaysOnTop = False;
527 Boolean saveSettingsOnExit;
528 char *settingsFileName;
529 char *icsTextMenuString;
531 char *firstChessProgramNames;
532 char *secondChessProgramNames;
534 WindowPlacement wpMain;
535 WindowPlacement wpConsole;
536 WindowPlacement wpComment;
537 WindowPlacement wpMoveHistory;
538 WindowPlacement wpEvalGraph;
539 WindowPlacement wpEngineOutput;
540 WindowPlacement wpGameList;
541 WindowPlacement wpTags;
543 extern Widget shells[];
544 extern Boolean shellUp[];
548 Pixmap pieceBitmap[2][(int)BlackPawn];
549 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
550 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
551 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
552 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
553 Pixmap xpmBoardBitmap[2];
554 int useImages, useImageSqs, useTexture, textureW[2], textureH[2];
555 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
556 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
557 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
558 XImage *ximLightSquare, *ximDarkSquare;
561 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
562 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
564 #define White(piece) ((int)(piece) < (int)BlackPawn)
566 /* Variables for doing smooth animation. This whole thing
567 would be much easier if the board was double-buffered,
568 but that would require a fairly major rewrite. */
573 GC blitGC, pieceGC, outlineGC;
574 XPoint startSquare, prevFrame, mouseDelta;
578 int startBoardX, startBoardY;
581 /* There can be two pieces being animated at once: a player
582 can begin dragging a piece before the remote opponent has moved. */
584 static AnimState game, player;
586 /* Bitmaps for use as masks when drawing XPM pieces.
587 Need one for each black and white piece. */
588 static Pixmap xpmMask[BlackKing + 1];
590 /* This magic number is the number of intermediate frames used
591 in each half of the animation. For short moves it's reduced
592 by 1. The total number of frames will be factor * 2 + 1. */
595 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
597 MenuItem fileMenu[] = {
598 {N_("New Game Ctrl+N"), "New Game", ResetProc},
599 {N_("New Shuffle Game ..."), "New Shuffle Game", ShuffleMenuProc},
600 {N_("New Variant ... Alt+Shift+V"), "New Variant", NewVariantProc}, // [HGM] variant: not functional yet
601 {"----", NULL, NothingProc},
602 {N_("Load Game Ctrl+O"), "Load Game", LoadGameProc},
603 {N_("Load Position Ctrl+Shift+O"), "Load Position", LoadPositionProc},
604 // {N_("Load Next Game"), "Load Next Game", LoadNextGameProc},
605 // {N_("Load Previous Game"), "Load Previous Game", LoadPrevGameProc},
606 // {N_("Reload Same Game"), "Reload Same Game", ReloadGameProc},
607 {N_("Next Position Shift+PgDn"), "Load Next Position", LoadNextPositionProc},
608 {N_("Prev Position Shift+PgUp"), "Load Previous Position", LoadPrevPositionProc},
609 {"----", NULL, NothingProc},
610 // {N_("Reload Same Position"), "Reload Same Position", ReloadPositionProc},
611 {N_("Save Game Ctrl+S"), "Save Game", SaveGameProc},
612 {N_("Save Position Ctrl+Shift+S"), "Save Position", SavePositionProc},
613 {"----", NULL, NothingProc},
614 {N_("Mail Move"), "Mail Move", MailMoveProc},
615 {N_("Reload CMail Message"), "Reload CMail Message", ReloadCmailMsgProc},
616 {"----", NULL, NothingProc},
617 {N_("Quit Ctr+Q"), "Exit", QuitProc},
621 MenuItem editMenu[] = {
622 {N_("Copy Game Ctrl+C"), "Copy Game", CopyGameProc},
623 {N_("Copy Position Ctrl+Shift+C"), "Copy Position", CopyPositionProc},
624 {N_("Copy Game List"), "Copy Game List", CopyGameListProc},
625 {"----", NULL, NothingProc},
626 {N_("Paste Game Ctrl+V"), "Paste Game", PasteGameProc},
627 {N_("Paste Position Ctrl+Shift+V"), "Paste Position", PastePositionProc},
628 {"----", NULL, NothingProc},
629 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
630 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
631 {N_("Edit Tags"), "Edit Tags", EditTagsProc},
632 {N_("Edit Comment"), "Edit Comment", EditCommentProc},
633 {"----", NULL, NothingProc},
634 {N_("Revert Home"), "Revert", RevertProc},
635 {N_("Annotate"), "Annotate", AnnotateProc},
636 {N_("Truncate Game End"), "Truncate Game", TruncateGameProc},
637 {"----", NULL, NothingProc},
638 {N_("Backward Alt+Left"), "Backward", BackwardProc},
639 {N_("Forward Alt+Right"), "Forward", ForwardProc},
640 {N_("Back to Start Alt+Home"), "Back to Start", ToStartProc},
641 {N_("Forward to End Alt+End"), "Forward to End", ToEndProc},
645 MenuItem viewMenu[] = {
646 {N_("Flip View F2"), "Flip View", FlipViewProc},
647 {"----", NULL, NothingProc},
648 {N_("Engine Output Alt+Shift+O"), "Show Engine Output", EngineOutputProc},
649 {N_("Move History Alt+Shift+H"), "Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
650 {N_("Evaluation Graph Alt+Shift+E"), "Show Evaluation Graph", EvalGraphProc},
651 {N_("Game List Alt+Shift+G"), "Show Game List", ShowGameListProc},
652 {N_("ICS text menu"), "ICStex", IcsTextProc},
653 {"----", NULL, NothingProc},
654 {N_("Tags"), "Show Tags", EditTagsProc},
655 {N_("Comments"), "Show Comments", EditCommentProc},
656 {N_("ICS Input Box"), "ICS Input Box", IcsInputBoxProc},
657 {"----", NULL, NothingProc},
658 {N_("Board..."), "Board Options", BoardOptionsProc},
659 {N_("Game List Tags..."), "Game List", GameListOptionsPopUp},
663 MenuItem modeMenu[] = {
664 {N_("Machine White Ctrl+W"), "Machine White", MachineWhiteProc},
665 {N_("Machine Black Ctrl+B"), "Machine Black", MachineBlackProc},
666 {N_("Two Machines Ctrl+T"), "Two Machines", TwoMachinesProc},
667 {N_("Analysis Mode Ctrl+A"), "Analysis Mode", AnalyzeModeProc},
668 {N_("Analyze File Ctrl+F"), "Analyze File", AnalyzeFileProc },
669 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
670 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
671 {N_("Training"), "Training", TrainingProc},
672 {N_("ICS Client"), "ICS Client", IcsClientProc},
673 {"----", NULL, NothingProc},
674 {N_("Machine Match"), "Machine Match", MatchProc},
675 {N_("Pause Pause"), "Pause", PauseProc},
679 MenuItem actionMenu[] = {
680 {N_("Accept F3"), "Accept", AcceptProc},
681 {N_("Decline F4"), "Decline", DeclineProc},
682 {N_("Rematch F12"), "Rematch", RematchProc},
683 {"----", NULL, NothingProc},
684 {N_("Call Flag F5"), "Call Flag", CallFlagProc},
685 {N_("Draw F6"), "Draw", DrawProc},
686 {N_("Adjourn F7"), "Adjourn", AdjournProc},
687 {N_("Abort F8"),"Abort", AbortProc},
688 {N_("Resign F9"), "Resign", ResignProc},
689 {"----", NULL, NothingProc},
690 {N_("Stop Observing F10"), "Stop Observing", StopObservingProc},
691 {N_("Stop Examining F11"), "Stop Examining", StopExaminingProc},
692 {N_("Upload to Examine"), "Upload to Examine", UploadProc},
693 {"----", NULL, NothingProc},
694 {N_("Adjudicate to White"), "Adjudicate to White", AdjuWhiteProc},
695 {N_("Adjudicate to Black"), "Adjudicate to Black", AdjuBlackProc},
696 {N_("Adjudicate Draw"), "Adjudicate Draw", AdjuDrawProc},
700 MenuItem engineMenu[] = {
701 {N_("Engine #1 Settings ..."), "Engine #1 Settings", FirstSettingsProc},
702 {N_("Engine #2 Settings ..."), "Engine #2 Settings", SecondSettingsProc},
703 {"----", NULL, NothingProc},
704 {N_("Hint"), "Hint", HintProc},
705 {N_("Book"), "Book", BookProc},
706 {"----", NULL, NothingProc},
707 {N_("Move Now Ctrl+M"), "Move Now", MoveNowProc},
708 {N_("Retract Move Ctrl+X"), "Retract Move", RetractMoveProc},
712 MenuItem optionsMenu[] = {
713 #define OPTIONSDIALOG
715 {N_("General ..."), "General", OptionsProc},
717 {N_("Time Control ... Alt+Shift+T"), "Time Control", TimeControlProc},
718 {N_("Common Engine ... Alt+Shift+U"), "Common Engine", UciMenuProc},
719 {N_("Adjudications ... Alt+Shift+J"), "Adjudications", EngineMenuProc},
720 {N_("ICS ..."), "ICS", IcsOptionsProc},
721 {N_("Match ..."), "Match", MatchOptionsProc},
722 {N_("Load Game ..."), "Load Game", LoadOptionsProc},
723 {N_("Save Game ..."), "Save Game", SaveOptionsProc},
724 // {N_(" ..."), "", OptionsProc},
725 {N_("Game List ..."), "Game List", GameListOptionsPopUp},
726 {N_("Sounds ..."), "Sounds", SoundOptionsProc},
727 {"----", NULL, NothingProc},
728 #ifndef OPTIONSDIALOG
729 {N_("Always Queen Ctrl+Shift+Q"), "Always Queen", AlwaysQueenProc},
730 {N_("Animate Dragging"), "Animate Dragging", AnimateDraggingProc},
731 {N_("Animate Moving Ctrl+Shift+A"), "Animate Moving", AnimateMovingProc},
732 {N_("Auto Flag Ctrl+Shift+F"), "Auto Flag", AutoflagProc},
733 {N_("Auto Flip View"), "Auto Flip View", AutoflipProc},
734 {N_("Blindfold"), "Blindfold", BlindfoldProc},
735 {N_("Flash Moves"), "Flash Moves", FlashMovesProc},
737 {N_("Highlight Dragging"), "Highlight Dragging", HighlightDraggingProc},
739 {N_("Highlight Last Move"), "Highlight Last Move", HighlightLastMoveProc},
740 {N_("Highlight With Arrow"), "Arrow", HighlightArrowProc},
741 {N_("Move Sound"), "Move Sound", MoveSoundProc},
742 // {N_("ICS Alarm"), "ICS Alarm", IcsAlarmProc},
743 {N_("One-Click Moving"), "OneClick", OneClickProc},
744 {N_("Periodic Updates"), "Periodic Updates", PeriodicUpdatesProc},
745 {N_("Ponder Next Move Ctrl+Shift+P"), "Ponder Next Move", PonderNextMoveProc},
746 {N_("Popup Exit Message"), "Popup Exit Message", PopupExitMessageProc},
747 {N_("Popup Move Errors"), "Popup Move Errors", PopupMoveErrorsProc},
748 // {N_("Premove"), "Premove", PremoveProc},
749 {N_("Show Coords"), "Show Coords", ShowCoordsProc},
750 {N_("Hide Thinking Ctrl+Shift+H"), "Hide Thinking", HideThinkingProc},
751 {N_("Test Legality Ctrl+Shift+L"), "Test Legality", TestLegalityProc},
752 {"----", NULL, NothingProc},
754 {N_("Save Settings Now"), "Save Settings Now", SaveSettingsProc},
755 {N_("Save Settings on Exit"), "Save Settings on Exit", SaveOnExitProc},
759 MenuItem helpMenu[] = {
760 {N_("Info XBoard"), "Info XBoard", InfoProc},
761 {N_("Man XBoard F1"), "Man XBoard", ManProc},
762 {"----", NULL, NothingProc},
763 {N_("About XBoard"), "About XBoard", AboutProc},
768 {N_("File"), "File", fileMenu},
769 {N_("Edit"), "Edit", editMenu},
770 {N_("View"), "View", viewMenu},
771 {N_("Mode"), "Mode", modeMenu},
772 {N_("Action"), "Action", actionMenu},
773 {N_("Engine"), "Engine", engineMenu},
774 {N_("Options"), "Options", optionsMenu},
775 {N_("Help"), "Help", helpMenu},
779 #define PAUSE_BUTTON "P"
780 MenuItem buttonBar[] = {
781 {"<<", "<<", ToStartProc},
782 {"<", "<", BackwardProc},
783 {PAUSE_BUTTON, PAUSE_BUTTON, PauseProc},
784 {">", ">", ForwardProc},
785 {">>", ">>", ToEndProc},
789 #define PIECE_MENU_SIZE 18
790 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
791 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
792 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
793 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
794 N_("Empty square"), N_("Clear board") },
795 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
796 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
797 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
798 N_("Empty square"), N_("Clear board") }
800 /* must be in same order as PieceMenuStrings! */
801 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
802 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
803 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
804 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
805 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
806 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
807 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
808 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
809 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
812 #define DROP_MENU_SIZE 6
813 String dropMenuStrings[DROP_MENU_SIZE] = {
814 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
816 /* must be in same order as PieceMenuStrings! */
817 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
818 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
819 WhiteRook, WhiteQueen
827 DropMenuEnables dmEnables[] = {
845 { XtNborderWidth, 0 },
846 { XtNdefaultDistance, 0 },
850 { XtNborderWidth, 0 },
851 { XtNresizable, (XtArgVal) True },
855 { XtNborderWidth, 0 },
861 { XtNjustify, (XtArgVal) XtJustifyRight },
862 { XtNlabel, (XtArgVal) "..." },
863 { XtNresizable, (XtArgVal) True },
864 { XtNresize, (XtArgVal) False }
867 Arg messageArgs[] = {
868 { XtNjustify, (XtArgVal) XtJustifyLeft },
869 { XtNlabel, (XtArgVal) "..." },
870 { XtNresizable, (XtArgVal) True },
871 { XtNresize, (XtArgVal) False }
875 { XtNborderWidth, 0 },
876 { XtNjustify, (XtArgVal) XtJustifyLeft }
879 XtResource clientResources[] = {
880 { "flashCount", "flashCount", XtRInt, sizeof(int),
881 XtOffset(AppDataPtr, flashCount), XtRImmediate,
882 (XtPointer) FLASH_COUNT },
885 XrmOptionDescRec shellOptions[] = {
886 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
887 { "-flash", "flashCount", XrmoptionNoArg, "3" },
888 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
891 XtActionsRec boardActions[] = {
892 { "DrawPosition", DrawPositionProc },
893 { "HandleUserMove", HandleUserMove },
894 { "AnimateUserMove", AnimateUserMove },
895 { "HandlePV", HandlePV },
896 { "SelectPV", SelectPV },
897 { "StopPV", StopPV },
898 { "FileNameAction", FileNameAction },
899 { "AskQuestionProc", AskQuestionProc },
900 { "AskQuestionReplyAction", AskQuestionReplyAction },
901 { "PieceMenuPopup", PieceMenuPopup },
902 { "WhiteClock", WhiteClock },
903 { "BlackClock", BlackClock },
904 { "Iconify", Iconify },
905 { "ResetProc", ResetProc },
906 { "NewVariantProc", NewVariantProc },
907 { "LoadGameProc", LoadGameProc },
908 { "LoadNextGameProc", LoadNextGameProc },
909 { "LoadPrevGameProc", LoadPrevGameProc },
910 { "LoadSelectedProc", LoadSelectedProc },
911 { "SetFilterProc", SetFilterProc },
912 { "ReloadGameProc", ReloadGameProc },
913 { "LoadPositionProc", LoadPositionProc },
914 { "LoadNextPositionProc", LoadNextPositionProc },
915 { "LoadPrevPositionProc", LoadPrevPositionProc },
916 { "ReloadPositionProc", ReloadPositionProc },
917 { "CopyPositionProc", CopyPositionProc },
918 { "PastePositionProc", PastePositionProc },
919 { "CopyGameProc", CopyGameProc },
920 { "CopyGameListProc", CopyGameListProc },
921 { "PasteGameProc", PasteGameProc },
922 { "SaveGameProc", SaveGameProc },
923 { "SavePositionProc", SavePositionProc },
924 { "MailMoveProc", MailMoveProc },
925 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
926 { "QuitProc", QuitProc },
927 { "MachineWhiteProc", MachineWhiteProc },
928 { "MachineBlackProc", MachineBlackProc },
929 { "AnalysisModeProc", AnalyzeModeProc },
930 { "AnalyzeFileProc", AnalyzeFileProc },
931 { "TwoMachinesProc", TwoMachinesProc },
932 { "IcsClientProc", IcsClientProc },
933 { "EditGameProc", EditGameProc },
934 { "EditPositionProc", EditPositionProc },
935 { "TrainingProc", EditPositionProc },
936 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
937 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
938 { "ShowGameListProc", ShowGameListProc },
939 { "ShowMoveListProc", HistoryShowProc},
940 { "EditTagsProc", EditCommentProc },
941 { "EditCommentProc", EditCommentProc },
942 { "IcsInputBoxProc", IcsInputBoxProc },
943 { "PauseProc", PauseProc },
944 { "AcceptProc", AcceptProc },
945 { "DeclineProc", DeclineProc },
946 { "RematchProc", RematchProc },
947 { "CallFlagProc", CallFlagProc },
948 { "DrawProc", DrawProc },
949 { "AdjournProc", AdjournProc },
950 { "AbortProc", AbortProc },
951 { "ResignProc", ResignProc },
952 { "AdjuWhiteProc", AdjuWhiteProc },
953 { "AdjuBlackProc", AdjuBlackProc },
954 { "AdjuDrawProc", AdjuDrawProc },
955 { "TypeInProc", TypeInProc },
956 { "EnterKeyProc", EnterKeyProc },
957 { "UpKeyProc", UpKeyProc },
958 { "DownKeyProc", DownKeyProc },
959 { "StopObservingProc", StopObservingProc },
960 { "StopExaminingProc", StopExaminingProc },
961 { "UploadProc", UploadProc },
962 { "BackwardProc", BackwardProc },
963 { "ForwardProc", ForwardProc },
964 { "ToStartProc", ToStartProc },
965 { "ToEndProc", ToEndProc },
966 { "RevertProc", RevertProc },
967 { "AnnotateProc", AnnotateProc },
968 { "TruncateGameProc", TruncateGameProc },
969 { "MoveNowProc", MoveNowProc },
970 { "RetractMoveProc", RetractMoveProc },
971 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
972 { "UciMenuProc", (XtActionProc) UciMenuProc },
973 { "TimeControlProc", (XtActionProc) TimeControlProc },
974 { "FlipViewProc", FlipViewProc },
975 { "PonderNextMoveProc", PonderNextMoveProc },
976 #ifndef OPTIONSDIALOG
977 { "AlwaysQueenProc", AlwaysQueenProc },
978 { "AnimateDraggingProc", AnimateDraggingProc },
979 { "AnimateMovingProc", AnimateMovingProc },
980 { "AutoflagProc", AutoflagProc },
981 { "AutoflipProc", AutoflipProc },
982 { "BlindfoldProc", BlindfoldProc },
983 { "FlashMovesProc", FlashMovesProc },
985 { "HighlightDraggingProc", HighlightDraggingProc },
987 { "HighlightLastMoveProc", HighlightLastMoveProc },
988 // { "IcsAlarmProc", IcsAlarmProc },
989 { "MoveSoundProc", MoveSoundProc },
990 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
991 { "PopupExitMessageProc", PopupExitMessageProc },
992 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
993 // { "PremoveProc", PremoveProc },
994 { "ShowCoordsProc", ShowCoordsProc },
995 { "ShowThinkingProc", ShowThinkingProc },
996 { "HideThinkingProc", HideThinkingProc },
997 { "TestLegalityProc", TestLegalityProc },
999 { "SaveSettingsProc", SaveSettingsProc },
1000 { "SaveOnExitProc", SaveOnExitProc },
1001 { "InfoProc", InfoProc },
1002 { "ManProc", ManProc },
1003 { "HintProc", HintProc },
1004 { "BookProc", BookProc },
1005 { "AboutGameProc", AboutGameProc },
1006 { "AboutProc", AboutProc },
1007 { "DebugProc", DebugProc },
1008 { "NothingProc", NothingProc },
1009 { "CommentClick", (XtActionProc) CommentClick },
1010 { "CommentPopDown", (XtActionProc) CommentPopDown },
1011 { "TagsPopDown", (XtActionProc) TagsPopDown },
1012 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
1013 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
1014 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
1015 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
1016 { "GameListPopDown", (XtActionProc) GameListPopDown },
1017 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
1018 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1019 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
1020 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1021 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1022 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
1023 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
1024 { "GenericPopDown", (XtActionProc) GenericPopDown },
1025 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1028 char globalTranslations[] =
1029 ":<Key>F9: ResignProc() \n \
1030 :Ctrl<Key>n: ResetProc() \n \
1031 :Meta<Key>V: NewVariantProc() \n \
1032 :Ctrl<Key>o: LoadGameProc() \n \
1033 :Meta<Key>Next: LoadNextGameProc() \n \
1034 :Meta<Key>Prior: LoadPrevGameProc() \n \
1035 :Ctrl<Key>s: SaveGameProc() \n \
1036 :Ctrl<Key>c: CopyGameProc() \n \
1037 :Ctrl<Key>v: PasteGameProc() \n \
1038 :Ctrl<Key>O: LoadPositionProc() \n \
1039 :Shift<Key>Next: LoadNextPositionProc() \n \
1040 :Shift<Key>Prior: LoadPrevPositionProc() \n \
1041 :Ctrl<Key>S: SavePositionProc() \n \
1042 :Ctrl<Key>C: CopyPositionProc() \n \
1043 :Ctrl<Key>V: PastePositionProc() \n \
1044 :Ctrl<Key>q: QuitProc() \n \
1045 :Ctrl<Key>w: MachineWhiteProc() \n \
1046 :Ctrl<Key>b: MachineBlackProc() \n \
1047 :Ctrl<Key>t: TwoMachinesProc() \n \
1048 :Ctrl<Key>a: AnalysisModeProc() \n \
1049 :Ctrl<Key>f: AnalyzeFileProc() \n \
1050 :Ctrl<Key>e: EditGameProc() \n \
1051 :Ctrl<Key>E: EditPositionProc() \n \
1052 :Meta<Key>O: EngineOutputProc() \n \
1053 :Meta<Key>E: EvalGraphProc() \n \
1054 :Meta<Key>G: ShowGameListProc() \n \
1055 :Meta<Key>H: ShowMoveListProc() \n \
1056 :<Key>Pause: PauseProc() \n \
1057 :<Key>F3: AcceptProc() \n \
1058 :<Key>F4: DeclineProc() \n \
1059 :<Key>F12: RematchProc() \n \
1060 :<Key>F5: CallFlagProc() \n \
1061 :<Key>F6: DrawProc() \n \
1062 :<Key>F7: AdjournProc() \n \
1063 :<Key>F8: AbortProc() \n \
1064 :<Key>F10: StopObservingProc() \n \
1065 :<Key>F11: StopExaminingProc() \n \
1066 :Meta Ctrl<Key>F12: DebugProc() \n \
1067 :Meta<Key>End: ToEndProc() \n \
1068 :Meta<Key>Right: ForwardProc() \n \
1069 :Meta<Key>Home: ToStartProc() \n \
1070 :Meta<Key>Left: BackwardProc() \n \
1071 :<Key>Home: RevertProc() \n \
1072 :<Key>End: TruncateGameProc() \n \
1073 :Ctrl<Key>m: MoveNowProc() \n \
1074 :Ctrl<Key>x: RetractMoveProc() \n \
1075 :Meta<Key>J: EngineMenuProc() \n \
1076 :Meta<Key>U: UciMenuProc() \n \
1077 :Meta<Key>T: TimeControlProc() \n \
1078 :Ctrl<Key>P: PonderNextMoveProc() \n "
1079 #ifndef OPTIONSDIALOG
1081 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1082 :Ctrl<Key>F: AutoflagProc() \n \
1083 :Ctrl<Key>A: AnimateMovingProc() \n \
1084 :Ctrl<Key>L: TestLegalityProc() \n \
1085 :Ctrl<Key>H: HideThinkingProc() \n "
1088 :<Key>-: Iconify() \n \
1089 :<Key>F1: ManProc() \n \
1090 :<Key>F2: FlipViewProc() \n \
1091 <KeyDown>.: BackwardProc() \n \
1092 <KeyUp>.: ForwardProc() \n \
1093 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1094 \"Send to chess program:\",,1) \n \
1095 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1096 \"Send to second chess program:\",,2) \n";
1098 char boardTranslations[] =
1099 "<Btn1Down>: HandleUserMove(0) \n \
1100 Shift<Btn1Up>: HandleUserMove(1) \n \
1101 <Btn1Up>: HandleUserMove(0) \n \
1102 <Btn1Motion>: AnimateUserMove() \n \
1103 <Btn3Motion>: HandlePV() \n \
1104 <Btn3Up>: PieceMenuPopup(menuB) \n \
1105 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1106 PieceMenuPopup(menuB) \n \
1107 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1108 PieceMenuPopup(menuW) \n \
1109 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1110 PieceMenuPopup(menuW) \n \
1111 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1112 PieceMenuPopup(menuB) \n";
1114 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1115 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1117 char ICSInputTranslations[] =
1118 "<Key>Up: UpKeyProc() \n "
1119 "<Key>Down: DownKeyProc() \n "
1120 "<Key>Return: EnterKeyProc() \n";
1122 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1123 // as the widget is destroyed before the up-click can call extend-end
1124 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1126 String xboardResources[] = {
1127 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1128 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1129 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1134 /* Max possible square size */
1135 #define MAXSQSIZE 256
1137 static int xpm_avail[MAXSQSIZE];
1139 #ifdef HAVE_DIR_STRUCT
1141 /* Extract piece size from filename */
1143 xpm_getsize(name, len, ext)
1154 if ((p=strchr(name, '.')) == NULL ||
1155 StrCaseCmp(p+1, ext) != 0)
1161 while (*p && isdigit(*p))
1168 /* Setup xpm_avail */
1170 xpm_getavail(dirname, ext)
1178 for (i=0; i<MAXSQSIZE; ++i)
1181 if (appData.debugMode)
1182 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1184 dir = opendir(dirname);
1187 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1188 programName, dirname);
1192 while ((ent=readdir(dir)) != NULL) {
1193 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1194 if (i > 0 && i < MAXSQSIZE)
1204 xpm_print_avail(fp, ext)
1210 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1211 for (i=1; i<MAXSQSIZE; ++i) {
1217 /* Return XPM piecesize closest to size */
1219 xpm_closest_to(dirname, size, ext)
1225 int sm_diff = MAXSQSIZE;
1229 xpm_getavail(dirname, ext);
1231 if (appData.debugMode)
1232 xpm_print_avail(stderr, ext);
1234 for (i=1; i<MAXSQSIZE; ++i) {
1237 diff = (diff<0) ? -diff : diff;
1238 if (diff < sm_diff) {
1246 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1252 #else /* !HAVE_DIR_STRUCT */
1253 /* If we are on a system without a DIR struct, we can't
1254 read the directory, so we can't collect a list of
1255 filenames, etc., so we can't do any size-fitting. */
1257 xpm_closest_to(dirname, size, ext)
1262 fprintf(stderr, _("\
1263 Warning: No DIR structure found on this system --\n\
1264 Unable to autosize for XPM/XIM pieces.\n\
1265 Please report this error to frankm@hiwaay.net.\n\
1266 Include system type & operating system in message.\n"));
1269 #endif /* HAVE_DIR_STRUCT */
1271 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1272 "magenta", "cyan", "white" };
1276 TextColors textColors[(int)NColorClasses];
1278 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1280 parse_color(str, which)
1284 char *p, buf[100], *d;
1287 if (strlen(str) > 99) /* watch bounds on buf */
1292 for (i=0; i<which; ++i) {
1299 /* Could be looking at something like:
1301 .. in which case we want to stop on a comma also */
1302 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1306 return -1; /* Use default for empty field */
1309 if (which == 2 || isdigit(*p))
1312 while (*p && isalpha(*p))
1317 for (i=0; i<8; ++i) {
1318 if (!StrCaseCmp(buf, cnames[i]))
1319 return which? (i+40) : (i+30);
1321 if (!StrCaseCmp(buf, "default")) return -1;
1323 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1328 parse_cpair(cc, str)
1332 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1333 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1338 /* bg and attr are optional */
1339 textColors[(int)cc].bg = parse_color(str, 1);
1340 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1341 textColors[(int)cc].attr = 0;
1347 /* Arrange to catch delete-window events */
1348 Atom wm_delete_window;
1350 CatchDeleteWindow(Widget w, String procname)
1353 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1354 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1355 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1362 XtSetArg(args[0], XtNiconic, False);
1363 XtSetValues(shellWidget, args, 1);
1365 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1368 //---------------------------------------------------------------------------------------------------------
1369 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1372 #define CW_USEDEFAULT (1<<31)
1373 #define ICS_TEXT_MENU_SIZE 90
1374 #define DEBUG_FILE "xboard.debug"
1375 #define SetCurrentDirectory chdir
1376 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1380 // these two must some day move to frontend.h, when they are implemented
1381 Boolean GameListIsUp();
1383 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1386 // front-end part of option handling
1388 // [HGM] This platform-dependent table provides the location for storing the color info
1389 extern char *crWhite, * crBlack;
1393 &appData.whitePieceColor,
1394 &appData.blackPieceColor,
1395 &appData.lightSquareColor,
1396 &appData.darkSquareColor,
1397 &appData.highlightSquareColor,
1398 &appData.premoveHighlightColor,
1399 &appData.lowTimeWarningColor,
1410 // [HGM] font: keep a font for each square size, even non-stndard ones
1411 #define NUM_SIZES 18
1412 #define MAX_SIZE 130
1413 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1414 char *fontTable[NUM_FONTS][MAX_SIZE];
1417 ParseFont(char *name, int number)
1418 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1420 if(sscanf(name, "size%d:", &size)) {
1421 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1422 // defer processing it until we know if it matches our board size
1423 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1424 fontTable[number][size] = strdup(strchr(name, ':')+1);
1425 fontValid[number][size] = True;
1430 case 0: // CLOCK_FONT
1431 appData.clockFont = strdup(name);
1433 case 1: // MESSAGE_FONT
1434 appData.font = strdup(name);
1436 case 2: // COORD_FONT
1437 appData.coordFont = strdup(name);
1442 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1447 { // only 2 fonts currently
1448 appData.clockFont = CLOCK_FONT_NAME;
1449 appData.coordFont = COORD_FONT_NAME;
1450 appData.font = DEFAULT_FONT_NAME;
1455 { // no-op, until we identify the code for this already in XBoard and move it here
1459 ParseColor(int n, char *name)
1460 { // in XBoard, just copy the color-name string
1461 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1465 ParseTextAttribs(ColorClass cc, char *s)
1467 (&appData.colorShout)[cc] = strdup(s);
1471 ParseBoardSize(void *addr, char *name)
1473 appData.boardSize = strdup(name);
1478 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1482 SetCommPortDefaults()
1483 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1486 // [HGM] args: these three cases taken out to stay in front-end
1488 SaveFontArg(FILE *f, ArgDescriptor *ad)
1491 int i, n = (int)(intptr_t)ad->argLoc;
1493 case 0: // CLOCK_FONT
1494 name = appData.clockFont;
1496 case 1: // MESSAGE_FONT
1497 name = appData.font;
1499 case 2: // COORD_FONT
1500 name = appData.coordFont;
1505 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1506 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1507 fontTable[n][squareSize] = strdup(name);
1508 fontValid[n][squareSize] = True;
1511 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1512 fprintf(f, OPTCHAR "%s" SEPCHAR "\"size%d:%s\"\n", ad->argName, i, fontTable[n][i]);
1517 { // nothing to do, as the sounds are at all times represented by their text-string names already
1521 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1522 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1523 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
1527 SaveColor(FILE *f, ArgDescriptor *ad)
1528 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1529 if(colorVariable[(int)(intptr_t)ad->argLoc])
1530 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
1534 SaveBoardSize(FILE *f, char *name, void *addr)
1535 { // wrapper to shield back-end from BoardSize & sizeInfo
1536 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1540 ParseCommPortSettings(char *s)
1541 { // no such option in XBoard (yet)
1544 extern Widget engineOutputShell;
1547 GetActualPlacement(Widget wg, WindowPlacement *wp)
1557 XtSetArg(args[i], XtNx, &x); i++;
1558 XtSetArg(args[i], XtNy, &y); i++;
1559 XtSetArg(args[i], XtNwidth, &w); i++;
1560 XtSetArg(args[i], XtNheight, &h); i++;
1561 XtGetValues(wg, args, i);
1570 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1571 // In XBoard this will have to wait until awareness of window parameters is implemented
1572 GetActualPlacement(shellWidget, &wpMain);
1573 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1574 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1575 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1576 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1577 if(shellUp[1]) GetActualPlacement(shells[1], &wpComment);
1578 if(shellUp[2]) GetActualPlacement(shells[2], &wpTags);
1582 PrintCommPortSettings(FILE *f, char *name)
1583 { // This option does not exist in XBoard
1587 MySearchPath(char *installDir, char *name, char *fullname)
1588 { // just append installDir and name. Perhaps ExpandPath should be used here?
1589 name = ExpandPathName(name);
1590 if(name && name[0] == '/')
1591 safeStrCpy(fullname, name, MSG_SIZ );
1593 sprintf(fullname, "%s%c%s", installDir, '/', name);
1599 MyGetFullPathName(char *name, char *fullname)
1600 { // should use ExpandPath?
1601 name = ExpandPathName(name);
1602 safeStrCpy(fullname, name, MSG_SIZ );
1607 EnsureOnScreen(int *x, int *y, int minX, int minY)
1614 { // [HGM] args: allows testing if main window is realized from back-end
1615 return xBoardWindow != 0;
1619 PopUpStartupDialog()
1620 { // start menu not implemented in XBoard
1624 ConvertToLine(int argc, char **argv)
1626 static char line[128*1024], buf[1024];
1630 for(i=1; i<argc; i++)
1632 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1633 && argv[i][0] != '{' )
1634 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1636 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1637 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1640 line[strlen(line)-1] = NULLCHAR;
1644 //--------------------------------------------------------------------------------------------
1646 extern Boolean twoBoards, partnerUp;
1649 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1651 #define BoardSize int
1652 void InitDrawingSizes(BoardSize boardSize, int flags)
1653 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1654 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1656 XtGeometryResult gres;
1659 if(!formWidget) return;
1662 * Enable shell resizing.
1664 shellArgs[0].value = (XtArgVal) &w;
1665 shellArgs[1].value = (XtArgVal) &h;
1666 XtGetValues(shellWidget, shellArgs, 2);
1668 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1669 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1670 XtSetValues(shellWidget, &shellArgs[2], 4);
1672 XtSetArg(args[0], XtNdefaultDistance, &sep);
1673 XtGetValues(formWidget, args, 1);
1675 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1676 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1677 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1679 hOffset = boardWidth + 10;
1680 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1681 secondSegments[i] = gridSegments[i];
1682 secondSegments[i].x1 += hOffset;
1683 secondSegments[i].x2 += hOffset;
1686 XtSetArg(args[0], XtNwidth, boardWidth);
1687 XtSetArg(args[1], XtNheight, boardHeight);
1688 XtSetValues(boardWidget, args, 2);
1690 timerWidth = (boardWidth - sep) / 2;
1691 XtSetArg(args[0], XtNwidth, timerWidth);
1692 XtSetValues(whiteTimerWidget, args, 1);
1693 XtSetValues(blackTimerWidget, args, 1);
1695 XawFormDoLayout(formWidget, False);
1697 if (appData.titleInWindow) {
1699 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1700 XtSetArg(args[i], XtNheight, &h); i++;
1701 XtGetValues(titleWidget, args, i);
1703 w = boardWidth - 2*bor;
1705 XtSetArg(args[0], XtNwidth, &w);
1706 XtGetValues(menuBarWidget, args, 1);
1707 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1710 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1711 if (gres != XtGeometryYes && appData.debugMode) {
1713 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1714 programName, gres, w, h, wr, hr);
1718 XawFormDoLayout(formWidget, True);
1721 * Inhibit shell resizing.
1723 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1724 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1725 shellArgs[4].value = shellArgs[2].value = w;
1726 shellArgs[5].value = shellArgs[3].value = h;
1727 XtSetValues(shellWidget, &shellArgs[0], 6);
1729 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1732 for(i=0; i<4; i++) {
1734 for(p=0; p<=(int)WhiteKing; p++)
1735 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1736 if(gameInfo.variant == VariantShogi) {
1737 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1738 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1739 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1740 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1741 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1744 if(gameInfo.variant == VariantGothic) {
1745 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1748 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1749 xpmPieceBitmap[i][(int)WhiteAngel] = xpmPieceBitmap2[i][(int)WhiteFalcon];
1750 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1753 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1754 for(p=0; p<=(int)WhiteKing; p++)
1755 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1756 if(gameInfo.variant == VariantShogi) {
1757 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1758 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1759 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1760 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1761 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1764 if(gameInfo.variant == VariantGothic) {
1765 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1768 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1769 ximMaskPm[(int)WhiteAngel] = ximMaskPm2[(int)WhiteFalcon];
1770 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1775 for(i=0; i<2; i++) {
1777 for(p=0; p<=(int)WhiteKing; p++)
1778 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1779 if(gameInfo.variant == VariantShogi) {
1780 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1781 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1782 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1783 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1784 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1787 if(gameInfo.variant == VariantGothic) {
1788 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1791 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1792 pieceBitmap[i][(int)WhiteAngel] = pieceBitmap2[i][(int)WhiteFalcon];
1793 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1803 void ParseIcsTextColors()
1804 { // [HGM] tken out of main(), so it can be called from ICS-Options dialog
1805 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1806 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1807 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1808 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1809 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1810 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1811 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1812 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1813 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1814 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1816 if (appData.colorize) {
1818 _("%s: can't parse color names; disabling colorization\n"),
1821 appData.colorize = FALSE;
1826 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
1827 XrmValue vFrom, vTo;
1828 int forceMono = False;
1830 if (!appData.monoMode) {
1831 vFrom.addr = (caddr_t) appData.lightSquareColor;
1832 vFrom.size = strlen(appData.lightSquareColor);
1833 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1834 if (vTo.addr == NULL) {
1835 appData.monoMode = True;
1838 lightSquareColor = *(Pixel *) vTo.addr;
1841 if (!appData.monoMode) {
1842 vFrom.addr = (caddr_t) appData.darkSquareColor;
1843 vFrom.size = strlen(appData.darkSquareColor);
1844 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1845 if (vTo.addr == NULL) {
1846 appData.monoMode = True;
1849 darkSquareColor = *(Pixel *) vTo.addr;
1852 if (!appData.monoMode) {
1853 vFrom.addr = (caddr_t) appData.whitePieceColor;
1854 vFrom.size = strlen(appData.whitePieceColor);
1855 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1856 if (vTo.addr == NULL) {
1857 appData.monoMode = True;
1860 whitePieceColor = *(Pixel *) vTo.addr;
1863 if (!appData.monoMode) {
1864 vFrom.addr = (caddr_t) appData.blackPieceColor;
1865 vFrom.size = strlen(appData.blackPieceColor);
1866 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1867 if (vTo.addr == NULL) {
1868 appData.monoMode = True;
1871 blackPieceColor = *(Pixel *) vTo.addr;
1875 if (!appData.monoMode) {
1876 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1877 vFrom.size = strlen(appData.highlightSquareColor);
1878 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1879 if (vTo.addr == NULL) {
1880 appData.monoMode = True;
1883 highlightSquareColor = *(Pixel *) vTo.addr;
1887 if (!appData.monoMode) {
1888 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1889 vFrom.size = strlen(appData.premoveHighlightColor);
1890 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1891 if (vTo.addr == NULL) {
1892 appData.monoMode = True;
1895 premoveHighlightColor = *(Pixel *) vTo.addr;
1906 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1907 XSetWindowAttributes window_attributes;
1909 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1910 XrmValue vFrom, vTo;
1911 XtGeometryResult gres;
1914 int forceMono = False;
1916 srandom(time(0)); // [HGM] book: make random truly random
1918 setbuf(stdout, NULL);
1919 setbuf(stderr, NULL);
1922 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1923 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1927 programName = strrchr(argv[0], '/');
1928 if (programName == NULL)
1929 programName = argv[0];
1934 XtSetLanguageProc(NULL, NULL, NULL);
1935 bindtextdomain(PACKAGE, LOCALEDIR);
1936 textdomain(PACKAGE);
1940 XtAppInitialize(&appContext, "XBoard", shellOptions,
1941 XtNumber(shellOptions),
1942 &argc, argv, xboardResources, NULL, 0);
1943 appData.boardSize = "";
1944 InitAppData(ConvertToLine(argc, argv));
1946 if (p == NULL) p = "/tmp";
1947 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1948 gameCopyFilename = (char*) malloc(i);
1949 gamePasteFilename = (char*) malloc(i);
1950 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1951 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1953 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1954 clientResources, XtNumber(clientResources),
1957 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1958 static char buf[MSG_SIZ];
1959 EscapeExpand(buf, appData.initString);
1960 appData.initString = strdup(buf);
1961 EscapeExpand(buf, appData.secondInitString);
1962 appData.secondInitString = strdup(buf);
1963 EscapeExpand(buf, appData.firstComputerString);
1964 appData.firstComputerString = strdup(buf);
1965 EscapeExpand(buf, appData.secondComputerString);
1966 appData.secondComputerString = strdup(buf);
1969 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1972 if (chdir(chessDir) != 0) {
1973 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1979 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1980 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1981 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1982 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1985 setbuf(debugFP, NULL);
1988 /* [HGM,HR] make sure board size is acceptable */
1989 if(appData.NrFiles > BOARD_FILES ||
1990 appData.NrRanks > BOARD_RANKS )
1991 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1994 /* This feature does not work; animation needs a rewrite */
1995 appData.highlightDragging = FALSE;
1999 xDisplay = XtDisplay(shellWidget);
2000 xScreen = DefaultScreen(xDisplay);
2001 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
2003 gameInfo.variant = StringToVariant(appData.variant);
2004 InitPosition(FALSE);
2007 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
2009 if (isdigit(appData.boardSize[0])) {
2010 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
2011 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
2012 &fontPxlSize, &smallLayout, &tinyLayout);
2014 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
2015 programName, appData.boardSize);
2019 /* Find some defaults; use the nearest known size */
2020 SizeDefaults *szd, *nearest;
2021 int distance = 99999;
2022 nearest = szd = sizeDefaults;
2023 while (szd->name != NULL) {
2024 if (abs(szd->squareSize - squareSize) < distance) {
2026 distance = abs(szd->squareSize - squareSize);
2027 if (distance == 0) break;
2031 if (i < 2) lineGap = nearest->lineGap;
2032 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
2033 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
2034 if (i < 5) fontPxlSize = nearest->fontPxlSize;
2035 if (i < 6) smallLayout = nearest->smallLayout;
2036 if (i < 7) tinyLayout = nearest->tinyLayout;
2039 SizeDefaults *szd = sizeDefaults;
2040 if (*appData.boardSize == NULLCHAR) {
2041 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
2042 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
2045 if (szd->name == NULL) szd--;
2046 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
2048 while (szd->name != NULL &&
2049 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
2050 if (szd->name == NULL) {
2051 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
2052 programName, appData.boardSize);
2056 squareSize = szd->squareSize;
2057 lineGap = szd->lineGap;
2058 clockFontPxlSize = szd->clockFontPxlSize;
2059 coordFontPxlSize = szd->coordFontPxlSize;
2060 fontPxlSize = szd->fontPxlSize;
2061 smallLayout = szd->smallLayout;
2062 tinyLayout = szd->tinyLayout;
2063 // [HGM] font: use defaults from settings file if available and not overruled
2065 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
2066 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
2067 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
2068 appData.font = fontTable[MESSAGE_FONT][squareSize];
2069 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
2070 appData.coordFont = fontTable[COORD_FONT][squareSize];
2072 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
2073 if (strlen(appData.pixmapDirectory) > 0) {
2074 p = ExpandPathName(appData.pixmapDirectory);
2076 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
2077 appData.pixmapDirectory);
2080 if (appData.debugMode) {
2081 fprintf(stderr, _("\
2082 XBoard square size (hint): %d\n\
2083 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
2085 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
2086 if (appData.debugMode) {
2087 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
2090 defaultLineGap = lineGap;
2091 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
2093 /* [HR] height treated separately (hacked) */
2094 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
2095 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
2096 if (appData.showJail == 1) {
2097 /* Jail on top and bottom */
2098 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2099 XtSetArg(boardArgs[2], XtNheight,
2100 boardHeight + 2*(lineGap + squareSize));
2101 } else if (appData.showJail == 2) {
2103 XtSetArg(boardArgs[1], XtNwidth,
2104 boardWidth + 2*(lineGap + squareSize));
2105 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2108 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2109 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2113 * Determine what fonts to use.
2115 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2116 clockFontID = XLoadFont(xDisplay, appData.clockFont);
2117 clockFontStruct = XQueryFont(xDisplay, clockFontID);
2118 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2119 coordFontID = XLoadFont(xDisplay, appData.coordFont);
2120 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2121 appData.font = FindFont(appData.font, fontPxlSize);
2122 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
2123 countFontStruct = XQueryFont(xDisplay, countFontID);
2124 // appData.font = FindFont(appData.font, fontPxlSize);
2126 xdb = XtDatabase(xDisplay);
2127 XrmPutStringResource(&xdb, "*font", appData.font);
2130 * Detect if there are not enough colors available and adapt.
2132 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2133 appData.monoMode = True;
2136 forceMono = MakeColors();
2139 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2142 if (appData.bitmapDirectory == NULL ||
2143 appData.bitmapDirectory[0] == NULLCHAR)
2144 appData.bitmapDirectory = DEF_BITMAP_DIR;
2147 if (appData.lowTimeWarning && !appData.monoMode) {
2148 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2149 vFrom.size = strlen(appData.lowTimeWarningColor);
2150 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2151 if (vTo.addr == NULL)
2152 appData.monoMode = True;
2154 lowTimeWarningColor = *(Pixel *) vTo.addr;
2157 if (appData.monoMode && appData.debugMode) {
2158 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2159 (unsigned long) XWhitePixel(xDisplay, xScreen),
2160 (unsigned long) XBlackPixel(xDisplay, xScreen));
2163 ParseIcsTextColors();
2164 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2165 textColors[ColorNone].attr = 0;
2167 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2173 layoutName = "tinyLayout";
2174 } else if (smallLayout) {
2175 layoutName = "smallLayout";
2177 layoutName = "normalLayout";
2179 /* Outer layoutWidget is there only to provide a name for use in
2180 resources that depend on the layout style */
2182 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2183 layoutArgs, XtNumber(layoutArgs));
2185 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2186 formArgs, XtNumber(formArgs));
2187 XtSetArg(args[0], XtNdefaultDistance, &sep);
2188 XtGetValues(formWidget, args, 1);
2191 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2192 XtSetArg(args[0], XtNtop, XtChainTop);
2193 XtSetArg(args[1], XtNbottom, XtChainTop);
2194 XtSetArg(args[2], XtNright, XtChainLeft);
2195 XtSetValues(menuBarWidget, args, 3);
2197 widgetList[j++] = whiteTimerWidget =
2198 XtCreateWidget("whiteTime", labelWidgetClass,
2199 formWidget, timerArgs, XtNumber(timerArgs));
2200 XtSetArg(args[0], XtNfont, clockFontStruct);
2201 XtSetArg(args[1], XtNtop, XtChainTop);
2202 XtSetArg(args[2], XtNbottom, XtChainTop);
2203 XtSetValues(whiteTimerWidget, args, 3);
2205 widgetList[j++] = blackTimerWidget =
2206 XtCreateWidget("blackTime", labelWidgetClass,
2207 formWidget, timerArgs, XtNumber(timerArgs));
2208 XtSetArg(args[0], XtNfont, clockFontStruct);
2209 XtSetArg(args[1], XtNtop, XtChainTop);
2210 XtSetArg(args[2], XtNbottom, XtChainTop);
2211 XtSetValues(blackTimerWidget, args, 3);
2213 if (appData.titleInWindow) {
2214 widgetList[j++] = titleWidget =
2215 XtCreateWidget("title", labelWidgetClass, formWidget,
2216 titleArgs, XtNumber(titleArgs));
2217 XtSetArg(args[0], XtNtop, XtChainTop);
2218 XtSetArg(args[1], XtNbottom, XtChainTop);
2219 XtSetValues(titleWidget, args, 2);
2222 if (appData.showButtonBar) {
2223 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2224 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2225 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2226 XtSetArg(args[2], XtNtop, XtChainTop);
2227 XtSetArg(args[3], XtNbottom, XtChainTop);
2228 XtSetValues(buttonBarWidget, args, 4);
2231 widgetList[j++] = messageWidget =
2232 XtCreateWidget("message", labelWidgetClass, formWidget,
2233 messageArgs, XtNumber(messageArgs));
2234 XtSetArg(args[0], XtNtop, XtChainTop);
2235 XtSetArg(args[1], XtNbottom, XtChainTop);
2236 XtSetValues(messageWidget, args, 2);
2238 widgetList[j++] = boardWidget =
2239 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2240 XtNumber(boardArgs));
2242 XtManageChildren(widgetList, j);
2244 timerWidth = (boardWidth - sep) / 2;
2245 XtSetArg(args[0], XtNwidth, timerWidth);
2246 XtSetValues(whiteTimerWidget, args, 1);
2247 XtSetValues(blackTimerWidget, args, 1);
2249 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2250 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2251 XtGetValues(whiteTimerWidget, args, 2);
2253 if (appData.showButtonBar) {
2254 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2255 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2256 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2260 * formWidget uses these constraints but they are stored
2264 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2265 XtSetValues(menuBarWidget, args, i);
2266 if (appData.titleInWindow) {
2269 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2270 XtSetValues(whiteTimerWidget, args, i);
2272 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2273 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2274 XtSetValues(blackTimerWidget, args, i);
2276 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2277 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2278 XtSetValues(titleWidget, args, i);
2280 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2281 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2282 XtSetValues(messageWidget, args, i);
2283 if (appData.showButtonBar) {
2285 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2286 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2287 XtSetValues(buttonBarWidget, args, i);
2291 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2292 XtSetValues(whiteTimerWidget, args, i);
2294 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2295 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2296 XtSetValues(blackTimerWidget, args, i);
2298 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2299 XtSetValues(titleWidget, args, i);
2301 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2302 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2303 XtSetValues(messageWidget, args, i);
2304 if (appData.showButtonBar) {
2306 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2307 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2308 XtSetValues(buttonBarWidget, args, i);
2313 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2314 XtSetValues(whiteTimerWidget, args, i);
2316 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2317 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2318 XtSetValues(blackTimerWidget, args, i);
2320 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2321 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2322 XtSetValues(messageWidget, args, i);
2323 if (appData.showButtonBar) {
2325 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2326 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2327 XtSetValues(buttonBarWidget, args, i);
2331 XtSetArg(args[0], XtNfromVert, messageWidget);
2332 XtSetArg(args[1], XtNtop, XtChainTop);
2333 XtSetArg(args[2], XtNbottom, XtChainBottom);
2334 XtSetArg(args[3], XtNleft, XtChainLeft);
2335 XtSetArg(args[4], XtNright, XtChainRight);
2336 XtSetValues(boardWidget, args, 5);
2338 XtRealizeWidget(shellWidget);
2341 XtSetArg(args[0], XtNx, wpMain.x);
2342 XtSetArg(args[1], XtNy, wpMain.y);
2343 XtSetValues(shellWidget, args, 2);
2347 * Correct the width of the message and title widgets.
2348 * It is not known why some systems need the extra fudge term.
2349 * The value "2" is probably larger than needed.
2351 XawFormDoLayout(formWidget, False);
2353 #define WIDTH_FUDGE 2
2355 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2356 XtSetArg(args[i], XtNheight, &h); i++;
2357 XtGetValues(messageWidget, args, i);
2358 if (appData.showButtonBar) {
2360 XtSetArg(args[i], XtNwidth, &w); i++;
2361 XtGetValues(buttonBarWidget, args, i);
2362 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2364 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2367 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2368 if (gres != XtGeometryYes && appData.debugMode) {
2369 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2370 programName, gres, w, h, wr, hr);
2373 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2374 /* The size used for the child widget in layout lags one resize behind
2375 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2377 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2378 if (gres != XtGeometryYes && appData.debugMode) {
2379 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2380 programName, gres, w, h, wr, hr);
2383 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2384 XtSetArg(args[1], XtNright, XtChainRight);
2385 XtSetValues(messageWidget, args, 2);
2387 if (appData.titleInWindow) {
2389 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2390 XtSetArg(args[i], XtNheight, &h); i++;
2391 XtGetValues(titleWidget, args, i);
2393 w = boardWidth - 2*bor;
2395 XtSetArg(args[0], XtNwidth, &w);
2396 XtGetValues(menuBarWidget, args, 1);
2397 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2400 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2401 if (gres != XtGeometryYes && appData.debugMode) {
2403 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2404 programName, gres, w, h, wr, hr);
2407 XawFormDoLayout(formWidget, True);
2409 xBoardWindow = XtWindow(boardWidget);
2411 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2412 // not need to go into InitDrawingSizes().
2416 * Create X checkmark bitmap and initialize option menu checks.
2418 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2419 checkmark_bits, checkmark_width, checkmark_height);
2420 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2421 #ifndef OPTIONSDIALOG
2422 if (appData.alwaysPromoteToQueen) {
2423 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2426 if (appData.animateDragging) {
2427 XtSetValues(XtNameToWidget(menuBarWidget,
2428 "menuOptions.Animate Dragging"),
2431 if (appData.animate) {
2432 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2435 if (appData.autoCallFlag) {
2436 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2439 if (appData.autoFlipView) {
2440 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2443 if (appData.blindfold) {
2444 XtSetValues(XtNameToWidget(menuBarWidget,
2445 "menuOptions.Blindfold"), args, 1);
2447 if (appData.flashCount > 0) {
2448 XtSetValues(XtNameToWidget(menuBarWidget,
2449 "menuOptions.Flash Moves"),
2453 if (appData.highlightDragging) {
2454 XtSetValues(XtNameToWidget(menuBarWidget,
2455 "menuOptions.Highlight Dragging"),
2459 if (appData.highlightLastMove) {
2460 XtSetValues(XtNameToWidget(menuBarWidget,
2461 "menuOptions.Highlight Last Move"),
2464 if (appData.highlightMoveWithArrow) {
2465 XtSetValues(XtNameToWidget(menuBarWidget,
2466 "menuOptions.Arrow"),
2469 // if (appData.icsAlarm) {
2470 // XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2473 if (appData.ringBellAfterMoves) {
2474 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2477 if (appData.oneClick) {
2478 XtSetValues(XtNameToWidget(menuBarWidget,
2479 "menuOptions.OneClick"), args, 1);
2481 if (appData.periodicUpdates) {
2482 XtSetValues(XtNameToWidget(menuBarWidget,
2483 "menuOptions.Periodic Updates"), args, 1);
2485 if (appData.ponderNextMove) {
2486 XtSetValues(XtNameToWidget(menuBarWidget,
2487 "menuOptions.Ponder Next Move"), args, 1);
2489 if (appData.popupExitMessage) {
2490 XtSetValues(XtNameToWidget(menuBarWidget,
2491 "menuOptions.Popup Exit Message"), args, 1);
2493 if (appData.popupMoveErrors) {
2494 XtSetValues(XtNameToWidget(menuBarWidget,
2495 "menuOptions.Popup Move Errors"), args, 1);
2497 // if (appData.premove) {
2498 // XtSetValues(XtNameToWidget(menuBarWidget,
2499 // "menuOptions.Premove"), args, 1);
2501 if (appData.showCoords) {
2502 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2505 if (appData.hideThinkingFromHuman) {
2506 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2509 if (appData.testLegality) {
2510 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2514 if (saveSettingsOnExit) {
2515 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2522 ReadBitmap(&wIconPixmap, "icon_white.bm",
2523 icon_white_bits, icon_white_width, icon_white_height);
2524 ReadBitmap(&bIconPixmap, "icon_black.bm",
2525 icon_black_bits, icon_black_width, icon_black_height);
2526 iconPixmap = wIconPixmap;
2528 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2529 XtSetValues(shellWidget, args, i);
2532 * Create a cursor for the board widget.
2534 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2535 XChangeWindowAttributes(xDisplay, xBoardWindow,
2536 CWCursor, &window_attributes);
2539 * Inhibit shell resizing.
2541 shellArgs[0].value = (XtArgVal) &w;
2542 shellArgs[1].value = (XtArgVal) &h;
2543 XtGetValues(shellWidget, shellArgs, 2);
2544 shellArgs[4].value = shellArgs[2].value = w;
2545 shellArgs[5].value = shellArgs[3].value = h;
2546 XtSetValues(shellWidget, &shellArgs[2], 4);
2547 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2548 marginH = h - boardHeight;
2550 CatchDeleteWindow(shellWidget, "QuitProc");
2555 if (appData.bitmapDirectory[0] != NULLCHAR) {
2559 CreateXPMBoard(appData.liteBackTextureFile, 1);
2560 CreateXPMBoard(appData.darkBackTextureFile, 0);
2564 /* Create regular pieces */
2565 if (!useImages) CreatePieces();
2570 if (appData.animate || appData.animateDragging)
2573 XtAugmentTranslations(formWidget,
2574 XtParseTranslationTable(globalTranslations));
2575 XtAugmentTranslations(boardWidget,
2576 XtParseTranslationTable(boardTranslations));
2577 XtAugmentTranslations(whiteTimerWidget,
2578 XtParseTranslationTable(whiteTranslations));
2579 XtAugmentTranslations(blackTimerWidget,
2580 XtParseTranslationTable(blackTranslations));
2582 /* Why is the following needed on some versions of X instead
2583 * of a translation? */
2584 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2585 (XtEventHandler) EventProc, NULL);
2587 XtAddEventHandler(formWidget, KeyPressMask, False,
2588 (XtEventHandler) MoveTypeInProc, NULL);
2590 /* [AS] Restore layout */
2591 if( wpMoveHistory.visible ) {
2595 if( wpEvalGraph.visible )
2600 if( wpEngineOutput.visible ) {
2601 EngineOutputPopUp();
2606 if (errorExitStatus == -1) {
2607 if (appData.icsActive) {
2608 /* We now wait until we see "login:" from the ICS before
2609 sending the logon script (problems with timestamp otherwise) */
2610 /*ICSInitScript();*/
2611 if (appData.icsInputBox) ICSInputBoxPopUp();
2615 signal(SIGWINCH, TermSizeSigHandler);
2617 signal(SIGINT, IntSigHandler);
2618 signal(SIGTERM, IntSigHandler);
2619 if (*appData.cmailGameName != NULLCHAR) {
2620 signal(SIGUSR1, CmailSigHandler);
2623 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2625 XtSetKeyboardFocus(shellWidget, formWidget);
2627 XtAppMainLoop(appContext);
2628 if (appData.debugMode) fclose(debugFP); // [DM] debug
2635 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2636 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2638 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2639 unlink(gameCopyFilename);
2640 unlink(gamePasteFilename);
2643 RETSIGTYPE TermSizeSigHandler(int sig)
2656 CmailSigHandler(sig)
2662 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2664 /* Activate call-back function CmailSigHandlerCallBack() */
2665 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2667 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2671 CmailSigHandlerCallBack(isr, closure, message, count, error)
2679 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2681 /**** end signal code ****/
2687 /* try to open the icsLogon script, either in the location given
2688 * or in the users HOME directory
2695 f = fopen(appData.icsLogon, "r");
2698 homedir = getenv("HOME");
2699 if (homedir != NULL)
2701 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2702 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2703 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2704 f = fopen(buf, "r");
2709 ProcessICSInitScript(f);
2711 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2734 if (!menuBarWidget) return;
2735 w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2737 DisplayError("menuEdit.Revert", 0);
2739 XtSetSensitive(w, !grey);
2741 w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2743 DisplayError("menuEdit.Annotate", 0);
2745 XtSetSensitive(w, !grey);
2750 SetMenuEnables(enab)
2754 if (!menuBarWidget) return;
2755 while (enab->name != NULL) {
2756 w = XtNameToWidget(menuBarWidget, enab->name);
2758 DisplayError(enab->name, 0);
2760 XtSetSensitive(w, enab->value);
2766 Enables icsEnables[] = {
2767 { "menuFile.Mail Move", False },
2768 { "menuFile.Reload CMail Message", False },
2769 { "menuMode.Machine Black", False },
2770 { "menuMode.Machine White", False },
2771 { "menuMode.Analysis Mode", False },
2772 { "menuMode.Analyze File", False },
2773 { "menuMode.Two Machines", False },
2774 { "menuMode.Machine Match", False },
2776 { "menuEngine.Hint", False },
2777 { "menuEngine.Book", False },
2778 { "menuEngine.Move Now", False },
2779 #ifndef OPTIONSDIALOG
2780 { "menuOptions.Periodic Updates", False },
2781 { "menuOptions.Hide Thinking", False },
2782 { "menuOptions.Ponder Next Move", False },
2784 { "menuEngine.Engine #1 Settings", False },
2786 { "menuEngine.Engine #2 Settings", False },
2787 { "menuEdit.Annotate", False },
2791 Enables ncpEnables[] = {
2792 { "menuFile.Mail Move", False },
2793 { "menuFile.Reload CMail Message", False },
2794 { "menuMode.Machine White", False },
2795 { "menuMode.Machine Black", False },
2796 { "menuMode.Analysis Mode", False },
2797 { "menuMode.Analyze File", False },
2798 { "menuMode.Two Machines", False },
2799 { "menuMode.Machine Match", False },
2800 { "menuMode.ICS Client", False },
2801 { "menuView.ICStex", False },
2802 { "menuView.ICS Input Box", False },
2803 { "Action", False },
2804 { "menuEdit.Revert", False },
2805 { "menuEdit.Annotate", False },
2806 { "menuEngine.Engine #1 Settings", False },
2807 { "menuEngine.Engine #2 Settings", False },
2808 { "menuEngine.Move Now", False },
2809 { "menuEngine.Retract Move", False },
2810 { "menuOptions.ICS", False },
2811 #ifndef OPTIONSDIALOG
2812 { "menuOptions.Auto Flag", False },
2813 { "menuOptions.Auto Flip View", False },
2814 // { "menuOptions.ICS Alarm", False },
2815 { "menuOptions.Move Sound", False },
2816 { "menuOptions.Hide Thinking", False },
2817 { "menuOptions.Periodic Updates", False },
2818 { "menuOptions.Ponder Next Move", False },
2820 { "menuEngine.Hint", False },
2821 { "menuEngine.Book", False },
2825 Enables gnuEnables[] = {
2826 { "menuMode.ICS Client", False },
2827 { "menuView.ICStex", False },
2828 { "menuView.ICS Input Box", False },
2829 { "menuAction.Accept", False },
2830 { "menuAction.Decline", False },
2831 { "menuAction.Rematch", False },
2832 { "menuAction.Adjourn", False },
2833 { "menuAction.Stop Examining", False },
2834 { "menuAction.Stop Observing", False },
2835 { "menuAction.Upload to Examine", False },
2836 { "menuEdit.Revert", False },
2837 { "menuEdit.Annotate", False },
2838 { "menuOptions.ICS", False },
2840 /* The next two options rely on SetCmailMode being called *after* */
2841 /* SetGNUMode so that when GNU is being used to give hints these */
2842 /* menu options are still available */
2844 { "menuFile.Mail Move", False },
2845 { "menuFile.Reload CMail Message", False },
2849 Enables cmailEnables[] = {
2851 { "menuAction.Call Flag", False },
2852 { "menuAction.Draw", True },
2853 { "menuAction.Adjourn", False },
2854 { "menuAction.Abort", False },
2855 { "menuAction.Stop Observing", False },
2856 { "menuAction.Stop Examining", False },
2857 { "menuFile.Mail Move", True },
2858 { "menuFile.Reload CMail Message", True },
2862 Enables trainingOnEnables[] = {
2863 { "menuMode.Edit Comment", False },
2864 { "menuMode.Pause", False },
2865 { "menuEdit.Forward", False },
2866 { "menuEdit.Backward", False },
2867 { "menuEdit.Forward to End", False },
2868 { "menuEdit.Back to Start", False },
2869 { "menuEngine.Move Now", False },
2870 { "menuEdit.Truncate Game", False },
2874 Enables trainingOffEnables[] = {
2875 { "menuMode.Edit Comment", True },
2876 { "menuMode.Pause", True },
2877 { "menuEdit.Forward", True },
2878 { "menuEdit.Backward", True },
2879 { "menuEdit.Forward to End", True },
2880 { "menuEdit.Back to Start", True },
2881 { "menuEngine.Move Now", True },
2882 { "menuEdit.Truncate Game", True },
2886 Enables machineThinkingEnables[] = {
2887 { "menuFile.Load Game", False },
2888 // { "menuFile.Load Next Game", False },
2889 // { "menuFile.Load Previous Game", False },
2890 // { "menuFile.Reload Same Game", False },
2891 { "menuEdit.Paste Game", False },
2892 { "menuFile.Load Position", False },
2893 // { "menuFile.Load Next Position", False },
2894 // { "menuFile.Load Previous Position", False },
2895 // { "menuFile.Reload Same Position", False },
2896 { "menuEdit.Paste Position", False },
2897 { "menuMode.Machine White", False },
2898 { "menuMode.Machine Black", False },
2899 { "menuMode.Two Machines", False },
2900 { "menuMode.Machine Match", False },
2901 { "menuEngine.Retract Move", False },
2905 Enables userThinkingEnables[] = {
2906 { "menuFile.Load Game", True },
2907 // { "menuFile.Load Next Game", True },
2908 // { "menuFile.Load Previous Game", True },
2909 // { "menuFile.Reload Same Game", True },
2910 { "menuEdit.Paste Game", True },
2911 { "menuFile.Load Position", True },
2912 // { "menuFile.Load Next Position", True },
2913 // { "menuFile.Load Previous Position", True },
2914 // { "menuFile.Reload Same Position", True },
2915 { "menuEdit.Paste Position", True },
2916 { "menuMode.Machine White", True },
2917 { "menuMode.Machine Black", True },
2918 { "menuMode.Two Machines", True },
2919 { "menuMode.Machine Match", True },
2920 { "menuEngine.Retract Move", True },
2926 SetMenuEnables(icsEnables);
2929 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2930 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2937 SetMenuEnables(ncpEnables);
2943 SetMenuEnables(gnuEnables);
2949 SetMenuEnables(cmailEnables);
2955 SetMenuEnables(trainingOnEnables);
2956 if (appData.showButtonBar) {
2957 XtSetSensitive(buttonBarWidget, False);
2963 SetTrainingModeOff()
2965 SetMenuEnables(trainingOffEnables);
2966 if (appData.showButtonBar) {
2967 XtSetSensitive(buttonBarWidget, True);
2972 SetUserThinkingEnables()
2974 if (appData.noChessProgram) return;
2975 SetMenuEnables(userThinkingEnables);
2979 SetMachineThinkingEnables()
2981 if (appData.noChessProgram) return;
2982 SetMenuEnables(machineThinkingEnables);
2984 case MachinePlaysBlack:
2985 case MachinePlaysWhite:
2986 case TwoMachinesPlay:
2987 XtSetSensitive(XtNameToWidget(menuBarWidget,
2988 ModeToWidgetName(gameMode)), True);
2995 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2996 #define HISTORY_SIZE 64
2997 static char *history[HISTORY_SIZE];
2998 int histIn = 0, histP = 0;
3001 SaveInHistory(char *cmd)
3003 if (history[histIn] != NULL) {
3004 free(history[histIn]);
3005 history[histIn] = NULL;
3007 if (*cmd == NULLCHAR) return;
3008 history[histIn] = StrSave(cmd);
3009 histIn = (histIn + 1) % HISTORY_SIZE;
3010 if (history[histIn] != NULL) {
3011 free(history[histIn]);
3012 history[histIn] = NULL;
3018 PrevInHistory(char *cmd)
3021 if (histP == histIn) {
3022 if (history[histIn] != NULL) free(history[histIn]);
3023 history[histIn] = StrSave(cmd);
3025 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
3026 if (newhp == histIn || history[newhp] == NULL) return NULL;
3028 return history[histP];
3034 if (histP == histIn) return NULL;
3035 histP = (histP + 1) % HISTORY_SIZE;
3036 return history[histP];
3038 // end of borrowed code
3040 #define Abs(n) ((n)<0 ? -(n) : (n))
3043 * Find a font that matches "pattern" that is as close as
3044 * possible to the targetPxlSize. Prefer fonts that are k
3045 * pixels smaller to fonts that are k pixels larger. The
3046 * pattern must be in the X Consortium standard format,
3047 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3048 * The return value should be freed with XtFree when no
3052 FindFont(pattern, targetPxlSize)
3056 char **fonts, *p, *best, *scalable, *scalableTail;
3057 int i, j, nfonts, minerr, err, pxlSize;
3060 char **missing_list;
3062 char *def_string, *base_fnt_lst, strInt[3];
3064 XFontStruct **fnt_list;
3065 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3066 snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize);
3067 p = strstr(pattern, "--");
3068 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3069 strcat(base_fnt_lst, strInt);
3070 strcat(base_fnt_lst, strchr(p + 2, '-'));
3072 if ((fntSet = XCreateFontSet(xDisplay,
3076 &def_string)) == NULL) {
3078 fprintf(stderr, _("Unable to create font set.\n"));
3082 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3084 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3086 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3087 programName, pattern);
3095 for (i=0; i<nfonts; i++) {
3098 if (*p != '-') continue;
3100 if (*p == NULLCHAR) break;
3101 if (*p++ == '-') j++;
3103 if (j < 7) continue;
3106 scalable = fonts[i];
3109 err = pxlSize - targetPxlSize;
3110 if (Abs(err) < Abs(minerr) ||
3111 (minerr > 0 && err < 0 && -err == minerr)) {
3117 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3118 /* If the error is too big and there is a scalable font,
3119 use the scalable font. */
3120 int headlen = scalableTail - scalable;
3121 p = (char *) XtMalloc(strlen(scalable) + 10);
3122 while (isdigit(*scalableTail)) scalableTail++;
3123 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3125 p = (char *) XtMalloc(strlen(best) + 2);
3126 safeStrCpy(p, best, strlen(best)+1 );
3128 if (appData.debugMode) {
3129 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3130 pattern, targetPxlSize, p);
3133 if (missing_count > 0)
3134 XFreeStringList(missing_list);
3135 XFreeFontSet(xDisplay, fntSet);
3137 XFreeFontNames(fonts);
3143 { // [HGM] deletes GCs that are to be remade, to prevent resource leak;
3144 // must be called before all non-first callse to CreateGCs()
3145 XtReleaseGC(shellWidget, highlineGC);
3146 XtReleaseGC(shellWidget, lightSquareGC);
3147 XtReleaseGC(shellWidget, darkSquareGC);
3148 XtReleaseGC(shellWidget, lineGC);
3149 if (appData.monoMode) {
3150 if (DefaultDepth(xDisplay, xScreen) == 1) {
3151 XtReleaseGC(shellWidget, wbPieceGC);
3153 XtReleaseGC(shellWidget, bwPieceGC);
3156 XtReleaseGC(shellWidget, prelineGC);
3157 XtReleaseGC(shellWidget, jailSquareGC);
3158 XtReleaseGC(shellWidget, wdPieceGC);
3159 XtReleaseGC(shellWidget, wlPieceGC);
3160 XtReleaseGC(shellWidget, wjPieceGC);
3161 XtReleaseGC(shellWidget, bdPieceGC);
3162 XtReleaseGC(shellWidget, blPieceGC);
3163 XtReleaseGC(shellWidget, bjPieceGC);
3167 void CreateGCs(int redo)
3169 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3170 | GCBackground | GCFunction | GCPlaneMask;
3171 XGCValues gc_values;
3174 gc_values.plane_mask = AllPlanes;
3175 gc_values.line_width = lineGap;
3176 gc_values.line_style = LineSolid;
3177 gc_values.function = GXcopy;
3180 DeleteGCs(); // called a second time; clean up old GCs first
3181 } else { // [HGM] grid and font GCs created on first call only
3182 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3183 gc_values.background = XWhitePixel(xDisplay, xScreen);
3184 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3185 XSetFont(xDisplay, coordGC, coordFontID);
3187 // [HGM] make font for holdings counts (white on black)
3188 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3189 gc_values.background = XBlackPixel(xDisplay, xScreen);
3190 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3191 XSetFont(xDisplay, countGC, countFontID);
3193 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3194 gc_values.background = XBlackPixel(xDisplay, xScreen);
3195 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3197 if (appData.monoMode) {
3198 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3199 gc_values.background = XWhitePixel(xDisplay, xScreen);
3200 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3202 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3203 gc_values.background = XBlackPixel(xDisplay, xScreen);
3204 lightSquareGC = wbPieceGC
3205 = XtGetGC(shellWidget, value_mask, &gc_values);
3207 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3208 gc_values.background = XWhitePixel(xDisplay, xScreen);
3209 darkSquareGC = bwPieceGC
3210 = XtGetGC(shellWidget, value_mask, &gc_values);
3212 if (DefaultDepth(xDisplay, xScreen) == 1) {
3213 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3214 gc_values.function = GXcopyInverted;
3215 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3216 gc_values.function = GXcopy;
3217 if (XBlackPixel(xDisplay, xScreen) == 1) {
3218 bwPieceGC = darkSquareGC;
3219 wbPieceGC = copyInvertedGC;
3221 bwPieceGC = copyInvertedGC;
3222 wbPieceGC = lightSquareGC;
3226 gc_values.foreground = highlightSquareColor;
3227 gc_values.background = highlightSquareColor;
3228 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3230 gc_values.foreground = premoveHighlightColor;
3231 gc_values.background = premoveHighlightColor;
3232 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3234 gc_values.foreground = lightSquareColor;
3235 gc_values.background = darkSquareColor;
3236 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3238 gc_values.foreground = darkSquareColor;
3239 gc_values.background = lightSquareColor;
3240 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3242 gc_values.foreground = jailSquareColor;
3243 gc_values.background = jailSquareColor;
3244 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3246 gc_values.foreground = whitePieceColor;
3247 gc_values.background = darkSquareColor;
3248 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3250 gc_values.foreground = whitePieceColor;
3251 gc_values.background = lightSquareColor;
3252 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3254 gc_values.foreground = whitePieceColor;
3255 gc_values.background = jailSquareColor;
3256 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3258 gc_values.foreground = blackPieceColor;
3259 gc_values.background = darkSquareColor;
3260 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3262 gc_values.foreground = blackPieceColor;
3263 gc_values.background = lightSquareColor;
3264 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3266 gc_values.foreground = blackPieceColor;
3267 gc_values.background = jailSquareColor;
3268 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3272 void loadXIM(xim, xmask, filename, dest, mask)
3285 fp = fopen(filename, "rb");
3287 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3294 for (y=0; y<h; ++y) {
3295 for (x=0; x<h; ++x) {
3300 XPutPixel(xim, x, y, blackPieceColor);
3302 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3305 XPutPixel(xim, x, y, darkSquareColor);
3307 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3310 XPutPixel(xim, x, y, whitePieceColor);
3312 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3315 XPutPixel(xim, x, y, lightSquareColor);
3317 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3325 /* create Pixmap of piece */
3326 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3328 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3331 /* create Pixmap of clipmask
3332 Note: We assume the white/black pieces have the same
3333 outline, so we make only 6 masks. This is okay
3334 since the XPM clipmask routines do the same. */
3336 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3338 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3341 /* now create the 1-bit version */
3342 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3345 values.foreground = 1;
3346 values.background = 0;
3348 /* Don't use XtGetGC, not read only */
3349 maskGC = XCreateGC(xDisplay, *mask,
3350 GCForeground | GCBackground, &values);
3351 XCopyPlane(xDisplay, temp, *mask, maskGC,
3352 0, 0, squareSize, squareSize, 0, 0, 1);
3353 XFreePixmap(xDisplay, temp);
3358 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3360 void CreateXIMPieces()
3365 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3370 /* The XSynchronize calls were copied from CreatePieces.
3371 Not sure if needed, but can't hurt */
3372 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3375 /* temp needed by loadXIM() */
3376 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3377 0, 0, ss, ss, AllPlanes, XYPixmap);
3379 if (strlen(appData.pixmapDirectory) == 0) {
3383 if (appData.monoMode) {
3384 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3388 fprintf(stderr, _("\nLoading XIMs...\n"));
3390 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3391 fprintf(stderr, "%d", piece+1);
3392 for (kind=0; kind<4; kind++) {
3393 fprintf(stderr, ".");
3394 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3395 ExpandPathName(appData.pixmapDirectory),
3396 piece <= (int) WhiteKing ? "" : "w",
3397 pieceBitmapNames[piece],
3399 ximPieceBitmap[kind][piece] =
3400 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3401 0, 0, ss, ss, AllPlanes, XYPixmap);
3402 if (appData.debugMode)
3403 fprintf(stderr, _("(File:%s:) "), buf);
3404 loadXIM(ximPieceBitmap[kind][piece],
3406 &(xpmPieceBitmap2[kind][piece]),
3407 &(ximMaskPm2[piece]));
3408 if(piece <= (int)WhiteKing)
3409 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3411 fprintf(stderr," ");
3413 /* Load light and dark squares */
3414 /* If the LSQ and DSQ pieces don't exist, we will
3415 draw them with solid squares. */
3416 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3417 if (access(buf, 0) != 0) {
3421 fprintf(stderr, _("light square "));
3423 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3424 0, 0, ss, ss, AllPlanes, XYPixmap);
3425 if (appData.debugMode)
3426 fprintf(stderr, _("(File:%s:) "), buf);
3428 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3429 fprintf(stderr, _("dark square "));
3430 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3431 ExpandPathName(appData.pixmapDirectory), ss);
3432 if (appData.debugMode)
3433 fprintf(stderr, _("(File:%s:) "), buf);
3435 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3436 0, 0, ss, ss, AllPlanes, XYPixmap);
3437 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3438 xpmJailSquare = xpmLightSquare;
3440 fprintf(stderr, _("Done.\n"));
3442 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3445 static VariantClass oldVariant = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
3448 void CreateXPMBoard(char *s, int kind)
3452 if(s == NULL || *s == 0 || *s == '*') { useTexture &= ~(kind+1); return; }
3453 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3454 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3458 void FreeXPMPieces()
3459 { // [HGM] to prevent resoucre leak on calling CreaeXPMPieces() a second time,
3460 // thisroutine has to be called t free the old piece pixmaps
3462 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++)
3463 for (kind=0; kind<4; kind++) XFreePixmap(xDisplay, xpmPieceBitmap2[kind][piece]);
3465 XFreePixmap(xDisplay, xpmLightSquare);
3466 XFreePixmap(xDisplay, xpmDarkSquare);
3470 void CreateXPMPieces()
3474 u_int ss = squareSize;
3476 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3477 XpmColorSymbol symbols[4];
3478 static int redo = False;
3480 if(redo) FreeXPMPieces(); else redo = 1;
3482 /* The XSynchronize calls were copied from CreatePieces.
3483 Not sure if needed, but can't hurt */
3484 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3486 /* Setup translations so piece colors match square colors */
3487 symbols[0].name = "light_piece";
3488 symbols[0].value = appData.whitePieceColor;
3489 symbols[1].name = "dark_piece";
3490 symbols[1].value = appData.blackPieceColor;
3491 symbols[2].name = "light_square";
3492 symbols[2].value = appData.lightSquareColor;
3493 symbols[3].name = "dark_square";
3494 symbols[3].value = appData.darkSquareColor;
3496 attr.valuemask = XpmColorSymbols;
3497 attr.colorsymbols = symbols;
3498 attr.numsymbols = 4;
3500 if (appData.monoMode) {
3501 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3505 if (strlen(appData.pixmapDirectory) == 0) {
3506 XpmPieces* pieces = builtInXpms;
3509 while (pieces->size != squareSize && pieces->size) pieces++;
3510 if (!pieces->size) {
3511 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3514 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3515 for (kind=0; kind<4; kind++) {
3517 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3518 pieces->xpm[piece][kind],
3519 &(xpmPieceBitmap2[kind][piece]),
3520 NULL, &attr)) != 0) {
3521 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3525 if(piece <= (int) WhiteKing)
3526 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3530 xpmJailSquare = xpmLightSquare;
3534 fprintf(stderr, _("\nLoading XPMs...\n"));
3537 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3538 fprintf(stderr, "%d ", piece+1);
3539 for (kind=0; kind<4; kind++) {
3540 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3541 ExpandPathName(appData.pixmapDirectory),
3542 piece > (int) WhiteKing ? "w" : "",
3543 pieceBitmapNames[piece],
3545 if (appData.debugMode) {
3546 fprintf(stderr, _("(File:%s:) "), buf);
3548 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3549 &(xpmPieceBitmap2[kind][piece]),
3550 NULL, &attr)) != 0) {
3551 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3552 // [HGM] missing: read of unorthodox piece failed; substitute King.
3553 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3554 ExpandPathName(appData.pixmapDirectory),
3556 if (appData.debugMode) {
3557 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3559 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3560 &(xpmPieceBitmap2[kind][piece]),
3564 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3569 if(piece <= (int) WhiteKing)
3570 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3573 /* Load light and dark squares */
3574 /* If the LSQ and DSQ pieces don't exist, we will
3575 draw them with solid squares. */
3576 fprintf(stderr, _("light square "));
3577 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3578 if (access(buf, 0) != 0) {
3582 if (appData.debugMode)
3583 fprintf(stderr, _("(File:%s:) "), buf);
3585 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3586 &xpmLightSquare, NULL, &attr)) != 0) {
3587 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3590 fprintf(stderr, _("dark square "));
3591 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3592 ExpandPathName(appData.pixmapDirectory), ss);
3593 if (appData.debugMode) {
3594 fprintf(stderr, _("(File:%s:) "), buf);
3596 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3597 &xpmDarkSquare, NULL, &attr)) != 0) {
3598 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3602 xpmJailSquare = xpmLightSquare;
3603 fprintf(stderr, _("Done.\n"));
3605 oldVariant = -1; // kludge to force re-makig of animation masks
3606 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3609 #endif /* HAVE_LIBXPM */
3612 /* No built-in bitmaps */
3617 u_int ss = squareSize;
3619 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3622 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3623 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3624 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3625 pieceBitmapNames[piece],
3626 ss, kind == SOLID ? 's' : 'o');
3627 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3628 if(piece <= (int)WhiteKing)
3629 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3633 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3637 /* With built-in bitmaps */
3640 BuiltInBits* bib = builtInBits;
3643 u_int ss = squareSize;
3645 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3648 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3650 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3651 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3652 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3653 pieceBitmapNames[piece],
3654 ss, kind == SOLID ? 's' : 'o');
3655 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3656 bib->bits[kind][piece], ss, ss);
3657 if(piece <= (int)WhiteKing)
3658 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3662 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3667 void ReadBitmap(pm, name, bits, wreq, hreq)
3670 unsigned char bits[];
3676 char msg[MSG_SIZ], fullname[MSG_SIZ];
3678 if (*appData.bitmapDirectory != NULLCHAR) {
3679 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3680 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3681 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3682 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3683 &w, &h, pm, &x_hot, &y_hot);
3684 fprintf(stderr, "load %s\n", name);
3685 if (errcode != BitmapSuccess) {
3687 case BitmapOpenFailed:
3688 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3690 case BitmapFileInvalid:
3691 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3693 case BitmapNoMemory:
3694 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3698 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3702 fprintf(stderr, _("%s: %s...using built-in\n"),
3704 } else if (w != wreq || h != hreq) {
3706 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3707 programName, fullname, w, h, wreq, hreq);
3713 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3722 if (lineGap == 0) return;
3724 /* [HR] Split this into 2 loops for non-square boards. */
3726 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3727 gridSegments[i].x1 = 0;
3728 gridSegments[i].x2 =
3729 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3730 gridSegments[i].y1 = gridSegments[i].y2
3731 = lineGap / 2 + (i * (squareSize + lineGap));
3734 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3735 gridSegments[j + i].y1 = 0;
3736 gridSegments[j + i].y2 =
3737 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3738 gridSegments[j + i].x1 = gridSegments[j + i].x2
3739 = lineGap / 2 + (j * (squareSize + lineGap));
3743 static void MenuBarSelect(w, addr, index)
3748 XtActionProc proc = (XtActionProc) addr;
3750 (proc)(NULL, NULL, NULL, NULL);
3753 void CreateMenuBarPopup(parent, name, mb)
3763 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3766 XtSetArg(args[j], XtNleftMargin, 20); j++;
3767 XtSetArg(args[j], XtNrightMargin, 20); j++;
3769 while (mi->string != NULL) {
3770 if (strcmp(mi->string, "----") == 0) {
3771 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3774 XtSetArg(args[j], XtNlabel, XtNewString(mi->string));
3775 entry = XtCreateManagedWidget(mi->ref, smeBSBObjectClass,
3777 XtAddCallback(entry, XtNcallback,
3778 (XtCallbackProc) MenuBarSelect,
3779 (caddr_t) mi->proc);
3785 Widget CreateMenuBar(mb)
3789 Widget anchor, menuBar;
3791 char menuName[MSG_SIZ];
3794 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3795 XtSetArg(args[j], XtNvSpace, 0); j++;
3796 XtSetArg(args[j], XtNborderWidth, 0); j++;
3797 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3798 formWidget, args, j);
3800 while (mb->name != NULL) {
3801 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3802 strncat(menuName, mb->ref, MSG_SIZ - strlen(menuName) - 1);
3804 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3807 shortName[0] = mb->name[0];
3808 shortName[1] = NULLCHAR;
3809 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3812 XtSetArg(args[j], XtNlabel, XtNewString(mb->name)); j++;
3815 XtSetArg(args[j], XtNborderWidth, 0); j++;
3816 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3818 CreateMenuBarPopup(menuBar, menuName, mb);
3824 Widget CreateButtonBar(mi)
3828 Widget button, buttonBar;
3832 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3834 XtSetArg(args[j], XtNhSpace, 0); j++;
3836 XtSetArg(args[j], XtNborderWidth, 0); j++;
3837 XtSetArg(args[j], XtNvSpace, 0); j++;
3838 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3839 formWidget, args, j);
3841 while (mi->string != NULL) {
3844 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3845 XtSetArg(args[j], XtNborderWidth, 0); j++;
3847 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3848 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3849 buttonBar, args, j);
3850 XtAddCallback(button, XtNcallback,
3851 (XtCallbackProc) MenuBarSelect,
3852 (caddr_t) mi->proc);
3859 CreatePieceMenu(name, color)
3866 ChessSquare selection;
3868 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3869 boardWidget, args, 0);
3871 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3872 String item = pieceMenuStrings[color][i];
3874 if (strcmp(item, "----") == 0) {
3875 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3878 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3879 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3881 selection = pieceMenuTranslation[color][i];
3882 XtAddCallback(entry, XtNcallback,
3883 (XtCallbackProc) PieceMenuSelect,
3884 (caddr_t) selection);
3885 if (selection == WhitePawn || selection == BlackPawn) {
3886 XtSetArg(args[0], XtNpopupOnEntry, entry);
3887 XtSetValues(menu, args, 1);
3900 ChessSquare selection;
3902 whitePieceMenu = CreatePieceMenu("menuW", 0);
3903 blackPieceMenu = CreatePieceMenu("menuB", 1);
3905 XtRegisterGrabAction(PieceMenuPopup, True,
3906 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3907 GrabModeAsync, GrabModeAsync);
3909 XtSetArg(args[0], XtNlabel, _("Drop"));
3910 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3911 boardWidget, args, 1);
3912 for (i = 0; i < DROP_MENU_SIZE; i++) {
3913 String item = dropMenuStrings[i];
3915 if (strcmp(item, "----") == 0) {
3916 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3919 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3920 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3922 selection = dropMenuTranslation[i];
3923 XtAddCallback(entry, XtNcallback,
3924 (XtCallbackProc) DropMenuSelect,
3925 (caddr_t) selection);
3930 void SetupDropMenu()
3938 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3939 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3940 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3941 dmEnables[i].piece);
3942 XtSetSensitive(entry, p != NULL || !appData.testLegality
3943 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3944 && !appData.icsActive));
3946 while (p && *p++ == dmEnables[i].piece) count++;
3947 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3949 XtSetArg(args[j], XtNlabel, label); j++;
3950 XtSetValues(entry, args, j);
3954 void PieceMenuPopup(w, event, params, num_params)
3958 Cardinal *num_params;
3960 String whichMenu; int menuNr;
3961 shiftKey = strcmp(params[0], "menuW"); // used to indicate black
3962 if (event->type == ButtonRelease)
3963 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3964 else if (event->type == ButtonPress)
3965 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3967 case 0: whichMenu = params[0]; break;
3968 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3970 case -1: if (errorUp) ErrorPopDown();
3973 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3976 static void PieceMenuSelect(w, piece, junk)
3981 if (pmFromX < 0 || pmFromY < 0) return;
3982 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3985 static void DropMenuSelect(w, piece, junk)
3990 if (pmFromX < 0 || pmFromY < 0) return;
3991 DropMenuEvent(piece, pmFromX, pmFromY);
3994 void WhiteClock(w, event, prms, nprms)
4003 void BlackClock(w, event, prms, nprms)
4014 * If the user selects on a border boundary, return -1; if off the board,
4015 * return -2. Otherwise map the event coordinate to the square.
4017 int EventToSquare(x, limit)
4025 if ((x % (squareSize + lineGap)) >= squareSize)
4027 x /= (squareSize + lineGap);
4033 static void do_flash_delay(msec)
4039 static void drawHighlight(file, rank, gc)
4045 if (lineGap == 0) return;
4048 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
4049 (squareSize + lineGap);
4050 y = lineGap/2 + rank * (squareSize + lineGap);
4052 x = lineGap/2 + file * (squareSize + lineGap);
4053 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
4054 (squareSize + lineGap);
4057 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
4058 squareSize+lineGap, squareSize+lineGap);
4061 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
4062 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4065 SetHighlights(fromX, fromY, toX, toY)
4066 int fromX, fromY, toX, toY;
4068 if (hi1X != fromX || hi1Y != fromY) {
4069 if (hi1X >= 0 && hi1Y >= 0) {
4070 drawHighlight(hi1X, hi1Y, lineGC);
4072 } // [HGM] first erase both, then draw new!
4073 if (hi2X != toX || hi2Y != toY) {
4074 if (hi2X >= 0 && hi2Y >= 0) {
4075 drawHighlight(hi2X, hi2Y, lineGC);
4078 if (hi1X != fromX || hi1Y != fromY) {
4079 if (fromX >= 0 && fromY >= 0) {
4080 drawHighlight(fromX, fromY, highlineGC);
4083 if (hi2X != toX || hi2Y != toY) {
4084 if (toX >= 0 && toY >= 0) {
4085 drawHighlight(toX, toY, highlineGC);
4097 SetHighlights(-1, -1, -1, -1);
4102 SetPremoveHighlights(fromX, fromY, toX, toY)
4103 int fromX, fromY, toX, toY;
4105 if (pm1X != fromX || pm1Y != fromY) {
4106 if (pm1X >= 0 && pm1Y >= 0) {
4107 drawHighlight(pm1X, pm1Y, lineGC);
4109 if (fromX >= 0 && fromY >= 0) {
4110 drawHighlight(fromX, fromY, prelineGC);
4113 if (pm2X != toX || pm2Y != toY) {
4114 if (pm2X >= 0 && pm2Y >= 0) {
4115 drawHighlight(pm2X, pm2Y, lineGC);
4117 if (toX >= 0 && toY >= 0) {
4118 drawHighlight(toX, toY, prelineGC);
4128 ClearPremoveHighlights()
4130 SetPremoveHighlights(-1, -1, -1, -1);
4133 static int CutOutSquare(x, y, x0, y0, kind)
4134 int x, y, *x0, *y0, kind;
4136 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
4137 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
4139 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
4140 if(textureW[kind] < W*squareSize)
4141 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
4143 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
4144 if(textureH[kind] < H*squareSize)
4145 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
4147 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
4151 static void BlankSquare(x, y, color, piece, dest, fac)
4152 int x, y, color, fac;
4155 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
4157 if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
4158 XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
4159 squareSize, squareSize, x*fac, y*fac);
4161 if (useImages && useImageSqs) {
4165 pm = xpmLightSquare;
4170 case 2: /* neutral */
4175 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4176 squareSize, squareSize, x*fac, y*fac);
4186 case 2: /* neutral */
4191 XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
4196 I split out the routines to draw a piece so that I could
4197 make a generic flash routine.
4199 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4201 int square_color, x, y;
4204 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4205 switch (square_color) {
4207 case 2: /* neutral */
4209 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4210 ? *pieceToOutline(piece)
4211 : *pieceToSolid(piece),
4212 dest, bwPieceGC, 0, 0,
4213 squareSize, squareSize, x, y);
4216 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4217 ? *pieceToSolid(piece)
4218 : *pieceToOutline(piece),
4219 dest, wbPieceGC, 0, 0,
4220 squareSize, squareSize, x, y);
4225 static void monoDrawPiece(piece, square_color, x, y, dest)
4227 int square_color, x, y;
4230 switch (square_color) {
4232 case 2: /* neutral */
4234 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4235 ? *pieceToOutline(piece)
4236 : *pieceToSolid(piece),
4237 dest, bwPieceGC, 0, 0,
4238 squareSize, squareSize, x, y, 1);
4241 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4242 ? *pieceToSolid(piece)
4243 : *pieceToOutline(piece),
4244 dest, wbPieceGC, 0, 0,
4245 squareSize, squareSize, x, y, 1);
4250 static void colorDrawPiece(piece, square_color, x, y, dest)
4252 int square_color, x, y;
4255 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4256 switch (square_color) {
4258 XCopyPlane(xDisplay, *pieceToSolid(piece),
4259 dest, (int) piece < (int) BlackPawn
4260 ? wlPieceGC : blPieceGC, 0, 0,
4261 squareSize, squareSize, x, y, 1);
4264 XCopyPlane(xDisplay, *pieceToSolid(piece),
4265 dest, (int) piece < (int) BlackPawn
4266 ? wdPieceGC : bdPieceGC, 0, 0,
4267 squareSize, squareSize, x, y, 1);
4269 case 2: /* neutral */
4271 XCopyPlane(xDisplay, *pieceToSolid(piece),
4272 dest, (int) piece < (int) BlackPawn
4273 ? wjPieceGC : bjPieceGC, 0, 0,
4274 squareSize, squareSize, x, y, 1);
4279 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4281 int square_color, x, y;
4284 int kind, p = piece;
4286 switch (square_color) {
4288 case 2: /* neutral */
4290 if ((int)piece < (int) BlackPawn) {
4298 if ((int)piece < (int) BlackPawn) {
4306 if(appData.upsideDown && flipView) { kind ^= 2; p += p < BlackPawn ? BlackPawn : -BlackPawn; }// swap white and black pieces
4307 if(useTexture & square_color+1) {
4308 BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background
4309 XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]);
4310 XSetClipOrigin(xDisplay, wlPieceGC, x, y);
4311 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y);
4312 XSetClipMask(xDisplay, wlPieceGC, None);
4313 XSetClipOrigin(xDisplay, wlPieceGC, 0, 0);
4315 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4316 dest, wlPieceGC, 0, 0,
4317 squareSize, squareSize, x, y);
4320 typedef void (*DrawFunc)();
4322 DrawFunc ChooseDrawFunc()
4324 if (appData.monoMode) {
4325 if (DefaultDepth(xDisplay, xScreen) == 1) {
4326 return monoDrawPiece_1bit;
4328 return monoDrawPiece;
4332 return colorDrawPieceImage;
4334 return colorDrawPiece;
4338 /* [HR] determine square color depending on chess variant. */
4339 static int SquareColor(row, column)
4344 if (gameInfo.variant == VariantXiangqi) {
4345 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4347 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4349 } else if (row <= 4) {
4355 square_color = ((column + row) % 2) == 1;
4358 /* [hgm] holdings: next line makes all holdings squares light */
4359 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4361 return square_color;
4364 void DrawSquare(row, column, piece, do_flash)
4365 int row, column, do_flash;
4368 int square_color, x, y, direction, font_ascent, font_descent;
4371 XCharStruct overall;
4375 /* Calculate delay in milliseconds (2-delays per complete flash) */
4376 flash_delay = 500 / appData.flashRate;
4379 x = lineGap + ((BOARD_WIDTH-1)-column) *
4380 (squareSize + lineGap);
4381 y = lineGap + row * (squareSize + lineGap);
4383 x = lineGap + column * (squareSize + lineGap);
4384 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4385 (squareSize + lineGap);
4388 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4390 square_color = SquareColor(row, column);
4392 if ( // [HGM] holdings: blank out area between board and holdings
4393 column == BOARD_LEFT-1 || column == BOARD_RGHT
4394 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4395 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4396 BlankSquare(x, y, 2, EmptySquare, xBoardWindow, 1);
4398 // [HGM] print piece counts next to holdings
4399 string[1] = NULLCHAR;
4400 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4401 string[0] = '0' + piece;
4402 XTextExtents(countFontStruct, string, 1, &direction,
4403 &font_ascent, &font_descent, &overall);
4404 if (appData.monoMode) {
4405 XDrawImageString(xDisplay, xBoardWindow, countGC,
4406 x + squareSize - overall.width - 2,
4407 y + font_ascent + 1, string, 1);
4409 XDrawString(xDisplay, xBoardWindow, countGC,
4410 x + squareSize - overall.width - 2,
4411 y + font_ascent + 1, string, 1);
4414 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4415 string[0] = '0' + piece;
4416 XTextExtents(countFontStruct, string, 1, &direction,
4417 &font_ascent, &font_descent, &overall);
4418 if (appData.monoMode) {
4419 XDrawImageString(xDisplay, xBoardWindow, countGC,
4420 x + 2, y + font_ascent + 1, string, 1);
4422 XDrawString(xDisplay, xBoardWindow, countGC,
4423 x + 2, y + font_ascent + 1, string, 1);
4427 if (piece == EmptySquare || appData.blindfold) {
4428 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4430 drawfunc = ChooseDrawFunc();
4432 if (do_flash && appData.flashCount > 0) {
4433 for (i=0; i<appData.flashCount; ++i) {
4434 drawfunc(piece, square_color, x, y, xBoardWindow);
4435 XSync(xDisplay, False);
4436 do_flash_delay(flash_delay);
4438 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4439 XSync(xDisplay, False);
4440 do_flash_delay(flash_delay);
4443 drawfunc(piece, square_color, x, y, xBoardWindow);
4447 string[1] = NULLCHAR;
4448 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4449 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4450 string[0] = 'a' + column - BOARD_LEFT;
4451 XTextExtents(coordFontStruct, string, 1, &direction,
4452 &font_ascent, &font_descent, &overall);
4453 if (appData.monoMode) {
4454 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4455 x + squareSize - overall.width - 2,
4456 y + squareSize - font_descent - 1, string, 1);
4458 XDrawString(xDisplay, xBoardWindow, coordGC,
4459 x + squareSize - overall.width - 2,
4460 y + squareSize - font_descent - 1, string, 1);
4463 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4464 string[0] = ONE + row;
4465 XTextExtents(coordFontStruct, string, 1, &direction,
4466 &font_ascent, &font_descent, &overall);
4467 if (appData.monoMode) {
4468 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4469 x + 2, y + font_ascent + 1, string, 1);
4471 XDrawString(xDisplay, xBoardWindow, coordGC,
4472 x + 2, y + font_ascent + 1, string, 1);
4475 if(!partnerUp && marker[row][column]) {
4476 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4477 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4482 /* Why is this needed on some versions of X? */
4483 void EventProc(widget, unused, event)
4488 if (!XtIsRealized(widget))
4491 switch (event->type) {
4493 if (event->xexpose.count > 0) return; /* no clipping is done */
4494 XDrawPosition(widget, True, NULL);
4495 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4496 flipView = !flipView; partnerUp = !partnerUp;
4497 XDrawPosition(widget, True, NULL);
4498 flipView = !flipView; partnerUp = !partnerUp;
4502 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
4509 void DrawPosition(fullRedraw, board)
4510 /*Boolean*/int fullRedraw;
4513 XDrawPosition(boardWidget, fullRedraw, board);
4516 /* Returns 1 if there are "too many" differences between b1 and b2
4517 (i.e. more than 1 move was made) */
4518 static int too_many_diffs(b1, b2)
4524 for (i=0; i<BOARD_HEIGHT; ++i) {
4525 for (j=0; j<BOARD_WIDTH; ++j) {
4526 if (b1[i][j] != b2[i][j]) {
4527 if (++c > 4) /* Castling causes 4 diffs */
4535 /* Matrix describing castling maneuvers */
4536 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4537 static int castling_matrix[4][5] = {
4538 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4539 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4540 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4541 { 7, 7, 4, 5, 6 } /* 0-0, black */
4544 /* Checks whether castling occurred. If it did, *rrow and *rcol
4545 are set to the destination (row,col) of the rook that moved.
4547 Returns 1 if castling occurred, 0 if not.
4549 Note: Only handles a max of 1 castling move, so be sure
4550 to call too_many_diffs() first.
4552 static int check_castle_draw(newb, oldb, rrow, rcol)
4559 /* For each type of castling... */
4560 for (i=0; i<4; ++i) {
4561 r = castling_matrix[i];
4563 /* Check the 4 squares involved in the castling move */
4565 for (j=1; j<=4; ++j) {
4566 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4573 /* All 4 changed, so it must be a castling move */
4582 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4583 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4585 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4588 void DrawSeekBackground( int left, int top, int right, int bottom )
4590 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4593 void DrawSeekText(char *buf, int x, int y)
4595 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4598 void DrawSeekDot(int x, int y, int colorNr)
4600 int square = colorNr & 0x80;
4603 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4605 XFillRectangle(xDisplay, xBoardWindow, color,
4606 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4608 XFillArc(xDisplay, xBoardWindow, color,
4609 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4612 static int damage[2][BOARD_RANKS][BOARD_FILES];
4615 * event handler for redrawing the board
4617 void XDrawPosition(w, repaint, board)
4619 /*Boolean*/int repaint;
4623 static int lastFlipView = 0;
4624 static int lastBoardValid[2] = {0, 0};
4625 static Board lastBoard[2];
4628 int nr = twoBoards*partnerUp;
4630 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4632 if (board == NULL) {
4633 if (!lastBoardValid[nr]) return;
4634 board = lastBoard[nr];
4636 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4637 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4638 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Flip View"),
4643 * It would be simpler to clear the window with XClearWindow()
4644 * but this causes a very distracting flicker.
4647 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4649 if ( lineGap && IsDrawArrowEnabled())
4650 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4651 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4653 /* If too much changes (begin observing new game, etc.), don't
4655 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4657 /* Special check for castling so we don't flash both the king
4658 and the rook (just flash the king). */
4660 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4661 /* Draw rook with NO flashing. King will be drawn flashing later */
4662 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4663 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4667 /* First pass -- Draw (newly) empty squares and repair damage.
4668 This prevents you from having a piece show up twice while it
4669 is flashing on its new square */
4670 for (i = 0; i < BOARD_HEIGHT; i++)
4671 for (j = 0; j < BOARD_WIDTH; j++)
4672 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4673 || damage[nr][i][j]) {
4674 DrawSquare(i, j, board[i][j], 0);
4675 damage[nr][i][j] = False;
4678 /* Second pass -- Draw piece(s) in new position and flash them */
4679 for (i = 0; i < BOARD_HEIGHT; i++)
4680 for (j = 0; j < BOARD_WIDTH; j++)
4681 if (board[i][j] != lastBoard[nr][i][j]) {
4682 DrawSquare(i, j, board[i][j], do_flash);
4686 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4687 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4688 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4690 for (i = 0; i < BOARD_HEIGHT; i++)
4691 for (j = 0; j < BOARD_WIDTH; j++) {
4692 DrawSquare(i, j, board[i][j], 0);
4693 damage[nr][i][j] = False;
4697 CopyBoard(lastBoard[nr], board);
4698 lastBoardValid[nr] = 1;
4699 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4700 lastFlipView = flipView;
4702 /* Draw highlights */
4703 if (pm1X >= 0 && pm1Y >= 0) {
4704 drawHighlight(pm1X, pm1Y, prelineGC);
4706 if (pm2X >= 0 && pm2Y >= 0) {
4707 drawHighlight(pm2X, pm2Y, prelineGC);
4709 if (hi1X >= 0 && hi1Y >= 0) {
4710 drawHighlight(hi1X, hi1Y, highlineGC);
4712 if (hi2X >= 0 && hi2Y >= 0) {
4713 drawHighlight(hi2X, hi2Y, highlineGC);
4715 DrawArrowHighlight(hi1X, hi1Y, hi2X, hi2Y);
4717 /* If piece being dragged around board, must redraw that too */
4720 XSync(xDisplay, False);
4725 * event handler for redrawing the board
4727 void DrawPositionProc(w, event, prms, nprms)
4733 XDrawPosition(w, True, NULL);
4738 * event handler for parsing user moves
4740 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4741 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4742 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4743 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4744 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4745 // and at the end FinishMove() to perform the move after optional promotion popups.
4746 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4747 void HandleUserMove(w, event, prms, nprms)
4753 if (w != boardWidget || errorExitStatus != -1) return;
4754 if(nprms) shiftKey = !strcmp(prms[0], "1");
4757 if (event->type == ButtonPress) {
4758 XtPopdown(promotionShell);
4759 XtDestroyWidget(promotionShell);
4760 promotionUp = False;
4768 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4769 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4770 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4773 void AnimateUserMove (Widget w, XEvent * event,
4774 String * params, Cardinal * nParams)
4776 if(!PromoScroll(event->xmotion.x, event->xmotion.y))
4777 DragPieceMove(event->xmotion.x, event->xmotion.y);
4780 void HandlePV (Widget w, XEvent * event,
4781 String * params, Cardinal * nParams)
4782 { // [HGM] pv: walk PV
4783 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4786 static int savedIndex; /* gross that this is global */
4788 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
4791 XawTextPosition index, dummy;
4794 XawTextGetSelectionPos(w, &index, &dummy);
4795 XtSetArg(arg, XtNstring, &val);
4796 XtGetValues(w, &arg, 1);
4797 ReplaceComment(savedIndex, val);
4798 if(savedIndex != currentMove) ToNrEvent(savedIndex);
4799 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
4802 void EditCommentPopUp(index, title, text)
4807 if (text == NULL) text = "";
4808 NewCommentPopup(title, text, index);
4811 void ICSInputBoxPopUp()
4816 extern Option boxOptions[];
4818 void ICSInputSendText()
4825 edit = boxOptions[0].handle;
4827 XtSetArg(args[j], XtNstring, &val); j++;
4828 XtGetValues(edit, args, j);
4830 SendMultiLineToICS(val);
4831 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4832 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4835 void ICSInputBoxPopDown()
4840 void CommentPopUp(title, text)
4843 savedIndex = currentMove; // [HGM] vari
4844 NewCommentPopup(title, text, currentMove);
4847 void CommentPopDown()
4852 void FileNamePopUp(label, def, filter, proc, openMode)
4859 fileProc = proc; /* I can't see a way not */
4860 fileOpenMode = openMode; /* to use globals here */
4861 { // [HGM] use file-selector dialog stolen from Ghostview
4863 int index; // this is not supported yet
4865 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
4866 (def[0] ? def : NULL), filter, openMode, NULL, &name))
4867 (void) (*fileProc)(f, index=0, name);
4871 void FileNamePopDown()
4873 if (!filenameUp) return;
4874 XtPopdown(fileNameShell);
4875 XtDestroyWidget(fileNameShell);
4880 void FileNameCallback(w, client_data, call_data)
4882 XtPointer client_data, call_data;
4887 XtSetArg(args[0], XtNlabel, &name);
4888 XtGetValues(w, args, 1);
4890 if (strcmp(name, _("cancel")) == 0) {
4895 FileNameAction(w, NULL, NULL, NULL);
4898 void FileNameAction(w, event, prms, nprms)
4910 name = XawDialogGetValueString(w = XtParent(w));
4912 if ((name != NULL) && (*name != NULLCHAR)) {
4913 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
4914 XtPopdown(w = XtParent(XtParent(w)));
4918 p = strrchr(buf, ' ');
4925 fullname = ExpandPathName(buf);
4927 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
4930 f = fopen(fullname, fileOpenMode);
4932 DisplayError(_("Failed to open file"), errno);
4934 (void) (*fileProc)(f, index, buf);
4941 XtPopdown(w = XtParent(XtParent(w)));
4947 void PromotionPopUp()
4950 Widget dialog, layout;
4952 Dimension bw_width, pw_width;
4956 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4957 XtGetValues(boardWidget, args, j);
4960 XtSetArg(args[j], XtNresizable, True); j++;
4961 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
4963 XtCreatePopupShell("Promotion", transientShellWidgetClass,
4964 shellWidget, args, j);
4966 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
4967 layoutArgs, XtNumber(layoutArgs));
4970 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
4971 XtSetArg(args[j], XtNborderWidth, 0); j++;
4972 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
4975 if(gameInfo.variant != VariantShogi) {
4976 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) {
4977 XawDialogAddButton(dialog, _("Warlord"), PromotionCallback,
4978 (XtPointer) dialog);
4979 XawDialogAddButton(dialog, _("General"), PromotionCallback,
4980 (XtPointer) dialog);
4981 XawDialogAddButton(dialog, _("Lieutenant"), PromotionCallback,
4982 (XtPointer) dialog);
4983 XawDialogAddButton(dialog, _("Captain"), PromotionCallback,
4984 (XtPointer) dialog);
4986 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
4987 (XtPointer) dialog);
4988 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
4989 (XtPointer) dialog);
4990 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
4991 (XtPointer) dialog);
4992 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
4993 (XtPointer) dialog);
4995 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
4996 gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
\r
4997 gameInfo.variant == VariantGiveaway) {
4998 XawDialogAddButton(dialog, _("King"), PromotionCallback,
4999 (XtPointer) dialog);
5001 if(gameInfo.variant == VariantCapablanca ||
5002 gameInfo.variant == VariantGothic ||
5003 gameInfo.variant == VariantCapaRandom) {
5004 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5005 (XtPointer) dialog);
5006 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5007 (XtPointer) dialog);
5009 } else // [HGM] shogi
5011 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5012 (XtPointer) dialog);
5013 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5014 (XtPointer) dialog);
5016 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5017 (XtPointer) dialog);
5019 XtRealizeWidget(promotionShell);
5020 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5023 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5024 XtGetValues(promotionShell, args, j);
5026 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5027 lineGap + squareSize/3 +
5028 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5029 0 : 6*(squareSize + lineGap)), &x, &y);
5032 XtSetArg(args[j], XtNx, x); j++;
5033 XtSetArg(args[j], XtNy, y); j++;
5034 XtSetValues(promotionShell, args, j);
5036 XtPopup(promotionShell, XtGrabNone);
5041 void PromotionPopDown()
5043 if (!promotionUp) return;
5044 XtPopdown(promotionShell);
5045 XtDestroyWidget(promotionShell);
5046 promotionUp = False;
5049 void PromotionCallback(w, client_data, call_data)
5051 XtPointer client_data, call_data;
5057 XtSetArg(args[0], XtNlabel, &name);
5058 XtGetValues(w, args, 1);
5062 if (fromX == -1) return;
5064 if (strcmp(name, _("cancel")) == 0) {
5068 } else if (strcmp(name, _("Knight")) == 0) {
5070 } else if (strcmp(name, _("Promote")) == 0) {
5072 } else if (strcmp(name, _("Defer")) == 0) {
5075 promoChar = ToLower(name[0]);
5078 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5080 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5081 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5086 void ErrorCallback(w, client_data, call_data)
5088 XtPointer client_data, call_data;
5091 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5093 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5099 if (!errorUp) return;
5101 XtPopdown(errorShell);
5102 XtDestroyWidget(errorShell);
5103 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5106 void ErrorPopUp(title, label, modal)
5107 char *title, *label;
5111 Widget dialog, layout;
5115 Dimension bw_width, pw_width;
5116 Dimension pw_height;
5120 XtSetArg(args[i], XtNresizable, True); i++;
5121 XtSetArg(args[i], XtNtitle, title); i++;
5123 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5124 shellWidget, args, i);
5126 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5127 layoutArgs, XtNumber(layoutArgs));
5130 XtSetArg(args[i], XtNlabel, label); i++;
5131 XtSetArg(args[i], XtNborderWidth, 0); i++;
5132 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5135 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5137 XtRealizeWidget(errorShell);
5138 CatchDeleteWindow(errorShell, "ErrorPopDown");
5141 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5142 XtGetValues(boardWidget, args, i);
5144 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5145 XtSetArg(args[i], XtNheight, &pw_height); i++;
5146 XtGetValues(errorShell, args, i);
5149 /* This code seems to tickle an X bug if it is executed too soon
5150 after xboard starts up. The coordinates get transformed as if
5151 the main window was positioned at (0, 0).
5153 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5154 0 - pw_height + squareSize / 3, &x, &y);
5156 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5157 RootWindowOfScreen(XtScreen(boardWidget)),
5158 (bw_width - pw_width) / 2,
5159 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5163 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5166 XtSetArg(args[i], XtNx, x); i++;
5167 XtSetArg(args[i], XtNy, y); i++;
5168 XtSetValues(errorShell, args, i);
5171 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5174 /* Disable all user input other than deleting the window */
5175 static int frozen = 0;
5179 /* Grab by a widget that doesn't accept input */
5180 XtAddGrab(messageWidget, TRUE, FALSE);
5184 /* Undo a FreezeUI */
5187 if (!frozen) return;
5188 XtRemoveGrab(messageWidget);
5192 char *ModeToWidgetName(mode)
5196 case BeginningOfGame:
5197 if (appData.icsActive)
5198 return "menuMode.ICS Client";
5199 else if (appData.noChessProgram ||
5200 *appData.cmailGameName != NULLCHAR)
5201 return "menuMode.Edit Game";
5203 return "menuMode.Machine Black";
5204 case MachinePlaysBlack:
5205 return "menuMode.Machine Black";
5206 case MachinePlaysWhite:
5207 return "menuMode.Machine White";
5209 return "menuMode.Analysis Mode";
5211 return "menuMode.Analyze File";
5212 case TwoMachinesPlay:
5213 return "menuMode.Two Machines";
5215 return "menuMode.Edit Game";
5216 case PlayFromGameFile:
5217 return "menuFile.Load Game";
5219 return "menuMode.Edit Position";
5221 return "menuMode.Training";
5222 case IcsPlayingWhite:
5223 case IcsPlayingBlack:
5227 return "menuMode.ICS Client";
5234 void ModeHighlight()
5237 static int oldPausing = FALSE;
5238 static GameMode oldmode = (GameMode) -1;
5241 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5243 if (pausing != oldPausing) {
5244 oldPausing = pausing;
5246 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5248 XtSetArg(args[0], XtNleftBitmap, None);
5250 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5253 if (appData.showButtonBar) {
5254 /* Always toggle, don't set. Previous code messes up when
5255 invoked while the button is pressed, as releasing it
5256 toggles the state again. */
5259 XtSetArg(args[0], XtNbackground, &oldbg);
5260 XtSetArg(args[1], XtNforeground, &oldfg);
5261 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5263 XtSetArg(args[0], XtNbackground, oldfg);
5264 XtSetArg(args[1], XtNforeground, oldbg);
5266 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5270 wname = ModeToWidgetName(oldmode);
5271 if (wname != NULL) {
5272 XtSetArg(args[0], XtNleftBitmap, None);
5273 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5275 wname = ModeToWidgetName(gameMode);
5276 if (wname != NULL) {
5277 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5278 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5282 /* Maybe all the enables should be handled here, not just this one */
5283 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5284 gameMode == Training || gameMode == PlayFromGameFile);
5289 * Button/menu procedures
5291 void ResetProc(w, event, prms, nprms)
5300 int LoadGamePopUp(f, gameNumber, title)
5305 cmailMsgLoaded = FALSE;
5306 if (gameNumber == 0) {
5307 int error = GameListBuild(f);
5309 DisplayError(_("Cannot build game list"), error);
5310 } else if (!ListEmpty(&gameList) &&
5311 ((ListGame *) gameList.tailPred)->number > 1) {
5312 GameListPopUp(f, title);
5318 return LoadGame(f, gameNumber, title, FALSE);
5321 void LoadGameProc(w, event, prms, nprms)
5327 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5330 FileNamePopUp(_("Load game file name?"), "", ".pgn .game", LoadGamePopUp, "rb");
5333 void LoadNextGameProc(w, event, prms, nprms)
5342 void LoadPrevGameProc(w, event, prms, nprms)
5351 void ReloadGameProc(w, event, prms, nprms)
5360 void LoadNextPositionProc(w, event, prms, nprms)
5369 void LoadPrevPositionProc(w, event, prms, nprms)
5378 void ReloadPositionProc(w, event, prms, nprms)
5387 void LoadPositionProc(w, event, prms, nprms)
5393 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5396 FileNamePopUp(_("Load position file name?"), "", ".fen .epd .pos", LoadPosition, "rb");
5399 void SaveGameProc(w, event, prms, nprms)
5405 FileNamePopUp(_("Save game file name?"),
5406 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5407 appData.oldSaveStyle ? ".game" : ".pgn",
5411 void SavePositionProc(w, event, prms, nprms)
5417 FileNamePopUp(_("Save position file name?"),
5418 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5419 appData.oldSaveStyle ? ".pos" : ".fen",
5423 void ReloadCmailMsgProc(w, event, prms, nprms)
5429 ReloadCmailMsgEvent(FALSE);
5432 void MailMoveProc(w, event, prms, nprms)
5441 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5442 char *selected_fen_position=NULL;
5445 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5446 Atom *type_return, XtPointer *value_return,
5447 unsigned long *length_return, int *format_return)
5449 char *selection_tmp;
5451 if (!selected_fen_position) return False; /* should never happen */
5452 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5453 /* note: since no XtSelectionDoneProc was registered, Xt will
5454 * automatically call XtFree on the value returned. So have to
5455 * make a copy of it allocated with XtMalloc */
5456 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5457 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
5459 *value_return=selection_tmp;
5460 *length_return=strlen(selection_tmp);
5461 *type_return=*target;
5462 *format_return = 8; /* bits per byte */
5464 } else if (*target == XA_TARGETS(xDisplay)) {
5465 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5466 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5467 targets_tmp[1] = XA_STRING;
5468 *value_return = targets_tmp;
5469 *type_return = XA_ATOM;
5471 *format_return = 8 * sizeof(Atom);
5472 if (*format_return > 32) {
5473 *length_return *= *format_return / 32;
5474 *format_return = 32;
5482 /* note: when called from menu all parameters are NULL, so no clue what the
5483 * Widget which was clicked on was, or what the click event was
5485 void CopyPositionProc(w, event, prms, nprms)
5492 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5493 * have a notion of a position that is selected but not copied.
5494 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5496 if(gameMode == EditPosition) EditPositionDone(TRUE);
5497 if (selected_fen_position) free(selected_fen_position);
5498 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5499 if (!selected_fen_position) return;
5500 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5502 SendPositionSelection,
5503 NULL/* lose_ownership_proc */ ,
5504 NULL/* transfer_done_proc */);
5505 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5507 SendPositionSelection,
5508 NULL/* lose_ownership_proc */ ,
5509 NULL/* transfer_done_proc */);
5512 /* function called when the data to Paste is ready */
5514 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5515 Atom *type, XtPointer value, unsigned long *len, int *format)
5518 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5519 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5520 EditPositionPasteFEN(fenstr);
5524 /* called when Paste Position button is pressed,
5525 * all parameters will be NULL */
5526 void PastePositionProc(w, event, prms, nprms)
5532 XtGetSelectionValue(menuBarWidget,
5533 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5534 /* (XtSelectionCallbackProc) */ PastePositionCB,
5535 NULL, /* client_data passed to PastePositionCB */
5537 /* better to use the time field from the event that triggered the
5538 * call to this function, but that isn't trivial to get
5546 SendGameSelection(Widget w, Atom *selection, Atom *target,
5547 Atom *type_return, XtPointer *value_return,
5548 unsigned long *length_return, int *format_return)
5550 char *selection_tmp;
5552 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5553 FILE* f = fopen(gameCopyFilename, "r");
5556 if (f == NULL) return False;
5560 selection_tmp = XtMalloc(len + 1);
5561 count = fread(selection_tmp, 1, len, f);
5564 XtFree(selection_tmp);
5567 selection_tmp[len] = NULLCHAR;
5568 *value_return = selection_tmp;
5569 *length_return = len;
5570 *type_return = *target;
5571 *format_return = 8; /* bits per byte */
5573 } else if (*target == XA_TARGETS(xDisplay)) {
5574 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5575 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5576 targets_tmp[1] = XA_STRING;
5577 *value_return = targets_tmp;
5578 *type_return = XA_ATOM;
5580 *format_return = 8 * sizeof(Atom);
5581 if (*format_return > 32) {
5582 *length_return *= *format_return / 32;
5583 *format_return = 32;
5591 void CopySomething()
5596 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5597 * have a notion of a game that is selected but not copied.
5598 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5600 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5603 NULL/* lose_ownership_proc */ ,
5604 NULL/* transfer_done_proc */);
5605 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5608 NULL/* lose_ownership_proc */ ,
5609 NULL/* transfer_done_proc */);
5612 /* note: when called from menu all parameters are NULL, so no clue what the
5613 * Widget which was clicked on was, or what the click event was
5615 void CopyGameProc(w, event, prms, nprms)
5623 ret = SaveGameToFile(gameCopyFilename, FALSE);
5629 void CopyGameListProc(w, event, prms, nprms)
5635 if(!SaveGameListAsText(fopen(gameCopyFilename, "w"))) return;
5639 /* function called when the data to Paste is ready */
5641 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5642 Atom *type, XtPointer value, unsigned long *len, int *format)
5645 if (value == NULL || *len == 0) {
5646 return; /* nothing had been selected to copy */
5648 f = fopen(gamePasteFilename, "w");
5650 DisplayError(_("Can't open temp file"), errno);
5653 fwrite(value, 1, *len, f);
5656 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5659 /* called when Paste Game button is pressed,
5660 * all parameters will be NULL */
5661 void PasteGameProc(w, event, prms, nprms)
5667 XtGetSelectionValue(menuBarWidget,
5668 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5669 /* (XtSelectionCallbackProc) */ PasteGameCB,
5670 NULL, /* client_data passed to PasteGameCB */
5672 /* better to use the time field from the event that triggered the
5673 * call to this function, but that isn't trivial to get
5683 SaveGameProc(NULL, NULL, NULL, NULL);
5687 void QuitProc(w, event, prms, nprms)
5696 void PauseProc(w, event, prms, nprms)
5706 void MachineBlackProc(w, event, prms, nprms)
5712 MachineBlackEvent();
5715 void MachineWhiteProc(w, event, prms, nprms)
5721 MachineWhiteEvent();
5724 void AnalyzeModeProc(w, event, prms, nprms)
5732 if (!first.analysisSupport) {
5733 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5734 DisplayError(buf, 0);
5737 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5738 if (appData.icsActive) {
5739 if (gameMode != IcsObserving) {
5740 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
5741 DisplayError(buf, 0);
5743 if (appData.icsEngineAnalyze) {
5744 if (appData.debugMode)
5745 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5751 /* if enable, use want disable icsEngineAnalyze */
5752 if (appData.icsEngineAnalyze) {
5757 appData.icsEngineAnalyze = TRUE;
5758 if (appData.debugMode)
5759 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5761 #ifndef OPTIONSDIALOG
5762 if (!appData.showThinking)
5763 ShowThinkingProc(w,event,prms,nprms);
5769 void AnalyzeFileProc(w, event, prms, nprms)
5775 if (!first.analysisSupport) {
5777 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5778 DisplayError(buf, 0);
5782 #ifndef OPTIONSDIALOG
5783 if (!appData.showThinking)
5784 ShowThinkingProc(w,event,prms,nprms);
5787 FileNamePopUp(_("File to analyze"), "", ".pgn .game", LoadGamePopUp, "rb");
5788 AnalysisPeriodicEvent(1);
5791 void TwoMachinesProc(w, event, prms, nprms)
5800 void MatchProc(w, event, prms, nprms)
5806 if(gameMode != BeginningOfGame) { DisplayError(_("You can only start a match from the initial position."), 0); return; }
5807 appData.matchGames = appData.defaultMatchGames;
5811 void IcsClientProc(w, event, prms, nprms)
5820 void EditGameProc(w, event, prms, nprms)
5829 void EditPositionProc(w, event, prms, nprms)
5835 EditPositionEvent();
5838 void TrainingProc(w, event, prms, nprms)
5847 void EditCommentProc(w, event, prms, nprms)
5855 if (PopDown(1)) { // popdown succesful
5857 XtSetArg(args[j], XtNleftBitmap, None); j++;
5858 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"), args, j);
5859 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"), args, j);
5860 } else // was not up
5864 void IcsInputBoxProc(w, event, prms, nprms)
5870 if (!PopDown(4)) ICSInputBoxPopUp();
5873 void AcceptProc(w, event, prms, nprms)
5882 void DeclineProc(w, event, prms, nprms)
5891 void RematchProc(w, event, prms, nprms)
5900 void CallFlagProc(w, event, prms, nprms)
5909 void DrawProc(w, event, prms, nprms)
5918 void AbortProc(w, event, prms, nprms)
5927 void AdjournProc(w, event, prms, nprms)
5936 void ResignProc(w, event, prms, nprms)
5945 void AdjuWhiteProc(w, event, prms, nprms)
5951 UserAdjudicationEvent(+1);
5954 void AdjuBlackProc(w, event, prms, nprms)
5960 UserAdjudicationEvent(-1);
5963 void AdjuDrawProc(w, event, prms, nprms)
5969 UserAdjudicationEvent(0);
5972 void EnterKeyProc(w, event, prms, nprms)
5978 if (shellUp[4] == True)
5982 void UpKeyProc(w, event, prms, nprms)
5987 { // [HGM] input: let up-arrow recall previous line from history
5994 if (!shellUp[4]) return;
5995 edit = boxOptions[0].handle;
5997 XtSetArg(args[j], XtNstring, &val); j++;
5998 XtGetValues(edit, args, j);
5999 val = PrevInHistory(val);
6000 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6001 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6003 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6004 XawTextReplace(edit, 0, 0, &t);
6005 XawTextSetInsertionPoint(edit, 9999);
6009 void DownKeyProc(w, event, prms, nprms)
6014 { // [HGM] input: let down-arrow recall next line from history
6019 if (!shellUp[4]) return;
6020 edit = boxOptions[0].handle;
6021 val = NextInHistory();
6022 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6023 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6025 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6026 XawTextReplace(edit, 0, 0, &t);
6027 XawTextSetInsertionPoint(edit, 9999);
6031 void StopObservingProc(w, event, prms, nprms)
6037 StopObservingEvent();
6040 void StopExaminingProc(w, event, prms, nprms)
6046 StopExaminingEvent();
6049 void UploadProc(w, event, prms, nprms)
6059 void ForwardProc(w, event, prms, nprms)
6069 void BackwardProc(w, event, prms, nprms)
6078 void ToStartProc(w, event, prms, nprms)
6087 void ToEndProc(w, event, prms, nprms)
6096 void RevertProc(w, event, prms, nprms)
6105 void AnnotateProc(w, event, prms, nprms)
6114 void TruncateGameProc(w, event, prms, nprms)
6120 TruncateGameEvent();
6122 void RetractMoveProc(w, event, prms, nprms)
6131 void MoveNowProc(w, event, prms, nprms)
6140 void FlipViewProc(w, event, prms, nprms)
6146 flipView = !flipView;
6147 DrawPosition(True, NULL);
6150 void PonderNextMoveProc(w, event, prms, nprms)
6158 PonderNextMoveEvent(!appData.ponderNextMove);
6159 #ifndef OPTIONSDIALOG
6160 if (appData.ponderNextMove) {
6161 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6163 XtSetArg(args[0], XtNleftBitmap, None);
6165 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6170 #ifndef OPTIONSDIALOG
6171 void AlwaysQueenProc(w, event, prms, nprms)
6179 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6181 if (appData.alwaysPromoteToQueen) {
6182 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6184 XtSetArg(args[0], XtNleftBitmap, None);
6186 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6190 void AnimateDraggingProc(w, event, prms, nprms)
6198 appData.animateDragging = !appData.animateDragging;
6200 if (appData.animateDragging) {
6201 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6204 XtSetArg(args[0], XtNleftBitmap, None);
6206 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6210 void AnimateMovingProc(w, event, prms, nprms)
6218 appData.animate = !appData.animate;
6220 if (appData.animate) {
6221 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6224 XtSetArg(args[0], XtNleftBitmap, None);
6226 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6230 void AutoflagProc(w, event, prms, nprms)
6238 appData.autoCallFlag = !appData.autoCallFlag;
6240 if (appData.autoCallFlag) {
6241 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6243 XtSetArg(args[0], XtNleftBitmap, None);
6245 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6249 void AutoflipProc(w, event, prms, nprms)
6257 appData.autoFlipView = !appData.autoFlipView;
6259 if (appData.autoFlipView) {
6260 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6262 XtSetArg(args[0], XtNleftBitmap, None);
6264 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6268 void BlindfoldProc(w, event, prms, nprms)
6276 appData.blindfold = !appData.blindfold;
6278 if (appData.blindfold) {
6279 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6281 XtSetArg(args[0], XtNleftBitmap, None);
6283 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6286 DrawPosition(True, NULL);
6289 void TestLegalityProc(w, event, prms, nprms)
6297 appData.testLegality = !appData.testLegality;
6299 if (appData.testLegality) {
6300 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6302 XtSetArg(args[0], XtNleftBitmap, None);
6304 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6309 void FlashMovesProc(w, event, prms, nprms)
6317 if (appData.flashCount == 0) {
6318 appData.flashCount = 3;
6320 appData.flashCount = -appData.flashCount;
6323 if (appData.flashCount > 0) {
6324 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6326 XtSetArg(args[0], XtNleftBitmap, None);
6328 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6333 void HighlightDraggingProc(w, event, prms, nprms)
6341 appData.highlightDragging = !appData.highlightDragging;
6343 if (appData.highlightDragging) {
6344 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6346 XtSetArg(args[0], XtNleftBitmap, None);
6348 XtSetValues(XtNameToWidget(menuBarWidget,
6349 "menuOptions.Highlight Dragging"), args, 1);
6353 void HighlightLastMoveProc(w, event, prms, nprms)
6361 appData.highlightLastMove = !appData.highlightLastMove;
6363 if (appData.highlightLastMove) {
6364 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6366 XtSetArg(args[0], XtNleftBitmap, None);
6368 XtSetValues(XtNameToWidget(menuBarWidget,
6369 "menuOptions.Highlight Last Move"), args, 1);
6372 void HighlightArrowProc(w, event, prms, nprms)
6380 appData.highlightMoveWithArrow = !appData.highlightMoveWithArrow;
6382 if (appData.highlightMoveWithArrow) {
6383 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6385 XtSetArg(args[0], XtNleftBitmap, None);
6387 XtSetValues(XtNameToWidget(menuBarWidget,
6388 "menuOptions.Arrow"), args, 1);
6392 void IcsAlarmProc(w, event, prms, nprms)
6400 appData.icsAlarm = !appData.icsAlarm;
6402 if (appData.icsAlarm) {
6403 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6405 XtSetArg(args[0], XtNleftBitmap, None);
6407 XtSetValues(XtNameToWidget(menuBarWidget,
6408 "menuOptions.ICS Alarm"), args, 1);
6412 void MoveSoundProc(w, event, prms, nprms)
6420 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6422 if (appData.ringBellAfterMoves) {
6423 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6425 XtSetArg(args[0], XtNleftBitmap, None);
6427 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6431 void OneClickProc(w, event, prms, nprms)
6439 appData.oneClick = !appData.oneClick;
6441 if (appData.oneClick) {
6442 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6444 XtSetArg(args[0], XtNleftBitmap, None);
6446 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.OneClick"),
6450 void PeriodicUpdatesProc(w, event, prms, nprms)
6458 PeriodicUpdatesEvent(!appData.periodicUpdates);
6460 if (appData.periodicUpdates) {
6461 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6463 XtSetArg(args[0], XtNleftBitmap, None);
6465 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6469 void PopupExitMessageProc(w, event, prms, nprms)
6477 appData.popupExitMessage = !appData.popupExitMessage;
6479 if (appData.popupExitMessage) {
6480 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6482 XtSetArg(args[0], XtNleftBitmap, None);
6484 XtSetValues(XtNameToWidget(menuBarWidget,
6485 "menuOptions.Popup Exit Message"), args, 1);
6488 void PopupMoveErrorsProc(w, event, prms, nprms)
6496 appData.popupMoveErrors = !appData.popupMoveErrors;
6498 if (appData.popupMoveErrors) {
6499 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6501 XtSetArg(args[0], XtNleftBitmap, None);
6503 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6508 void PremoveProc(w, event, prms, nprms)
6516 appData.premove = !appData.premove;
6518 if (appData.premove) {
6519 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6521 XtSetArg(args[0], XtNleftBitmap, None);
6523 XtSetValues(XtNameToWidget(menuBarWidget,
6524 "menuOptions.Premove"), args, 1);
6528 void ShowCoordsProc(w, event, prms, nprms)
6536 appData.showCoords = !appData.showCoords;
6538 if (appData.showCoords) {
6539 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6541 XtSetArg(args[0], XtNleftBitmap, None);
6543 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6546 DrawPosition(True, NULL);
6549 void ShowThinkingProc(w, event, prms, nprms)
6555 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6556 ShowThinkingEvent();
6559 void HideThinkingProc(w, event, prms, nprms)
6567 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6568 ShowThinkingEvent();
6570 if (appData.hideThinkingFromHuman) {
6571 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6573 XtSetArg(args[0], XtNleftBitmap, None);
6575 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6580 void SaveOnExitProc(w, event, prms, nprms)
6588 saveSettingsOnExit = !saveSettingsOnExit;
6590 if (saveSettingsOnExit) {
6591 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6593 XtSetArg(args[0], XtNleftBitmap, None);
6595 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6599 void SaveSettingsProc(w, event, prms, nprms)
6605 SaveSettings(settingsFileName);
6608 void InfoProc(w, event, prms, nprms)
6615 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6620 void ManProc(w, event, prms, nprms)
6628 if (nprms && *nprms > 0)
6632 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6636 void HintProc(w, event, prms, nprms)
6645 void BookProc(w, event, prms, nprms)
6654 void AboutProc(w, event, prms, nprms)
6662 char *zippy = " (with Zippy code)";
6666 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6667 programVersion, zippy,
6668 "Copyright 1991 Digital Equipment Corporation",
6669 "Enhancements Copyright 1992-2009 Free Software Foundation",
6670 "Enhancements Copyright 2005 Alessandro Scotti",
6671 PACKAGE, " is free software and carries NO WARRANTY;",
6672 "see the file COPYING for more information.");
6673 ErrorPopUp(_("About XBoard"), buf, FALSE);
6676 void DebugProc(w, event, prms, nprms)
6682 appData.debugMode = !appData.debugMode;
6685 void AboutGameProc(w, event, prms, nprms)
6694 void NothingProc(w, event, prms, nprms)
6703 void Iconify(w, event, prms, nprms)
6712 XtSetArg(args[0], XtNiconic, True);
6713 XtSetValues(shellWidget, args, 1);
6716 void DisplayMessage(message, extMessage)
6717 char *message, *extMessage;
6719 /* display a message in the message widget */
6728 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
6733 message = extMessage;
6737 /* need to test if messageWidget already exists, since this function
6738 can also be called during the startup, if for example a Xresource
6739 is not set up correctly */
6742 XtSetArg(arg, XtNlabel, message);
6743 XtSetValues(messageWidget, &arg, 1);
6749 void DisplayTitle(text)
6754 char title[MSG_SIZ];
6757 if (text == NULL) text = "";
6759 if (appData.titleInWindow) {
6761 XtSetArg(args[i], XtNlabel, text); i++;
6762 XtSetValues(titleWidget, args, i);
6765 if (*text != NULLCHAR) {
6766 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
6767 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
6768 } else if (appData.icsActive) {
6769 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
6770 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
6771 } else if (appData.cmailGameName[0] != NULLCHAR) {
6772 snprintf(icon, sizeof(icon), "%s", "CMail");
6773 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
6775 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
6776 } else if (gameInfo.variant == VariantGothic) {
6777 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6778 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
6781 } else if (gameInfo.variant == VariantFalcon) {
6782 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6783 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
6785 } else if (appData.noChessProgram) {
6786 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6787 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
6789 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
6790 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
6793 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
6794 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
6795 XtSetValues(shellWidget, args, i);
6800 DisplayError(message, error)
6807 if (appData.debugMode || appData.matchMode) {
6808 fprintf(stderr, "%s: %s\n", programName, message);
6811 if (appData.debugMode || appData.matchMode) {
6812 fprintf(stderr, "%s: %s: %s\n",
6813 programName, message, strerror(error));
6815 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6818 ErrorPopUp(_("Error"), message, FALSE);
6822 void DisplayMoveError(message)
6827 DrawPosition(FALSE, NULL);
6828 if (appData.debugMode || appData.matchMode) {
6829 fprintf(stderr, "%s: %s\n", programName, message);
6831 if (appData.popupMoveErrors) {
6832 ErrorPopUp(_("Error"), message, FALSE);
6834 DisplayMessage(message, "");
6839 void DisplayFatalError(message, error, status)
6845 errorExitStatus = status;
6847 fprintf(stderr, "%s: %s\n", programName, message);
6849 fprintf(stderr, "%s: %s: %s\n",
6850 programName, message, strerror(error));
6851 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6854 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
6855 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
6861 void DisplayInformation(message)
6865 ErrorPopUp(_("Information"), message, TRUE);
6868 void DisplayNote(message)
6872 ErrorPopUp(_("Note"), message, FALSE);
6876 NullXErrorCheck(dpy, error_event)
6878 XErrorEvent *error_event;
6883 void DisplayIcsInteractionTitle(message)
6886 if (oldICSInteractionTitle == NULL) {
6887 /* Magic to find the old window title, adapted from vim */
6888 char *wina = getenv("WINDOWID");
6890 Window win = (Window) atoi(wina);
6891 Window root, parent, *children;
6892 unsigned int nchildren;
6893 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
6895 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
6896 if (!XQueryTree(xDisplay, win, &root, &parent,
6897 &children, &nchildren)) break;
6898 if (children) XFree((void *)children);
6899 if (parent == root || parent == 0) break;
6902 XSetErrorHandler(oldHandler);
6904 if (oldICSInteractionTitle == NULL) {
6905 oldICSInteractionTitle = "xterm";
6908 printf("\033]0;%s\007", message);
6912 char pendingReplyPrefix[MSG_SIZ];
6913 ProcRef pendingReplyPR;
6915 void AskQuestionProc(w, event, prms, nprms)
6922 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
6926 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
6929 void AskQuestionPopDown()
6931 if (!askQuestionUp) return;
6932 XtPopdown(askQuestionShell);
6933 XtDestroyWidget(askQuestionShell);
6934 askQuestionUp = False;
6937 void AskQuestionReplyAction(w, event, prms, nprms)
6947 reply = XawDialogGetValueString(w = XtParent(w));
6948 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
6949 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
6950 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
6951 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
6952 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
6953 AskQuestionPopDown();
6955 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
6958 void AskQuestionCallback(w, client_data, call_data)
6960 XtPointer client_data, call_data;
6965 XtSetArg(args[0], XtNlabel, &name);
6966 XtGetValues(w, args, 1);
6968 if (strcmp(name, _("cancel")) == 0) {
6969 AskQuestionPopDown();
6971 AskQuestionReplyAction(w, NULL, NULL, NULL);
6975 void AskQuestion(title, question, replyPrefix, pr)
6976 char *title, *question, *replyPrefix;
6980 Widget popup, layout, dialog, edit;
6986 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
6987 pendingReplyPR = pr;
6990 XtSetArg(args[i], XtNresizable, True); i++;
6991 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
6992 askQuestionShell = popup =
6993 XtCreatePopupShell(title, transientShellWidgetClass,
6994 shellWidget, args, i);
6997 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
6998 layoutArgs, XtNumber(layoutArgs));
7001 XtSetArg(args[i], XtNlabel, question); i++;
7002 XtSetArg(args[i], XtNvalue, ""); i++;
7003 XtSetArg(args[i], XtNborderWidth, 0); i++;
7004 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7007 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7008 (XtPointer) dialog);
7009 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7010 (XtPointer) dialog);
7012 XtRealizeWidget(popup);
7013 CatchDeleteWindow(popup, "AskQuestionPopDown");
7015 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7016 &x, &y, &win_x, &win_y, &mask);
7018 XtSetArg(args[0], XtNx, x - 10);
7019 XtSetArg(args[1], XtNy, y - 30);
7020 XtSetValues(popup, args, 2);
7022 XtPopup(popup, XtGrabExclusive);
7023 askQuestionUp = True;
7025 edit = XtNameToWidget(dialog, "*value");
7026 XtSetKeyboardFocus(popup, edit);
7034 if (*name == NULLCHAR) {
7036 } else if (strcmp(name, "$") == 0) {
7037 putc(BELLCHAR, stderr);
7040 char *prefix = "", *sep = "";
7041 if(!strchr(name, '/')) { prefix = appData.soundDirectory; sep = "/"; }
7042 snprintf(buf, sizeof(buf), "%s '%s%s%s' &", appData.soundProgram, prefix, sep, name);
7050 PlaySound(appData.soundMove);
7056 PlaySound(appData.soundIcsWin);
7062 PlaySound(appData.soundIcsLoss);
7068 PlaySound(appData.soundIcsDraw);
7072 PlayIcsUnfinishedSound()
7074 PlaySound(appData.soundIcsUnfinished);
7080 PlaySound(appData.soundIcsAlarm);
7086 system("stty echo");
7092 system("stty -echo");
7096 Colorize(cc, continuation)
7101 int count, outCount, error;
7103 if (textColors[(int)cc].bg > 0) {
7104 if (textColors[(int)cc].fg > 0) {
7105 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7106 textColors[(int)cc].fg, textColors[(int)cc].bg);
7108 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7109 textColors[(int)cc].bg);
7112 if (textColors[(int)cc].fg > 0) {
7113 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7114 textColors[(int)cc].fg);
7116 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7119 count = strlen(buf);
7120 outCount = OutputToProcess(NoProc, buf, count, &error);
7121 if (outCount < count) {
7122 DisplayFatalError(_("Error writing to display"), error, 1);
7125 if (continuation) return;
7128 PlaySound(appData.soundShout);
7131 PlaySound(appData.soundSShout);
7134 PlaySound(appData.soundChannel1);
7137 PlaySound(appData.soundChannel);
7140 PlaySound(appData.soundKibitz);
7143 PlaySound(appData.soundTell);
7145 case ColorChallenge:
7146 PlaySound(appData.soundChallenge);
7149 PlaySound(appData.soundRequest);
7152 PlaySound(appData.soundSeek);
7163 return getpwuid(getuid())->pw_name;
7167 ExpandPathName(path)
7170 static char static_buf[4*MSG_SIZ];
7171 char *d, *s, buf[4*MSG_SIZ];
7177 while (*s && isspace(*s))
7186 if (*(s+1) == '/') {
7187 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7191 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7192 { char *p; if(p = strchr(buf, '/')) *p = 0; }
7193 pwd = getpwnam(buf);
7196 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7200 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7201 strcat(d, strchr(s+1, '/'));
7205 safeStrCpy(d, s, 4*MSG_SIZ );
7212 static char host_name[MSG_SIZ];
7214 #if HAVE_GETHOSTNAME
7215 gethostname(host_name, MSG_SIZ);
7217 #else /* not HAVE_GETHOSTNAME */
7218 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7219 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7221 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7223 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7224 #endif /* not HAVE_GETHOSTNAME */
7227 XtIntervalId delayedEventTimerXID = 0;
7228 DelayedEventCallback delayedEventCallback = 0;
7233 delayedEventTimerXID = 0;
7234 delayedEventCallback();
7238 ScheduleDelayedEvent(cb, millisec)
7239 DelayedEventCallback cb; long millisec;
7241 if(delayedEventTimerXID && delayedEventCallback == cb)
7242 // [HGM] alive: replace, rather than add or flush identical event
7243 XtRemoveTimeOut(delayedEventTimerXID);
7244 delayedEventCallback = cb;
7245 delayedEventTimerXID =
7246 XtAppAddTimeOut(appContext, millisec,
7247 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7250 DelayedEventCallback
7253 if (delayedEventTimerXID) {
7254 return delayedEventCallback;
7261 CancelDelayedEvent()
7263 if (delayedEventTimerXID) {
7264 XtRemoveTimeOut(delayedEventTimerXID);
7265 delayedEventTimerXID = 0;
7269 XtIntervalId loadGameTimerXID = 0;
7271 int LoadGameTimerRunning()
7273 return loadGameTimerXID != 0;
7276 int StopLoadGameTimer()
7278 if (loadGameTimerXID != 0) {
7279 XtRemoveTimeOut(loadGameTimerXID);
7280 loadGameTimerXID = 0;
7288 LoadGameTimerCallback(arg, id)
7292 loadGameTimerXID = 0;
7297 StartLoadGameTimer(millisec)
7301 XtAppAddTimeOut(appContext, millisec,
7302 (XtTimerCallbackProc) LoadGameTimerCallback,
7306 XtIntervalId analysisClockXID = 0;
7309 AnalysisClockCallback(arg, id)
7313 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7314 || appData.icsEngineAnalyze) { // [DM]
7315 AnalysisPeriodicEvent(0);
7316 StartAnalysisClock();
7321 StartAnalysisClock()
7324 XtAppAddTimeOut(appContext, 2000,
7325 (XtTimerCallbackProc) AnalysisClockCallback,
7329 XtIntervalId clockTimerXID = 0;
7331 int ClockTimerRunning()
7333 return clockTimerXID != 0;
7336 int StopClockTimer()
7338 if (clockTimerXID != 0) {
7339 XtRemoveTimeOut(clockTimerXID);
7348 ClockTimerCallback(arg, id)
7357 StartClockTimer(millisec)
7361 XtAppAddTimeOut(appContext, millisec,
7362 (XtTimerCallbackProc) ClockTimerCallback,
7367 DisplayTimerLabel(w, color, timer, highlight)
7376 /* check for low time warning */
7377 Pixel foregroundOrWarningColor = timerForegroundPixel;
7380 appData.lowTimeWarning &&
7381 (timer / 1000) < appData.icsAlarmTime)
7382 foregroundOrWarningColor = lowTimeWarningColor;
7384 if (appData.clockMode) {
7385 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7386 XtSetArg(args[0], XtNlabel, buf);
7388 snprintf(buf, MSG_SIZ, "%s ", color);
7389 XtSetArg(args[0], XtNlabel, buf);
7394 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7395 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7397 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7398 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7401 XtSetValues(w, args, 3);
7405 DisplayWhiteClock(timeRemaining, highlight)
7411 if(appData.noGUI) return;
7412 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7413 if (highlight && iconPixmap == bIconPixmap) {
7414 iconPixmap = wIconPixmap;
7415 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7416 XtSetValues(shellWidget, args, 1);
7421 DisplayBlackClock(timeRemaining, highlight)
7427 if(appData.noGUI) return;
7428 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7429 if (highlight && iconPixmap == wIconPixmap) {
7430 iconPixmap = bIconPixmap;
7431 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7432 XtSetValues(shellWidget, args, 1);
7450 int StartChildProcess(cmdLine, dir, pr)
7457 int to_prog[2], from_prog[2];
7461 if (appData.debugMode) {
7462 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7465 /* We do NOT feed the cmdLine to the shell; we just
7466 parse it into blank-separated arguments in the
7467 most simple-minded way possible.
7470 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7473 while(*p == ' ') p++;
7475 if(*p == '"' || *p == '\'')
7476 p = strchr(++argv[i-1], *p);
7477 else p = strchr(p, ' ');
7478 if (p == NULL) break;
7483 SetUpChildIO(to_prog, from_prog);
7485 if ((pid = fork()) == 0) {
7487 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7488 close(to_prog[1]); // first close the unused pipe ends
7489 close(from_prog[0]);
7490 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7491 dup2(from_prog[1], 1);
7492 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7493 close(from_prog[1]); // and closing again loses one of the pipes!
7494 if(fileno(stderr) >= 2) // better safe than sorry...
7495 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7497 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7502 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7504 execvp(argv[0], argv);
7506 /* If we get here, exec failed */
7511 /* Parent process */
7513 close(from_prog[1]);
7515 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7518 cp->fdFrom = from_prog[0];
7519 cp->fdTo = to_prog[1];
7524 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7525 static RETSIGTYPE AlarmCallBack(int n)
7531 DestroyChildProcess(pr, signalType)
7535 ChildProc *cp = (ChildProc *) pr;
7537 if (cp->kind != CPReal) return;
7539 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7540 signal(SIGALRM, AlarmCallBack);
7542 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7543 kill(cp->pid, SIGKILL); // kill it forcefully
7544 wait((int *) 0); // and wait again
7548 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7550 /* Process is exiting either because of the kill or because of
7551 a quit command sent by the backend; either way, wait for it to die.
7560 InterruptChildProcess(pr)
7563 ChildProc *cp = (ChildProc *) pr;
7565 if (cp->kind != CPReal) return;
7566 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7569 int OpenTelnet(host, port, pr)
7574 char cmdLine[MSG_SIZ];
7576 if (port[0] == NULLCHAR) {
7577 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7579 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7581 return StartChildProcess(cmdLine, "", pr);
7584 int OpenTCP(host, port, pr)
7590 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7591 #else /* !OMIT_SOCKETS */
7593 struct sockaddr_in sa;
7595 unsigned short uport;
7598 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7602 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7603 sa.sin_family = AF_INET;
7604 sa.sin_addr.s_addr = INADDR_ANY;
7605 uport = (unsigned short) 0;
7606 sa.sin_port = htons(uport);
7607 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7611 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7612 if (!(hp = gethostbyname(host))) {
7614 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7615 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7616 hp->h_addrtype = AF_INET;
7618 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7619 hp->h_addr_list[0] = (char *) malloc(4);
7620 hp->h_addr_list[0][0] = b0;
7621 hp->h_addr_list[0][1] = b1;
7622 hp->h_addr_list[0][2] = b2;
7623 hp->h_addr_list[0][3] = b3;
7628 sa.sin_family = hp->h_addrtype;
7629 uport = (unsigned short) atoi(port);
7630 sa.sin_port = htons(uport);
7631 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7633 if (connect(s, (struct sockaddr *) &sa,
7634 sizeof(struct sockaddr_in)) < 0) {
7638 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7645 #endif /* !OMIT_SOCKETS */
7650 int OpenCommPort(name, pr)
7657 fd = open(name, 2, 0);
7658 if (fd < 0) return errno;
7660 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7670 int OpenLoopback(pr)
7676 SetUpChildIO(to, from);
7678 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7681 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7688 int OpenRcmd(host, user, cmd, pr)
7689 char *host, *user, *cmd;
7692 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7696 #define INPUT_SOURCE_BUF_SIZE 8192
7705 char buf[INPUT_SOURCE_BUF_SIZE];
7710 DoInputCallback(closure, source, xid)
7715 InputSource *is = (InputSource *) closure;
7720 if (is->lineByLine) {
7721 count = read(is->fd, is->unused,
7722 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7724 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7727 is->unused += count;
7729 while (p < is->unused) {
7730 q = memchr(p, '\n', is->unused - p);
7731 if (q == NULL) break;
7733 (is->func)(is, is->closure, p, q - p, 0);
7737 while (p < is->unused) {
7742 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
7747 (is->func)(is, is->closure, is->buf, count, error);
7751 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
7758 ChildProc *cp = (ChildProc *) pr;
7760 is = (InputSource *) calloc(1, sizeof(InputSource));
7761 is->lineByLine = lineByLine;
7765 is->fd = fileno(stdin);
7767 is->kind = cp->kind;
7768 is->fd = cp->fdFrom;
7771 is->unused = is->buf;
7774 is->xid = XtAppAddInput(appContext, is->fd,
7775 (XtPointer) (XtInputReadMask),
7776 (XtInputCallbackProc) DoInputCallback,
7778 is->closure = closure;
7779 return (InputSourceRef) is;
7783 RemoveInputSource(isr)
7786 InputSource *is = (InputSource *) isr;
7788 if (is->xid == 0) return;
7789 XtRemoveInput(is->xid);
7793 int OutputToProcess(pr, message, count, outError)
7799 static int line = 0;
7800 ChildProc *cp = (ChildProc *) pr;
7805 if (appData.noJoin || !appData.useInternalWrap)
7806 outCount = fwrite(message, 1, count, stdout);
7809 int width = get_term_width();
7810 int len = wrap(NULL, message, count, width, &line);
7811 char *msg = malloc(len);
7815 outCount = fwrite(message, 1, count, stdout);
7818 dbgchk = wrap(msg, message, count, width, &line);
7819 if (dbgchk != len && appData.debugMode)
7820 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
7821 outCount = fwrite(msg, 1, dbgchk, stdout);
7827 outCount = write(cp->fdTo, message, count);
7837 /* Output message to process, with "ms" milliseconds of delay
7838 between each character. This is needed when sending the logon
7839 script to ICC, which for some reason doesn't like the
7840 instantaneous send. */
7841 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
7848 ChildProc *cp = (ChildProc *) pr;
7853 r = write(cp->fdTo, message++, 1);
7866 /**** Animation code by Hugh Fisher, DCS, ANU.
7868 Known problem: if a window overlapping the board is
7869 moved away while a piece is being animated underneath,
7870 the newly exposed area won't be updated properly.
7871 I can live with this.
7873 Known problem: if you look carefully at the animation
7874 of pieces in mono mode, they are being drawn as solid
7875 shapes without interior detail while moving. Fixing
7876 this would be a major complication for minimal return.
7879 /* Masks for XPM pieces. Black and white pieces can have
7880 different shapes, but in the interest of retaining my
7881 sanity pieces must have the same outline on both light
7882 and dark squares, and all pieces must use the same
7883 background square colors/images. */
7885 static int xpmDone = 0;
7888 CreateAnimMasks (pieceDepth)
7895 unsigned long plane;
7898 /* Need a bitmap just to get a GC with right depth */
7899 buf = XCreatePixmap(xDisplay, xBoardWindow,
7901 values.foreground = 1;
7902 values.background = 0;
7903 /* Don't use XtGetGC, not read only */
7904 maskGC = XCreateGC(xDisplay, buf,
7905 GCForeground | GCBackground, &values);
7906 XFreePixmap(xDisplay, buf);
7908 buf = XCreatePixmap(xDisplay, xBoardWindow,
7909 squareSize, squareSize, pieceDepth);
7910 values.foreground = XBlackPixel(xDisplay, xScreen);
7911 values.background = XWhitePixel(xDisplay, xScreen);
7912 bufGC = XCreateGC(xDisplay, buf,
7913 GCForeground | GCBackground, &values);
7915 for (piece = WhitePawn; piece <= BlackKing; piece++) {
7916 /* Begin with empty mask */
7917 if(!xpmDone) // [HGM] pieces: keep using existing
7918 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
7919 squareSize, squareSize, 1);
7920 XSetFunction(xDisplay, maskGC, GXclear);
7921 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
7922 0, 0, squareSize, squareSize);
7924 /* Take a copy of the piece */
7929 XSetFunction(xDisplay, bufGC, GXcopy);
7930 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
7932 0, 0, squareSize, squareSize, 0, 0);
7934 /* XOR the background (light) over the piece */
7935 XSetFunction(xDisplay, bufGC, GXxor);
7937 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
7938 0, 0, squareSize, squareSize, 0, 0);
7940 XSetForeground(xDisplay, bufGC, lightSquareColor);
7941 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
7944 /* We now have an inverted piece image with the background
7945 erased. Construct mask by just selecting all the non-zero
7946 pixels - no need to reconstruct the original image. */
7947 XSetFunction(xDisplay, maskGC, GXor);
7949 /* Might be quicker to download an XImage and create bitmap
7950 data from it rather than this N copies per piece, but it
7951 only takes a fraction of a second and there is a much
7952 longer delay for loading the pieces. */
7953 for (n = 0; n < pieceDepth; n ++) {
7954 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
7955 0, 0, squareSize, squareSize,
7961 XFreePixmap(xDisplay, buf);
7962 XFreeGC(xDisplay, bufGC);
7963 XFreeGC(xDisplay, maskGC);
7967 InitAnimState (anim, info)
7969 XWindowAttributes * info;
7974 /* Each buffer is square size, same depth as window */
7975 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
7976 squareSize, squareSize, info->depth);
7977 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
7978 squareSize, squareSize, info->depth);
7980 /* Create a plain GC for blitting */
7981 mask = GCForeground | GCBackground | GCFunction |
7982 GCPlaneMask | GCGraphicsExposures;
7983 values.foreground = XBlackPixel(xDisplay, xScreen);
7984 values.background = XWhitePixel(xDisplay, xScreen);
7985 values.function = GXcopy;
7986 values.plane_mask = AllPlanes;
7987 values.graphics_exposures = False;
7988 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
7990 /* Piece will be copied from an existing context at
7991 the start of each new animation/drag. */
7992 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
7994 /* Outline will be a read-only copy of an existing */
7995 anim->outlineGC = None;
8001 XWindowAttributes info;
8003 if (xpmDone && gameInfo.variant == oldVariant) return;
8004 if(xpmDone) oldVariant = gameInfo.variant; // first time pieces might not be created yet
8005 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8007 InitAnimState(&game, &info);
8008 InitAnimState(&player, &info);
8010 /* For XPM pieces, we need bitmaps to use as masks. */
8012 CreateAnimMasks(info.depth);
8018 static Boolean frameWaiting;
8020 static RETSIGTYPE FrameAlarm (sig)
8023 frameWaiting = False;
8024 /* In case System-V style signals. Needed?? */
8025 signal(SIGALRM, FrameAlarm);
8032 struct itimerval delay;
8034 XSync(xDisplay, False);
8037 frameWaiting = True;
8038 signal(SIGALRM, FrameAlarm);
8039 delay.it_interval.tv_sec =
8040 delay.it_value.tv_sec = time / 1000;
8041 delay.it_interval.tv_usec =
8042 delay.it_value.tv_usec = (time % 1000) * 1000;
8043 setitimer(ITIMER_REAL, &delay, NULL);
8044 while (frameWaiting) pause();
8045 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8046 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8047 setitimer(ITIMER_REAL, &delay, NULL);
8057 XSync(xDisplay, False);
8059 usleep(time * 1000);
8064 /* Convert board position to corner of screen rect and color */
8067 ScreenSquare(column, row, pt, color)
8068 int column; int row; XPoint * pt; int * color;
8071 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8072 pt->y = lineGap + row * (squareSize + lineGap);
8074 pt->x = lineGap + column * (squareSize + lineGap);
8075 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8077 *color = SquareColor(row, column);
8080 /* Convert window coords to square */
8083 BoardSquare(x, y, column, row)
8084 int x; int y; int * column; int * row;
8086 *column = EventToSquare(x, BOARD_WIDTH);
8087 if (flipView && *column >= 0)
8088 *column = BOARD_WIDTH - 1 - *column;
8089 *row = EventToSquare(y, BOARD_HEIGHT);
8090 if (!flipView && *row >= 0)
8091 *row = BOARD_HEIGHT - 1 - *row;
8096 #undef Max /* just in case */
8098 #define Max(a, b) ((a) > (b) ? (a) : (b))
8099 #define Min(a, b) ((a) < (b) ? (a) : (b))
8102 SetRect(rect, x, y, width, height)
8103 XRectangle * rect; int x; int y; int width; int height;
8107 rect->width = width;
8108 rect->height = height;
8111 /* Test if two frames overlap. If they do, return
8112 intersection rect within old and location of
8113 that rect within new. */
8116 Intersect(old, new, size, area, pt)
8117 XPoint * old; XPoint * new;
8118 int size; XRectangle * area; XPoint * pt;
8120 if (old->x > new->x + size || new->x > old->x + size ||
8121 old->y > new->y + size || new->y > old->y + size) {
8124 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8125 size - abs(old->x - new->x), size - abs(old->y - new->y));
8126 pt->x = Max(old->x - new->x, 0);
8127 pt->y = Max(old->y - new->y, 0);
8132 /* For two overlapping frames, return the rect(s)
8133 in the old that do not intersect with the new. */
8136 CalcUpdateRects(old, new, size, update, nUpdates)
8137 XPoint * old; XPoint * new; int size;
8138 XRectangle update[]; int * nUpdates;
8142 /* If old = new (shouldn't happen) then nothing to draw */
8143 if (old->x == new->x && old->y == new->y) {
8147 /* Work out what bits overlap. Since we know the rects
8148 are the same size we don't need a full intersect calc. */
8150 /* Top or bottom edge? */
8151 if (new->y > old->y) {
8152 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8154 } else if (old->y > new->y) {
8155 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8156 size, old->y - new->y);
8159 /* Left or right edge - don't overlap any update calculated above. */
8160 if (new->x > old->x) {
8161 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8162 new->x - old->x, size - abs(new->y - old->y));
8164 } else if (old->x > new->x) {
8165 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8166 old->x - new->x, size - abs(new->y - old->y));
8173 /* Generate a series of frame coords from start->mid->finish.
8174 The movement rate doubles until the half way point is
8175 reached, then halves back down to the final destination,
8176 which gives a nice slow in/out effect. The algorithmn
8177 may seem to generate too many intermediates for short
8178 moves, but remember that the purpose is to attract the
8179 viewers attention to the piece about to be moved and
8180 then to where it ends up. Too few frames would be less
8184 Tween(start, mid, finish, factor, frames, nFrames)
8185 XPoint * start; XPoint * mid;
8186 XPoint * finish; int factor;
8187 XPoint frames[]; int * nFrames;
8189 int fraction, n, count;
8193 /* Slow in, stepping 1/16th, then 1/8th, ... */
8195 for (n = 0; n < factor; n++)
8197 for (n = 0; n < factor; n++) {
8198 frames[count].x = start->x + (mid->x - start->x) / fraction;
8199 frames[count].y = start->y + (mid->y - start->y) / fraction;
8201 fraction = fraction / 2;
8205 frames[count] = *mid;
8208 /* Slow out, stepping 1/2, then 1/4, ... */
8210 for (n = 0; n < factor; n++) {
8211 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8212 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8214 fraction = fraction * 2;
8219 /* Draw a piece on the screen without disturbing what's there */
8222 SelectGCMask(piece, clip, outline, mask)
8223 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8227 /* Bitmap for piece being moved. */
8228 if (appData.monoMode) {
8229 *mask = *pieceToSolid(piece);
8230 } else if (useImages) {
8232 *mask = xpmMask[piece];
8234 *mask = ximMaskPm[piece];
8237 *mask = *pieceToSolid(piece);
8240 /* GC for piece being moved. Square color doesn't matter, but
8241 since it gets modified we make a copy of the original. */
8243 if (appData.monoMode)
8248 if (appData.monoMode)
8253 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8255 /* Outline only used in mono mode and is not modified */
8257 *outline = bwPieceGC;
8259 *outline = wbPieceGC;
8263 OverlayPiece(piece, clip, outline, dest)
8264 ChessSquare piece; GC clip; GC outline; Drawable dest;
8269 /* Draw solid rectangle which will be clipped to shape of piece */
8270 XFillRectangle(xDisplay, dest, clip,
8271 0, 0, squareSize, squareSize);
8272 if (appData.monoMode)
8273 /* Also draw outline in contrasting color for black
8274 on black / white on white cases */
8275 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8276 0, 0, squareSize, squareSize, 0, 0, 1);
8278 /* Copy the piece */
8283 if(appData.upsideDown && flipView) kind ^= 2;
8284 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8286 0, 0, squareSize, squareSize,
8291 /* Animate the movement of a single piece */
8294 BeginAnimation(anim, piece, startColor, start)
8302 if(appData.upsideDown && flipView) piece += piece < BlackPawn ? BlackPawn : -BlackPawn;
8303 /* The old buffer is initialised with the start square (empty) */
8304 BlankSquare(start->x, start->y, startColor, EmptySquare, anim->saveBuf, 0);
8305 anim->prevFrame = *start;
8307 /* The piece will be drawn using its own bitmap as a matte */
8308 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8309 XSetClipMask(xDisplay, anim->pieceGC, mask);
8313 AnimationFrame(anim, frame, piece)
8318 XRectangle updates[4];
8323 /* Save what we are about to draw into the new buffer */
8324 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8325 frame->x, frame->y, squareSize, squareSize,
8328 /* Erase bits of the previous frame */
8329 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8330 /* Where the new frame overlapped the previous,
8331 the contents in newBuf are wrong. */
8332 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8333 overlap.x, overlap.y,
8334 overlap.width, overlap.height,
8336 /* Repaint the areas in the old that don't overlap new */
8337 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8338 for (i = 0; i < count; i++)
8339 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8340 updates[i].x - anim->prevFrame.x,
8341 updates[i].y - anim->prevFrame.y,
8342 updates[i].width, updates[i].height,
8343 updates[i].x, updates[i].y);
8345 /* Easy when no overlap */
8346 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8347 0, 0, squareSize, squareSize,
8348 anim->prevFrame.x, anim->prevFrame.y);
8351 /* Save this frame for next time round */
8352 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8353 0, 0, squareSize, squareSize,
8355 anim->prevFrame = *frame;
8357 /* Draw piece over original screen contents, not current,
8358 and copy entire rect. Wipes out overlapping piece images. */
8359 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8360 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8361 0, 0, squareSize, squareSize,
8362 frame->x, frame->y);
8366 EndAnimation (anim, finish)
8370 XRectangle updates[4];
8375 /* The main code will redraw the final square, so we
8376 only need to erase the bits that don't overlap. */
8377 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8378 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8379 for (i = 0; i < count; i++)
8380 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8381 updates[i].x - anim->prevFrame.x,
8382 updates[i].y - anim->prevFrame.y,
8383 updates[i].width, updates[i].height,
8384 updates[i].x, updates[i].y);
8386 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8387 0, 0, squareSize, squareSize,
8388 anim->prevFrame.x, anim->prevFrame.y);
8393 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8395 ChessSquare piece; int startColor;
8396 XPoint * start; XPoint * finish;
8397 XPoint frames[]; int nFrames;
8401 BeginAnimation(anim, piece, startColor, start);
8402 for (n = 0; n < nFrames; n++) {
8403 AnimationFrame(anim, &(frames[n]), piece);
8404 FrameDelay(appData.animSpeed);
8406 EndAnimation(anim, finish);
8410 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
8413 ChessSquare piece = board[fromY][toY];
8414 board[fromY][toY] = EmptySquare;
8415 DrawPosition(FALSE, board);
8417 x = lineGap + ((BOARD_WIDTH-1)-toX) * (squareSize + lineGap);
8418 y = lineGap + toY * (squareSize + lineGap);
8420 x = lineGap + toX * (squareSize + lineGap);
8421 y = lineGap + ((BOARD_HEIGHT-1)-toY) * (squareSize + lineGap);
8423 for(i=1; i<4*kFactor; i++) {
8424 int r = squareSize * 9 * i/(20*kFactor - 5);
8425 XFillArc(xDisplay, xBoardWindow, highlineGC,
8426 x + squareSize/2 - r, y+squareSize/2 - r, 2*r, 2*r, 0, 64*360);
8427 FrameDelay(appData.animSpeed);
8429 board[fromY][toY] = piece;
8432 /* Main control logic for deciding what to animate and how */
8435 AnimateMove(board, fromX, fromY, toX, toY)
8444 XPoint start, finish, mid;
8445 XPoint frames[kFactor * 2 + 1];
8446 int nFrames, startColor, endColor;
8448 /* Are we animating? */
8449 if (!appData.animate || appData.blindfold)
8452 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8453 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8454 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8456 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8457 piece = board[fromY][fromX];
8458 if (piece >= EmptySquare) return;
8463 hop = abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1;
8466 if (appData.debugMode) {
8467 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8468 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8469 piece, fromX, fromY, toX, toY); }
8471 ScreenSquare(fromX, fromY, &start, &startColor);
8472 ScreenSquare(toX, toY, &finish, &endColor);
8475 /* Knight: make straight movement then diagonal */
8476 if (abs(toY - fromY) < abs(toX - fromX)) {
8477 mid.x = start.x + (finish.x - start.x) / 2;
8481 mid.y = start.y + (finish.y - start.y) / 2;
8484 mid.x = start.x + (finish.x - start.x) / 2;
8485 mid.y = start.y + (finish.y - start.y) / 2;
8488 /* Don't use as many frames for very short moves */
8489 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8490 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8492 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8493 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8494 if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged
8496 for(i=0; i<BOARD_WIDTH; i++) for(j=0; j<BOARD_HEIGHT; j++)
8497 if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] = True;
8500 /* Be sure end square is redrawn */
8501 damage[0][toY][toX] = True;
8505 DragPieceBegin(x, y)
8508 int boardX, boardY, color;
8511 /* Are we animating? */
8512 if (!appData.animateDragging || appData.blindfold)
8515 /* Figure out which square we start in and the
8516 mouse position relative to top left corner. */
8517 BoardSquare(x, y, &boardX, &boardY);
8518 player.startBoardX = boardX;
8519 player.startBoardY = boardY;
8520 ScreenSquare(boardX, boardY, &corner, &color);
8521 player.startSquare = corner;
8522 player.startColor = color;
8523 /* As soon as we start dragging, the piece will jump slightly to
8524 be centered over the mouse pointer. */
8525 player.mouseDelta.x = squareSize/2;
8526 player.mouseDelta.y = squareSize/2;
8527 /* Initialise animation */
8528 player.dragPiece = PieceForSquare(boardX, boardY);
8530 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8531 player.dragActive = True;
8532 BeginAnimation(&player, player.dragPiece, color, &corner);
8533 /* Mark this square as needing to be redrawn. Note that
8534 we don't remove the piece though, since logically (ie
8535 as seen by opponent) the move hasn't been made yet. */
8536 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8537 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8538 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8539 corner.x, corner.y, squareSize, squareSize,
8540 0, 0); // [HGM] zh: unstack in stead of grab
8541 if(gatingPiece != EmptySquare) {
8542 /* Kludge alert: When gating we want the introduced
8543 piece to appear on the from square. To generate an
8544 image of it, we draw it on the board, copy the image,
8545 and draw the original piece again. */
8546 ChessSquare piece = boards[currentMove][boardY][boardX];
8547 DrawSquare(boardY, boardX, gatingPiece, 0);
8548 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8549 corner.x, corner.y, squareSize, squareSize, 0, 0);
8550 DrawSquare(boardY, boardX, piece, 0);
8552 damage[0][boardY][boardX] = True;
8554 player.dragActive = False;
8559 ChangeDragPiece(ChessSquare piece)
8562 player.dragPiece = piece;
8563 /* The piece will be drawn using its own bitmap as a matte */
8564 SelectGCMask(piece, &player.pieceGC, &player.outlineGC, &mask);
8565 XSetClipMask(xDisplay, player.pieceGC, mask);
8574 /* Are we animating? */
8575 if (!appData.animateDragging || appData.blindfold)
8579 if (! player.dragActive)
8581 /* Move piece, maintaining same relative position
8582 of mouse within square */
8583 corner.x = x - player.mouseDelta.x;
8584 corner.y = y - player.mouseDelta.y;
8585 AnimationFrame(&player, &corner, player.dragPiece);
8587 if (appData.highlightDragging) {
8589 BoardSquare(x, y, &boardX, &boardY);
8590 SetHighlights(fromX, fromY, boardX, boardY);
8599 int boardX, boardY, color;
8602 /* Are we animating? */
8603 if (!appData.animateDragging || appData.blindfold)
8607 if (! player.dragActive)
8609 /* Last frame in sequence is square piece is
8610 placed on, which may not match mouse exactly. */
8611 BoardSquare(x, y, &boardX, &boardY);
8612 ScreenSquare(boardX, boardY, &corner, &color);
8613 EndAnimation(&player, &corner);
8615 /* Be sure end square is redrawn */
8616 damage[0][boardY][boardX] = True;
8618 /* This prevents weird things happening with fast successive
8619 clicks which on my Sun at least can cause motion events
8620 without corresponding press/release. */
8621 player.dragActive = False;
8624 /* Handle expose event while piece being dragged */
8629 if (!player.dragActive || appData.blindfold)
8632 /* What we're doing: logically, the move hasn't been made yet,
8633 so the piece is still in it's original square. But visually
8634 it's being dragged around the board. So we erase the square
8635 that the piece is on and draw it at the last known drag point. */
8636 BlankSquare(player.startSquare.x, player.startSquare.y,
8637 player.startColor, EmptySquare, xBoardWindow, 1);
8638 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8639 damage[0][player.startBoardY][player.startBoardX] = TRUE;
8642 #include <sys/ioctl.h>
8643 int get_term_width()
8645 int fd, default_width;
8648 default_width = 79; // this is FICS default anyway...
8650 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8652 if (!ioctl(fd, TIOCGSIZE, &win))
8653 default_width = win.ts_cols;
8654 #elif defined(TIOCGWINSZ)
8656 if (!ioctl(fd, TIOCGWINSZ, &win))
8657 default_width = win.ws_col;
8659 return default_width;
8665 static int old_width = 0;
8666 int new_width = get_term_width();
8668 if (old_width != new_width)
8669 ics_printf("set width %d\n", new_width);
8670 old_width = new_width;
8673 void NotifyFrontendLogin()
8678 /* [AS] Arrow highlighting support */
8680 static double A_WIDTH = 5; /* Width of arrow body */
8682 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
8683 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
8685 static double Sqr( double x )
8690 static int Round( double x )
8692 return (int) (x + 0.5);
8695 void SquareToPos(int rank, int file, int *x, int *y)
8698 *x = lineGap + ((BOARD_WIDTH-1)-file) * (squareSize + lineGap);
8699 *y = lineGap + rank * (squareSize + lineGap);
8701 *x = lineGap + file * (squareSize + lineGap);
8702 *y = lineGap + ((BOARD_HEIGHT-1)-rank) * (squareSize + lineGap);
8706 /* Draw an arrow between two points using current settings */
8707 void DrawArrowBetweenPoints( int s_x, int s_y, int d_x, int d_y )
8710 double dx, dy, j, k, x, y;
8713 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
8715 arrow[0].x = s_x + A_WIDTH + 0.5;
8718 arrow[1].x = s_x + A_WIDTH + 0.5;
8719 arrow[1].y = d_y - h;
8721 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8722 arrow[2].y = d_y - h;
8727 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
8728 arrow[5].y = d_y - h;
8730 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8731 arrow[4].y = d_y - h;
8733 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
8736 else if( d_y == s_y ) {
8737 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
8740 arrow[0].y = s_y + A_WIDTH + 0.5;
8742 arrow[1].x = d_x - w;
8743 arrow[1].y = s_y + A_WIDTH + 0.5;
8745 arrow[2].x = d_x - w;
8746 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8751 arrow[5].x = d_x - w;
8752 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
8754 arrow[4].x = d_x - w;
8755 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8758 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
8761 /* [AS] Needed a lot of paper for this! :-) */
8762 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
8763 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
8765 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
8767 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
8772 arrow[0].x = Round(x - j);
8773 arrow[0].y = Round(y + j*dx);
8775 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
8776 arrow[1].y = Round(arrow[0].y - 2*j*dx);
8779 x = (double) d_x - k;
8780 y = (double) d_y - k*dy;
8783 x = (double) d_x + k;
8784 y = (double) d_y + k*dy;
8787 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
8789 arrow[6].x = Round(x - j);
8790 arrow[6].y = Round(y + j*dx);
8792 arrow[2].x = Round(arrow[6].x + 2*j);
8793 arrow[2].y = Round(arrow[6].y - 2*j*dx);
8795 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
8796 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
8801 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
8802 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
8805 XFillPolygon(xDisplay, xBoardWindow, highlineGC, arrow, 7, Nonconvex, CoordModeOrigin);
8806 // Polygon( hdc, arrow, 7 );
8809 /* [AS] Draw an arrow between two squares */
8810 void DrawArrowBetweenSquares( int s_col, int s_row, int d_col, int d_row )
8812 int s_x, s_y, d_x, d_y, hor, vert, i;
8814 if( s_col == d_col && s_row == d_row ) {
8818 /* Get source and destination points */
8819 SquareToPos( s_row, s_col, &s_x, &s_y);
8820 SquareToPos( d_row, d_col, &d_x, &d_y);
8823 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
8825 else if( d_y < s_y ) {
8826 d_y += squareSize / 2 + squareSize / 4;
8829 d_y += squareSize / 2;
8833 d_x += squareSize / 2 - squareSize / 4;
8835 else if( d_x < s_x ) {
8836 d_x += squareSize / 2 + squareSize / 4;
8839 d_x += squareSize / 2;
8842 s_x += squareSize / 2;
8843 s_y += squareSize / 2;
8846 A_WIDTH = squareSize / 14.; //[HGM] make float
8848 DrawArrowBetweenPoints( s_x, s_y, d_x, d_y );
8850 hor = 64*s_col + 32; vert = 64*s_row + 32;
8851 for(i=0; i<= 64; i++) {
8852 damage[0][vert+6>>6][hor+6>>6] = True;
8853 damage[0][vert-6>>6][hor+6>>6] = True;
8854 damage[0][vert+6>>6][hor-6>>6] = True;
8855 damage[0][vert-6>>6][hor-6>>6] = True;
8856 hor += d_col - s_col; vert += d_row - s_row;
8860 Boolean IsDrawArrowEnabled()
8862 return appData.highlightMoveWithArrow && squareSize >= 32;
8865 void DrawArrowHighlight(int fromX, int fromY, int toX,int toY)
8867 if( IsDrawArrowEnabled() && fromX >= 0 && fromY >= 0 && toX >= 0 && toY >= 0)
8868 DrawArrowBetweenSquares(fromX, fromY, toX, toY);