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 HandleUserMove P((Widget w, XEvent *event,
265 String *prms, Cardinal *nprms));
266 void AnimateUserMove P((Widget w, XEvent * event,
267 String * params, Cardinal * nParams));
268 void HandlePV P((Widget w, XEvent * event,
269 String * params, Cardinal * nParams));
270 void SelectPV P((Widget w, XEvent * event,
271 String * params, Cardinal * nParams));
272 void StopPV P((Widget w, XEvent * event,
273 String * params, Cardinal * nParams));
274 void WhiteClock P((Widget w, XEvent *event,
275 String *prms, Cardinal *nprms));
276 void BlackClock P((Widget w, XEvent *event,
277 String *prms, Cardinal *nprms));
278 void DrawPositionProc P((Widget w, XEvent *event,
279 String *prms, Cardinal *nprms));
280 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
282 void CommentClick P((Widget w, XEvent * event,
283 String * params, Cardinal * nParams));
284 void CommentPopUp P((char *title, char *label));
285 void CommentPopDown P((void));
286 void ICSInputBoxPopUp P((void));
287 void ICSInputBoxPopDown P((void));
288 void FileNamePopUp P((char *label, char *def, char *filter,
289 FileProc proc, char *openMode));
290 void FileNamePopDown P((void));
291 void FileNameCallback P((Widget w, XtPointer client_data,
292 XtPointer call_data));
293 void FileNameAction P((Widget w, XEvent *event,
294 String *prms, Cardinal *nprms));
295 void AskQuestionReplyAction P((Widget w, XEvent *event,
296 String *prms, Cardinal *nprms));
297 void AskQuestionProc P((Widget w, XEvent *event,
298 String *prms, Cardinal *nprms));
299 void AskQuestionPopDown P((void));
300 void PromotionPopDown P((void));
301 void PromotionCallback P((Widget w, XtPointer client_data,
302 XtPointer call_data));
303 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
304 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
305 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
306 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
308 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
310 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
312 void LoadPositionProc P((Widget w, XEvent *event,
313 String *prms, Cardinal *nprms));
314 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
316 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
318 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
320 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
322 void PastePositionProc P((Widget w, XEvent *event, String *prms,
324 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
325 void CopyGameListProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
326 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
327 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
328 void SavePositionProc P((Widget w, XEvent *event,
329 String *prms, Cardinal *nprms));
330 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
331 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
333 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
334 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
335 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
337 void MachineWhiteProc P((Widget w, XEvent *event,
338 String *prms, Cardinal *nprms));
339 void AnalyzeModeProc P((Widget w, XEvent *event,
340 String *prms, Cardinal *nprms));
341 void AnalyzeFileProc P((Widget w, XEvent *event,
342 String *prms, Cardinal *nprms));
343 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
345 void MatchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
346 void MatchOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
347 void IcsClientProc P((Widget w, XEvent *event, String *prms,
349 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
350 void EditPositionProc P((Widget w, XEvent *event,
351 String *prms, Cardinal *nprms));
352 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
353 void EditCommentProc P((Widget w, XEvent *event,
354 String *prms, Cardinal *nprms));
355 void IcsInputBoxProc P((Widget w, XEvent *event,
356 String *prms, Cardinal *nprms));
357 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
358 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
359 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
365 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
369 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
370 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
371 void StopObservingProc P((Widget w, XEvent *event, String *prms,
373 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
375 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
376 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
377 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
379 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
380 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
384 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
386 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
387 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
389 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
391 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
393 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
394 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
395 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
396 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
398 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
399 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
401 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
403 void HighlightArrowProc P((Widget w, XEvent *event, String *prms,
405 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
406 //void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
407 void OneClickProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
408 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
410 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
412 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
414 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
416 //void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
417 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
419 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
421 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
423 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
425 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
426 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
427 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
428 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
429 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
430 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
431 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
432 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
433 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
434 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
435 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
436 void DisplayMove P((int moveNumber));
437 void DisplayTitle P((char *title));
438 void ICSInitScript P((void));
439 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
440 void ErrorPopUp P((char *title, char *text, int modal));
441 void ErrorPopDown P((void));
442 static char *ExpandPathName P((char *path));
443 static void CreateAnimVars P((void));
444 static void DragPieceMove P((int x, int y));
445 static void DrawDragPiece P((void));
446 char *ModeToWidgetName P((GameMode mode));
447 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
448 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
449 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
450 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
451 void OptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
452 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
453 void IcsTextProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
454 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
455 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
456 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
457 void IcsOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
458 void SoundOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
459 void BoardOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
460 void LoadOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
461 void SaveOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
462 void GameListOptionsPopDown P(());
463 void ShufflePopDown P(());
464 void TimeControlPopDown P(());
465 void GenericPopDown P(());
466 void update_ics_width P(());
467 int get_term_width P(());
468 int CopyMemoProc P(());
469 void DrawArrowHighlight P((int fromX, int fromY, int toX,int toY));
470 Boolean IsDrawArrowEnabled P(());
473 * XBoard depends on Xt R4 or higher
475 int xtVersion = XtSpecificationRelease;
480 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
481 jailSquareColor, highlightSquareColor, premoveHighlightColor;
482 Pixel lowTimeWarningColor;
483 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
484 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
485 wjPieceGC, bjPieceGC, prelineGC, countGC;
486 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
487 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
488 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
489 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
490 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
491 ICSInputShell, fileNameShell, askQuestionShell;
492 Widget historyShell, evalGraphShell, gameListShell;
493 int hOffset; // [HGM] dual
494 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
495 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
496 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
497 Font clockFontID, coordFontID, countFontID;
498 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
499 XtAppContext appContext;
501 char *oldICSInteractionTitle;
505 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
507 Position commentX = -1, commentY = -1;
508 Dimension commentW, commentH;
509 typedef unsigned int BoardSize;
511 Boolean chessProgram;
513 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
514 int squareSize, smallLayout = 0, tinyLayout = 0,
515 marginW, marginH, // [HGM] for run-time resizing
516 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
517 ICSInputBoxUp = False, askQuestionUp = False,
518 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
519 errorUp = False, errorExitStatus = -1, lineGap, defaultLineGap;
520 Pixel timerForegroundPixel, timerBackgroundPixel;
521 Pixel buttonForegroundPixel, buttonBackgroundPixel;
522 char *chessDir, *programName, *programVersion,
523 *gameCopyFilename, *gamePasteFilename;
524 Boolean alwaysOnTop = False;
525 Boolean saveSettingsOnExit;
526 char *settingsFileName;
527 char *icsTextMenuString;
529 char *firstChessProgramNames;
530 char *secondChessProgramNames;
532 WindowPlacement wpMain;
533 WindowPlacement wpConsole;
534 WindowPlacement wpComment;
535 WindowPlacement wpMoveHistory;
536 WindowPlacement wpEvalGraph;
537 WindowPlacement wpEngineOutput;
538 WindowPlacement wpGameList;
539 WindowPlacement wpTags;
541 extern Widget shells[];
542 extern Boolean shellUp[];
546 Pixmap pieceBitmap[2][(int)BlackPawn];
547 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
548 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
549 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
550 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
551 Pixmap xpmBoardBitmap[2];
552 int useImages, useImageSqs, useTexture, textureW[2], textureH[2];
553 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
554 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
555 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
556 XImage *ximLightSquare, *ximDarkSquare;
559 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
560 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
562 #define White(piece) ((int)(piece) < (int)BlackPawn)
564 /* Variables for doing smooth animation. This whole thing
565 would be much easier if the board was double-buffered,
566 but that would require a fairly major rewrite. */
571 GC blitGC, pieceGC, outlineGC;
572 XPoint startSquare, prevFrame, mouseDelta;
576 int startBoardX, startBoardY;
579 /* There can be two pieces being animated at once: a player
580 can begin dragging a piece before the remote opponent has moved. */
582 static AnimState game, player;
584 /* Bitmaps for use as masks when drawing XPM pieces.
585 Need one for each black and white piece. */
586 static Pixmap xpmMask[BlackKing + 1];
588 /* This magic number is the number of intermediate frames used
589 in each half of the animation. For short moves it's reduced
590 by 1. The total number of frames will be factor * 2 + 1. */
593 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
595 MenuItem fileMenu[] = {
596 {N_("New Game Ctrl+N"), "New Game", ResetProc},
597 {N_("New Shuffle Game ..."), "New Shuffle Game", ShuffleMenuProc},
598 {N_("New Variant ... Alt+Shift+V"), "New Variant", NewVariantProc}, // [HGM] variant: not functional yet
599 {"----", NULL, NothingProc},
600 {N_("Load Game Ctrl+O"), "Load Game", LoadGameProc},
601 {N_("Load Position Ctrl+Shift+O"), "Load Position", LoadPositionProc},
602 // {N_("Load Next Game"), "Load Next Game", LoadNextGameProc},
603 // {N_("Load Previous Game"), "Load Previous Game", LoadPrevGameProc},
604 // {N_("Reload Same Game"), "Reload Same Game", ReloadGameProc},
605 {N_("Next Position Shift+PgDn"), "Load Next Position", LoadNextPositionProc},
606 {N_("Prev Position Shift+PgUp"), "Load Previous Position", LoadPrevPositionProc},
607 {"----", NULL, NothingProc},
608 // {N_("Reload Same Position"), "Reload Same Position", ReloadPositionProc},
609 {N_("Save Game Ctrl+S"), "Save Game", SaveGameProc},
610 {N_("Save Position Ctrl+Shift+S"), "Save Position", SavePositionProc},
611 {"----", NULL, NothingProc},
612 {N_("Mail Move"), "Mail Move", MailMoveProc},
613 {N_("Reload CMail Message"), "Reload CMail Message", ReloadCmailMsgProc},
614 {"----", NULL, NothingProc},
615 {N_("Quit Ctr+Q"), "Exit", QuitProc},
619 MenuItem editMenu[] = {
620 {N_("Copy Game Ctrl+C"), "Copy Game", CopyGameProc},
621 {N_("Copy Position Ctrl+Shift+C"), "Copy Position", CopyPositionProc},
622 {N_("Copy Game List"), "Copy Game List", CopyGameListProc},
623 {"----", NULL, NothingProc},
624 {N_("Paste Game Ctrl+V"), "Paste Game", PasteGameProc},
625 {N_("Paste Position Ctrl+Shift+V"), "Paste Position", PastePositionProc},
626 {"----", NULL, NothingProc},
627 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
628 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
629 {N_("Edit Tags"), "Edit Tags", EditTagsProc},
630 {N_("Edit Comment"), "Edit Comment", EditCommentProc},
631 {"----", NULL, NothingProc},
632 {N_("Revert Home"), "Revert", RevertProc},
633 {N_("Annotate"), "Annotate", AnnotateProc},
634 {N_("Truncate Game End"), "Truncate Game", TruncateGameProc},
635 {"----", NULL, NothingProc},
636 {N_("Backward Alt+Left"), "Backward", BackwardProc},
637 {N_("Forward Alt+Right"), "Forward", ForwardProc},
638 {N_("Back to Start Alt+Home"), "Back to Start", ToStartProc},
639 {N_("Forward to End Alt+End"), "Forward to End", ToEndProc},
643 MenuItem viewMenu[] = {
644 {N_("Flip View F2"), "Flip View", FlipViewProc},
645 {"----", NULL, NothingProc},
646 {N_("Engine Output Alt+Shift+O"), "Show Engine Output", EngineOutputProc},
647 {N_("Move History Alt+Shift+H"), "Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
648 {N_("Evaluation Graph Alt+Shift+E"), "Show Evaluation Graph", EvalGraphProc},
649 {N_("Game List Alt+Shift+G"), "Show Game List", ShowGameListProc},
650 {N_("ICS text menu"), "ICStex", IcsTextProc},
651 {"----", NULL, NothingProc},
652 {N_("Tags"), "Show Tags", EditTagsProc},
653 {N_("Comments"), "Show Comments", EditCommentProc},
654 {N_("ICS Input Box"), "ICS Input Box", IcsInputBoxProc},
655 {"----", NULL, NothingProc},
656 {N_("Board..."), "Board Options", BoardOptionsProc},
657 {N_("Game List Tags..."), "Game List", GameListOptionsPopUp},
661 MenuItem modeMenu[] = {
662 {N_("Machine White Ctrl+W"), "Machine White", MachineWhiteProc},
663 {N_("Machine Black Ctrl+B"), "Machine Black", MachineBlackProc},
664 {N_("Two Machines Ctrl+T"), "Two Machines", TwoMachinesProc},
665 {N_("Analysis Mode Ctrl+A"), "Analysis Mode", AnalyzeModeProc},
666 {N_("Analyze File Ctrl+F"), "Analyze File", AnalyzeFileProc },
667 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
668 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
669 {N_("Training"), "Training", TrainingProc},
670 {N_("ICS Client"), "ICS Client", IcsClientProc},
671 {"----", NULL, NothingProc},
672 {N_("Machine Match"), "Machine Match", MatchProc},
673 {N_("Pause Pause"), "Pause", PauseProc},
677 MenuItem actionMenu[] = {
678 {N_("Accept F3"), "Accept", AcceptProc},
679 {N_("Decline F4"), "Decline", DeclineProc},
680 {N_("Rematch F12"), "Rematch", RematchProc},
681 {"----", NULL, NothingProc},
682 {N_("Call Flag F5"), "Call Flag", CallFlagProc},
683 {N_("Draw F6"), "Draw", DrawProc},
684 {N_("Adjourn F7"), "Adjourn", AdjournProc},
685 {N_("Abort F8"),"Abort", AbortProc},
686 {N_("Resign F9"), "Resign", ResignProc},
687 {"----", NULL, NothingProc},
688 {N_("Stop Observing F10"), "Stop Observing", StopObservingProc},
689 {N_("Stop Examining F11"), "Stop Examining", StopExaminingProc},
690 {N_("Upload to Examine"), "Upload to Examine", UploadProc},
691 {"----", NULL, NothingProc},
692 {N_("Adjudicate to White"), "Adjudicate to White", AdjuWhiteProc},
693 {N_("Adjudicate to Black"), "Adjudicate to Black", AdjuBlackProc},
694 {N_("Adjudicate Draw"), "Adjudicate Draw", AdjuDrawProc},
698 MenuItem engineMenu[] = {
699 {N_("Engine #1 Settings ..."), "Engine #1 Settings", FirstSettingsProc},
700 {N_("Engine #2 Settings ..."), "Engine #2 Settings", SecondSettingsProc},
701 {"----", NULL, NothingProc},
702 {N_("Hint"), "Hint", HintProc},
703 {N_("Book"), "Book", BookProc},
704 {"----", NULL, NothingProc},
705 {N_("Move Now Ctrl+M"), "Move Now", MoveNowProc},
706 {N_("Retract Move Ctrl+X"), "Retract Move", RetractMoveProc},
710 MenuItem optionsMenu[] = {
711 #define OPTIONSDIALOG
713 {N_("General ..."), "General", OptionsProc},
715 {N_("Time Control ... Alt+Shift+T"), "Time Control", TimeControlProc},
716 {N_("Common Engine ... Alt+Shift+U"), "Common Engine", UciMenuProc},
717 {N_("Adjudications ... Alt+Shift+J"), "Adjudications", EngineMenuProc},
718 {N_("ICS ..."), "ICS", IcsOptionsProc},
719 {N_("Match ..."), "Match", MatchOptionsProc},
720 {N_("Load Game ..."), "Load Game", LoadOptionsProc},
721 {N_("Save Game ..."), "Save Game", SaveOptionsProc},
722 // {N_(" ..."), "", OptionsProc},
723 {N_("Game List ..."), "Game List", GameListOptionsPopUp},
724 {N_("Sounds ..."), "Sounds", SoundOptionsProc},
725 {"----", NULL, NothingProc},
726 #ifndef OPTIONSDIALOG
727 {N_("Always Queen Ctrl+Shift+Q"), "Always Queen", AlwaysQueenProc},
728 {N_("Animate Dragging"), "Animate Dragging", AnimateDraggingProc},
729 {N_("Animate Moving Ctrl+Shift+A"), "Animate Moving", AnimateMovingProc},
730 {N_("Auto Flag Ctrl+Shift+F"), "Auto Flag", AutoflagProc},
731 {N_("Auto Flip View"), "Auto Flip View", AutoflipProc},
732 {N_("Blindfold"), "Blindfold", BlindfoldProc},
733 {N_("Flash Moves"), "Flash Moves", FlashMovesProc},
735 {N_("Highlight Dragging"), "Highlight Dragging", HighlightDraggingProc},
737 {N_("Highlight Last Move"), "Highlight Last Move", HighlightLastMoveProc},
738 {N_("Highlight With Arrow"), "Arrow", HighlightArrowProc},
739 {N_("Move Sound"), "Move Sound", MoveSoundProc},
740 // {N_("ICS Alarm"), "ICS Alarm", IcsAlarmProc},
741 {N_("One-Click Moving"), "OneClick", OneClickProc},
742 {N_("Periodic Updates"), "Periodic Updates", PeriodicUpdatesProc},
743 {N_("Ponder Next Move Ctrl+Shift+P"), "Ponder Next Move", PonderNextMoveProc},
744 {N_("Popup Exit Message"), "Popup Exit Message", PopupExitMessageProc},
745 {N_("Popup Move Errors"), "Popup Move Errors", PopupMoveErrorsProc},
746 // {N_("Premove"), "Premove", PremoveProc},
747 {N_("Show Coords"), "Show Coords", ShowCoordsProc},
748 {N_("Hide Thinking Ctrl+Shift+H"), "Hide Thinking", HideThinkingProc},
749 {N_("Test Legality Ctrl+Shift+L"), "Test Legality", TestLegalityProc},
750 {"----", NULL, NothingProc},
752 {N_("Save Settings Now"), "Save Settings Now", SaveSettingsProc},
753 {N_("Save Settings on Exit"), "Save Settings on Exit", SaveOnExitProc},
757 MenuItem helpMenu[] = {
758 {N_("Info XBoard"), "Info XBoard", InfoProc},
759 {N_("Man XBoard F1"), "Man XBoard", ManProc},
760 {"----", NULL, NothingProc},
761 {N_("About XBoard"), "About XBoard", AboutProc},
766 {N_("File"), "File", fileMenu},
767 {N_("Edit"), "Edit", editMenu},
768 {N_("View"), "View", viewMenu},
769 {N_("Mode"), "Mode", modeMenu},
770 {N_("Action"), "Action", actionMenu},
771 {N_("Engine"), "Engine", engineMenu},
772 {N_("Options"), "Options", optionsMenu},
773 {N_("Help"), "Help", helpMenu},
777 #define PAUSE_BUTTON "P"
778 MenuItem buttonBar[] = {
779 {"<<", "<<", ToStartProc},
780 {"<", "<", BackwardProc},
781 {PAUSE_BUTTON, PAUSE_BUTTON, PauseProc},
782 {">", ">", ForwardProc},
783 {">>", ">>", ToEndProc},
787 #define PIECE_MENU_SIZE 18
788 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
789 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
790 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
791 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
792 N_("Empty square"), N_("Clear board") },
793 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
794 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
795 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
796 N_("Empty square"), N_("Clear board") }
798 /* must be in same order as PieceMenuStrings! */
799 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
800 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
801 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
802 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
803 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
804 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
805 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
806 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
807 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
810 #define DROP_MENU_SIZE 6
811 String dropMenuStrings[DROP_MENU_SIZE] = {
812 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
814 /* must be in same order as PieceMenuStrings! */
815 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
816 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
817 WhiteRook, WhiteQueen
825 DropMenuEnables dmEnables[] = {
843 { XtNborderWidth, 0 },
844 { XtNdefaultDistance, 0 },
848 { XtNborderWidth, 0 },
849 { XtNresizable, (XtArgVal) True },
853 { XtNborderWidth, 0 },
859 { XtNjustify, (XtArgVal) XtJustifyRight },
860 { XtNlabel, (XtArgVal) "..." },
861 { XtNresizable, (XtArgVal) True },
862 { XtNresize, (XtArgVal) False }
865 Arg messageArgs[] = {
866 { XtNjustify, (XtArgVal) XtJustifyLeft },
867 { XtNlabel, (XtArgVal) "..." },
868 { XtNresizable, (XtArgVal) True },
869 { XtNresize, (XtArgVal) False }
873 { XtNborderWidth, 0 },
874 { XtNjustify, (XtArgVal) XtJustifyLeft }
877 XtResource clientResources[] = {
878 { "flashCount", "flashCount", XtRInt, sizeof(int),
879 XtOffset(AppDataPtr, flashCount), XtRImmediate,
880 (XtPointer) FLASH_COUNT },
883 XrmOptionDescRec shellOptions[] = {
884 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
885 { "-flash", "flashCount", XrmoptionNoArg, "3" },
886 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
889 XtActionsRec boardActions[] = {
890 { "DrawPosition", DrawPositionProc },
891 { "HandleUserMove", HandleUserMove },
892 { "AnimateUserMove", AnimateUserMove },
893 { "HandlePV", HandlePV },
894 { "SelectPV", SelectPV },
895 { "StopPV", StopPV },
896 { "FileNameAction", FileNameAction },
897 { "AskQuestionProc", AskQuestionProc },
898 { "AskQuestionReplyAction", AskQuestionReplyAction },
899 { "PieceMenuPopup", PieceMenuPopup },
900 { "WhiteClock", WhiteClock },
901 { "BlackClock", BlackClock },
902 { "Iconify", Iconify },
903 { "ResetProc", ResetProc },
904 { "NewVariantProc", NewVariantProc },
905 { "LoadGameProc", LoadGameProc },
906 { "LoadNextGameProc", LoadNextGameProc },
907 { "LoadPrevGameProc", LoadPrevGameProc },
908 { "LoadSelectedProc", LoadSelectedProc },
909 { "SetFilterProc", SetFilterProc },
910 { "ReloadGameProc", ReloadGameProc },
911 { "LoadPositionProc", LoadPositionProc },
912 { "LoadNextPositionProc", LoadNextPositionProc },
913 { "LoadPrevPositionProc", LoadPrevPositionProc },
914 { "ReloadPositionProc", ReloadPositionProc },
915 { "CopyPositionProc", CopyPositionProc },
916 { "PastePositionProc", PastePositionProc },
917 { "CopyGameProc", CopyGameProc },
918 { "CopyGameListProc", CopyGameListProc },
919 { "PasteGameProc", PasteGameProc },
920 { "SaveGameProc", SaveGameProc },
921 { "SavePositionProc", SavePositionProc },
922 { "MailMoveProc", MailMoveProc },
923 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
924 { "QuitProc", QuitProc },
925 { "MachineWhiteProc", MachineWhiteProc },
926 { "MachineBlackProc", MachineBlackProc },
927 { "AnalysisModeProc", AnalyzeModeProc },
928 { "AnalyzeFileProc", AnalyzeFileProc },
929 { "TwoMachinesProc", TwoMachinesProc },
930 { "IcsClientProc", IcsClientProc },
931 { "EditGameProc", EditGameProc },
932 { "EditPositionProc", EditPositionProc },
933 { "TrainingProc", EditPositionProc },
934 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
935 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
936 { "ShowGameListProc", ShowGameListProc },
937 { "ShowMoveListProc", HistoryShowProc},
938 { "EditTagsProc", EditCommentProc },
939 { "EditCommentProc", EditCommentProc },
940 { "IcsInputBoxProc", IcsInputBoxProc },
941 { "PauseProc", PauseProc },
942 { "AcceptProc", AcceptProc },
943 { "DeclineProc", DeclineProc },
944 { "RematchProc", RematchProc },
945 { "CallFlagProc", CallFlagProc },
946 { "DrawProc", DrawProc },
947 { "AdjournProc", AdjournProc },
948 { "AbortProc", AbortProc },
949 { "ResignProc", ResignProc },
950 { "AdjuWhiteProc", AdjuWhiteProc },
951 { "AdjuBlackProc", AdjuBlackProc },
952 { "AdjuDrawProc", AdjuDrawProc },
953 { "EnterKeyProc", EnterKeyProc },
954 { "UpKeyProc", UpKeyProc },
955 { "DownKeyProc", DownKeyProc },
956 { "StopObservingProc", StopObservingProc },
957 { "StopExaminingProc", StopExaminingProc },
958 { "UploadProc", UploadProc },
959 { "BackwardProc", BackwardProc },
960 { "ForwardProc", ForwardProc },
961 { "ToStartProc", ToStartProc },
962 { "ToEndProc", ToEndProc },
963 { "RevertProc", RevertProc },
964 { "AnnotateProc", AnnotateProc },
965 { "TruncateGameProc", TruncateGameProc },
966 { "MoveNowProc", MoveNowProc },
967 { "RetractMoveProc", RetractMoveProc },
968 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
969 { "UciMenuProc", (XtActionProc) UciMenuProc },
970 { "TimeControlProc", (XtActionProc) TimeControlProc },
971 { "FlipViewProc", FlipViewProc },
972 { "PonderNextMoveProc", PonderNextMoveProc },
973 #ifndef OPTIONSDIALOG
974 { "AlwaysQueenProc", AlwaysQueenProc },
975 { "AnimateDraggingProc", AnimateDraggingProc },
976 { "AnimateMovingProc", AnimateMovingProc },
977 { "AutoflagProc", AutoflagProc },
978 { "AutoflipProc", AutoflipProc },
979 { "BlindfoldProc", BlindfoldProc },
980 { "FlashMovesProc", FlashMovesProc },
982 { "HighlightDraggingProc", HighlightDraggingProc },
984 { "HighlightLastMoveProc", HighlightLastMoveProc },
985 // { "IcsAlarmProc", IcsAlarmProc },
986 { "MoveSoundProc", MoveSoundProc },
987 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
988 { "PopupExitMessageProc", PopupExitMessageProc },
989 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
990 // { "PremoveProc", PremoveProc },
991 { "ShowCoordsProc", ShowCoordsProc },
992 { "ShowThinkingProc", ShowThinkingProc },
993 { "HideThinkingProc", HideThinkingProc },
994 { "TestLegalityProc", TestLegalityProc },
996 { "SaveSettingsProc", SaveSettingsProc },
997 { "SaveOnExitProc", SaveOnExitProc },
998 { "InfoProc", InfoProc },
999 { "ManProc", ManProc },
1000 { "HintProc", HintProc },
1001 { "BookProc", BookProc },
1002 { "AboutGameProc", AboutGameProc },
1003 { "AboutProc", AboutProc },
1004 { "DebugProc", DebugProc },
1005 { "NothingProc", NothingProc },
1006 { "CommentClick", (XtActionProc) CommentClick },
1007 { "CommentPopDown", (XtActionProc) CommentPopDown },
1008 { "TagsPopDown", (XtActionProc) TagsPopDown },
1009 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
1010 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
1011 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
1012 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
1013 { "GameListPopDown", (XtActionProc) GameListPopDown },
1014 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
1015 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1016 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
1017 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1018 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1019 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
1020 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
1021 { "GenericPopDown", (XtActionProc) GenericPopDown },
1022 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1025 char globalTranslations[] =
1026 ":<Key>F9: ResignProc() \n \
1027 :Ctrl<Key>n: ResetProc() \n \
1028 :Meta<Key>V: NewVariantProc() \n \
1029 :Ctrl<Key>o: LoadGameProc() \n \
1030 :Meta<Key>Next: LoadNextGameProc() \n \
1031 :Meta<Key>Prior: LoadPrevGameProc() \n \
1032 :Ctrl<Key>s: SaveGameProc() \n \
1033 :Ctrl<Key>c: CopyGameProc() \n \
1034 :Ctrl<Key>v: PasteGameProc() \n \
1035 :Ctrl<Key>O: LoadPositionProc() \n \
1036 :Shift<Key>Next: LoadNextPositionProc() \n \
1037 :Shift<Key>Prior: LoadPrevPositionProc() \n \
1038 :Ctrl<Key>S: SavePositionProc() \n \
1039 :Ctrl<Key>C: CopyPositionProc() \n \
1040 :Ctrl<Key>V: PastePositionProc() \n \
1041 :Ctrl<Key>q: QuitProc() \n \
1042 :Ctrl<Key>w: MachineWhiteProc() \n \
1043 :Ctrl<Key>b: MachineBlackProc() \n \
1044 :Ctrl<Key>t: TwoMachinesProc() \n \
1045 :Ctrl<Key>a: AnalysisModeProc() \n \
1046 :Ctrl<Key>f: AnalyzeFileProc() \n \
1047 :Ctrl<Key>e: EditGameProc() \n \
1048 :Ctrl<Key>E: EditPositionProc() \n \
1049 :Meta<Key>O: EngineOutputProc() \n \
1050 :Meta<Key>E: EvalGraphProc() \n \
1051 :Meta<Key>G: ShowGameListProc() \n \
1052 :Meta<Key>H: ShowMoveListProc() \n \
1053 :<Key>Pause: PauseProc() \n \
1054 :<Key>F3: AcceptProc() \n \
1055 :<Key>F4: DeclineProc() \n \
1056 :<Key>F12: RematchProc() \n \
1057 :<Key>F5: CallFlagProc() \n \
1058 :<Key>F6: DrawProc() \n \
1059 :<Key>F7: AdjournProc() \n \
1060 :<Key>F8: AbortProc() \n \
1061 :<Key>F10: StopObservingProc() \n \
1062 :<Key>F11: StopExaminingProc() \n \
1063 :Meta Ctrl<Key>F12: DebugProc() \n \
1064 :Meta<Key>End: ToEndProc() \n \
1065 :Meta<Key>Right: ForwardProc() \n \
1066 :Meta<Key>Home: ToStartProc() \n \
1067 :Meta<Key>Left: BackwardProc() \n \
1068 :<Key>Home: RevertProc() \n \
1069 :<Key>End: TruncateGameProc() \n \
1070 :Ctrl<Key>m: MoveNowProc() \n \
1071 :Ctrl<Key>x: RetractMoveProc() \n \
1072 :Meta<Key>J: EngineMenuProc() \n \
1073 :Meta<Key>U: UciMenuProc() \n \
1074 :Meta<Key>T: TimeControlProc() \n \
1075 :Ctrl<Key>P: PonderNextMoveProc() \n "
1076 #ifndef OPTIONSDIALOG
1078 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1079 :Ctrl<Key>F: AutoflagProc() \n \
1080 :Ctrl<Key>A: AnimateMovingProc() \n \
1081 :Ctrl<Key>L: TestLegalityProc() \n \
1082 :Ctrl<Key>H: HideThinkingProc() \n "
1085 :<Key>-: Iconify() \n \
1086 :<Key>F1: ManProc() \n \
1087 :<Key>F2: FlipViewProc() \n \
1088 <KeyDown>.: BackwardProc() \n \
1089 <KeyUp>.: ForwardProc() \n \
1090 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1091 \"Send to chess program:\",,1) \n \
1092 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1093 \"Send to second chess program:\",,2) \n";
1095 char boardTranslations[] =
1096 "<Btn1Down>: HandleUserMove(0) \n \
1097 Shift<Btn1Up>: HandleUserMove(1) \n \
1098 <Btn1Up>: HandleUserMove(0) \n \
1099 <Btn1Motion>: AnimateUserMove() \n \
1100 <Btn3Motion>: HandlePV() \n \
1101 <Btn3Up>: PieceMenuPopup(menuB) \n \
1102 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1103 PieceMenuPopup(menuB) \n \
1104 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1105 PieceMenuPopup(menuW) \n \
1106 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1107 PieceMenuPopup(menuW) \n \
1108 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1109 PieceMenuPopup(menuB) \n";
1111 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1112 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1114 char ICSInputTranslations[] =
1115 "<Key>Up: UpKeyProc() \n "
1116 "<Key>Down: DownKeyProc() \n "
1117 "<Key>Return: EnterKeyProc() \n";
1119 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1120 // as the widget is destroyed before the up-click can call extend-end
1121 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1123 String xboardResources[] = {
1124 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1125 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1126 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1131 /* Max possible square size */
1132 #define MAXSQSIZE 256
1134 static int xpm_avail[MAXSQSIZE];
1136 #ifdef HAVE_DIR_STRUCT
1138 /* Extract piece size from filename */
1140 xpm_getsize(name, len, ext)
1151 if ((p=strchr(name, '.')) == NULL ||
1152 StrCaseCmp(p+1, ext) != 0)
1158 while (*p && isdigit(*p))
1165 /* Setup xpm_avail */
1167 xpm_getavail(dirname, ext)
1175 for (i=0; i<MAXSQSIZE; ++i)
1178 if (appData.debugMode)
1179 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1181 dir = opendir(dirname);
1184 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1185 programName, dirname);
1189 while ((ent=readdir(dir)) != NULL) {
1190 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1191 if (i > 0 && i < MAXSQSIZE)
1201 xpm_print_avail(fp, ext)
1207 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1208 for (i=1; i<MAXSQSIZE; ++i) {
1214 /* Return XPM piecesize closest to size */
1216 xpm_closest_to(dirname, size, ext)
1222 int sm_diff = MAXSQSIZE;
1226 xpm_getavail(dirname, ext);
1228 if (appData.debugMode)
1229 xpm_print_avail(stderr, ext);
1231 for (i=1; i<MAXSQSIZE; ++i) {
1234 diff = (diff<0) ? -diff : diff;
1235 if (diff < sm_diff) {
1243 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1249 #else /* !HAVE_DIR_STRUCT */
1250 /* If we are on a system without a DIR struct, we can't
1251 read the directory, so we can't collect a list of
1252 filenames, etc., so we can't do any size-fitting. */
1254 xpm_closest_to(dirname, size, ext)
1259 fprintf(stderr, _("\
1260 Warning: No DIR structure found on this system --\n\
1261 Unable to autosize for XPM/XIM pieces.\n\
1262 Please report this error to frankm@hiwaay.net.\n\
1263 Include system type & operating system in message.\n"));
1266 #endif /* HAVE_DIR_STRUCT */
1268 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1269 "magenta", "cyan", "white" };
1273 TextColors textColors[(int)NColorClasses];
1275 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1277 parse_color(str, which)
1281 char *p, buf[100], *d;
1284 if (strlen(str) > 99) /* watch bounds on buf */
1289 for (i=0; i<which; ++i) {
1296 /* Could be looking at something like:
1298 .. in which case we want to stop on a comma also */
1299 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1303 return -1; /* Use default for empty field */
1306 if (which == 2 || isdigit(*p))
1309 while (*p && isalpha(*p))
1314 for (i=0; i<8; ++i) {
1315 if (!StrCaseCmp(buf, cnames[i]))
1316 return which? (i+40) : (i+30);
1318 if (!StrCaseCmp(buf, "default")) return -1;
1320 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1325 parse_cpair(cc, str)
1329 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1330 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1335 /* bg and attr are optional */
1336 textColors[(int)cc].bg = parse_color(str, 1);
1337 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1338 textColors[(int)cc].attr = 0;
1344 /* Arrange to catch delete-window events */
1345 Atom wm_delete_window;
1347 CatchDeleteWindow(Widget w, String procname)
1350 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1351 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1352 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1359 XtSetArg(args[0], XtNiconic, False);
1360 XtSetValues(shellWidget, args, 1);
1362 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1365 //---------------------------------------------------------------------------------------------------------
1366 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1369 #define CW_USEDEFAULT (1<<31)
1370 #define ICS_TEXT_MENU_SIZE 90
1371 #define DEBUG_FILE "xboard.debug"
1372 #define SetCurrentDirectory chdir
1373 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1377 // these two must some day move to frontend.h, when they are implemented
1378 Boolean GameListIsUp();
1380 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1383 // front-end part of option handling
1385 // [HGM] This platform-dependent table provides the location for storing the color info
1386 extern char *crWhite, * crBlack;
1390 &appData.whitePieceColor,
1391 &appData.blackPieceColor,
1392 &appData.lightSquareColor,
1393 &appData.darkSquareColor,
1394 &appData.highlightSquareColor,
1395 &appData.premoveHighlightColor,
1396 &appData.lowTimeWarningColor,
1407 // [HGM] font: keep a font for each square size, even non-stndard ones
1408 #define NUM_SIZES 18
1409 #define MAX_SIZE 130
1410 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1411 char *fontTable[NUM_FONTS][MAX_SIZE];
1414 ParseFont(char *name, int number)
1415 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1417 if(sscanf(name, "size%d:", &size)) {
1418 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1419 // defer processing it until we know if it matches our board size
1420 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1421 fontTable[number][size] = strdup(strchr(name, ':')+1);
1422 fontValid[number][size] = True;
1427 case 0: // CLOCK_FONT
1428 appData.clockFont = strdup(name);
1430 case 1: // MESSAGE_FONT
1431 appData.font = strdup(name);
1433 case 2: // COORD_FONT
1434 appData.coordFont = strdup(name);
1439 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1444 { // only 2 fonts currently
1445 appData.clockFont = CLOCK_FONT_NAME;
1446 appData.coordFont = COORD_FONT_NAME;
1447 appData.font = DEFAULT_FONT_NAME;
1452 { // no-op, until we identify the code for this already in XBoard and move it here
1456 ParseColor(int n, char *name)
1457 { // in XBoard, just copy the color-name string
1458 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1462 ParseTextAttribs(ColorClass cc, char *s)
1464 (&appData.colorShout)[cc] = strdup(s);
1468 ParseBoardSize(void *addr, char *name)
1470 appData.boardSize = strdup(name);
1475 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1479 SetCommPortDefaults()
1480 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1483 // [HGM] args: these three cases taken out to stay in front-end
1485 SaveFontArg(FILE *f, ArgDescriptor *ad)
1488 int i, n = (int)(intptr_t)ad->argLoc;
1490 case 0: // CLOCK_FONT
1491 name = appData.clockFont;
1493 case 1: // MESSAGE_FONT
1494 name = appData.font;
1496 case 2: // COORD_FONT
1497 name = appData.coordFont;
1502 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1503 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1504 fontTable[n][squareSize] = strdup(name);
1505 fontValid[n][squareSize] = True;
1508 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1509 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1514 { // nothing to do, as the sounds are at all times represented by their text-string names already
1518 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1519 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1520 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
1524 SaveColor(FILE *f, ArgDescriptor *ad)
1525 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1526 if(colorVariable[(int)(intptr_t)ad->argLoc])
1527 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
1531 SaveBoardSize(FILE *f, char *name, void *addr)
1532 { // wrapper to shield back-end from BoardSize & sizeInfo
1533 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1537 ParseCommPortSettings(char *s)
1538 { // no such option in XBoard (yet)
1541 extern Widget engineOutputShell;
1544 GetActualPlacement(Widget wg, WindowPlacement *wp)
1554 XtSetArg(args[i], XtNx, &x); i++;
1555 XtSetArg(args[i], XtNy, &y); i++;
1556 XtSetArg(args[i], XtNwidth, &w); i++;
1557 XtSetArg(args[i], XtNheight, &h); i++;
1558 XtGetValues(wg, args, i);
1567 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1568 // In XBoard this will have to wait until awareness of window parameters is implemented
1569 GetActualPlacement(shellWidget, &wpMain);
1570 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1571 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1572 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1573 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1574 if(shellUp[1]) GetActualPlacement(shells[1], &wpComment);
1575 if(shellUp[2]) GetActualPlacement(shells[2], &wpTags);
1579 PrintCommPortSettings(FILE *f, char *name)
1580 { // This option does not exist in XBoard
1584 MySearchPath(char *installDir, char *name, char *fullname)
1585 { // just append installDir and name. Perhaps ExpandPath should be used here?
1586 name = ExpandPathName(name);
1587 if(name && name[0] == '/')
1588 safeStrCpy(fullname, name, MSG_SIZ );
1590 sprintf(fullname, "%s%c%s", installDir, '/', name);
1596 MyGetFullPathName(char *name, char *fullname)
1597 { // should use ExpandPath?
1598 name = ExpandPathName(name);
1599 safeStrCpy(fullname, name, MSG_SIZ );
1604 EnsureOnScreen(int *x, int *y, int minX, int minY)
1611 { // [HGM] args: allows testing if main window is realized from back-end
1612 return xBoardWindow != 0;
1616 PopUpStartupDialog()
1617 { // start menu not implemented in XBoard
1621 ConvertToLine(int argc, char **argv)
1623 static char line[128*1024], buf[1024];
1627 for(i=1; i<argc; i++)
1629 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1630 && argv[i][0] != '{' )
1631 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1633 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1634 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1637 line[strlen(line)-1] = NULLCHAR;
1641 //--------------------------------------------------------------------------------------------
1643 extern Boolean twoBoards, partnerUp;
1646 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1648 #define BoardSize int
1649 void InitDrawingSizes(BoardSize boardSize, int flags)
1650 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1651 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1653 XtGeometryResult gres;
1656 if(!formWidget) return;
1659 * Enable shell resizing.
1661 shellArgs[0].value = (XtArgVal) &w;
1662 shellArgs[1].value = (XtArgVal) &h;
1663 XtGetValues(shellWidget, shellArgs, 2);
1665 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1666 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1667 XtSetValues(shellWidget, &shellArgs[2], 4);
1669 XtSetArg(args[0], XtNdefaultDistance, &sep);
1670 XtGetValues(formWidget, args, 1);
1672 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1673 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1674 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1676 hOffset = boardWidth + 10;
1677 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1678 secondSegments[i] = gridSegments[i];
1679 secondSegments[i].x1 += hOffset;
1680 secondSegments[i].x2 += hOffset;
1683 XtSetArg(args[0], XtNwidth, boardWidth);
1684 XtSetArg(args[1], XtNheight, boardHeight);
1685 XtSetValues(boardWidget, args, 2);
1687 timerWidth = (boardWidth - sep) / 2;
1688 XtSetArg(args[0], XtNwidth, timerWidth);
1689 XtSetValues(whiteTimerWidget, args, 1);
1690 XtSetValues(blackTimerWidget, args, 1);
1692 XawFormDoLayout(formWidget, False);
1694 if (appData.titleInWindow) {
1696 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1697 XtSetArg(args[i], XtNheight, &h); i++;
1698 XtGetValues(titleWidget, args, i);
1700 w = boardWidth - 2*bor;
1702 XtSetArg(args[0], XtNwidth, &w);
1703 XtGetValues(menuBarWidget, args, 1);
1704 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1707 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1708 if (gres != XtGeometryYes && appData.debugMode) {
1710 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1711 programName, gres, w, h, wr, hr);
1715 XawFormDoLayout(formWidget, True);
1718 * Inhibit shell resizing.
1720 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1721 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1722 shellArgs[4].value = shellArgs[2].value = w;
1723 shellArgs[5].value = shellArgs[3].value = h;
1724 XtSetValues(shellWidget, &shellArgs[0], 6);
1726 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1729 for(i=0; i<4; i++) {
1731 for(p=0; p<=(int)WhiteKing; p++)
1732 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1733 if(gameInfo.variant == VariantShogi) {
1734 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1735 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1736 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1737 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1738 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1741 if(gameInfo.variant == VariantGothic) {
1742 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1745 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1746 xpmPieceBitmap[i][(int)WhiteAngel] = xpmPieceBitmap2[i][(int)WhiteFalcon];
1747 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1750 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1751 for(p=0; p<=(int)WhiteKing; p++)
1752 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1753 if(gameInfo.variant == VariantShogi) {
1754 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1755 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1756 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1757 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1758 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1761 if(gameInfo.variant == VariantGothic) {
1762 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1765 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1766 ximMaskPm[(int)WhiteAngel] = ximMaskPm2[(int)WhiteFalcon];
1767 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1772 for(i=0; i<2; i++) {
1774 for(p=0; p<=(int)WhiteKing; p++)
1775 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1776 if(gameInfo.variant == VariantShogi) {
1777 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1778 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1779 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1780 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1781 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1784 if(gameInfo.variant == VariantGothic) {
1785 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1788 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1789 pieceBitmap[i][(int)WhiteAngel] = pieceBitmap2[i][(int)WhiteFalcon];
1790 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1800 void ParseIcsTextColors()
1801 { // [HGM] tken out of main(), so it can be called from ICS-Options dialog
1802 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1803 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1804 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1805 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1806 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1807 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1808 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1809 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1810 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1811 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1813 if (appData.colorize) {
1815 _("%s: can't parse color names; disabling colorization\n"),
1818 appData.colorize = FALSE;
1823 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
1824 XrmValue vFrom, vTo;
1825 int forceMono = False;
1827 if (!appData.monoMode) {
1828 vFrom.addr = (caddr_t) appData.lightSquareColor;
1829 vFrom.size = strlen(appData.lightSquareColor);
1830 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1831 if (vTo.addr == NULL) {
1832 appData.monoMode = True;
1835 lightSquareColor = *(Pixel *) vTo.addr;
1838 if (!appData.monoMode) {
1839 vFrom.addr = (caddr_t) appData.darkSquareColor;
1840 vFrom.size = strlen(appData.darkSquareColor);
1841 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1842 if (vTo.addr == NULL) {
1843 appData.monoMode = True;
1846 darkSquareColor = *(Pixel *) vTo.addr;
1849 if (!appData.monoMode) {
1850 vFrom.addr = (caddr_t) appData.whitePieceColor;
1851 vFrom.size = strlen(appData.whitePieceColor);
1852 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1853 if (vTo.addr == NULL) {
1854 appData.monoMode = True;
1857 whitePieceColor = *(Pixel *) vTo.addr;
1860 if (!appData.monoMode) {
1861 vFrom.addr = (caddr_t) appData.blackPieceColor;
1862 vFrom.size = strlen(appData.blackPieceColor);
1863 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1864 if (vTo.addr == NULL) {
1865 appData.monoMode = True;
1868 blackPieceColor = *(Pixel *) vTo.addr;
1872 if (!appData.monoMode) {
1873 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1874 vFrom.size = strlen(appData.highlightSquareColor);
1875 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1876 if (vTo.addr == NULL) {
1877 appData.monoMode = True;
1880 highlightSquareColor = *(Pixel *) vTo.addr;
1884 if (!appData.monoMode) {
1885 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1886 vFrom.size = strlen(appData.premoveHighlightColor);
1887 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1888 if (vTo.addr == NULL) {
1889 appData.monoMode = True;
1892 premoveHighlightColor = *(Pixel *) vTo.addr;
1903 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1904 XSetWindowAttributes window_attributes;
1906 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1907 XrmValue vFrom, vTo;
1908 XtGeometryResult gres;
1911 int forceMono = False;
1913 srandom(time(0)); // [HGM] book: make random truly random
1915 setbuf(stdout, NULL);
1916 setbuf(stderr, NULL);
1919 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1920 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1924 programName = strrchr(argv[0], '/');
1925 if (programName == NULL)
1926 programName = argv[0];
1931 XtSetLanguageProc(NULL, NULL, NULL);
1932 bindtextdomain(PACKAGE, LOCALEDIR);
1933 textdomain(PACKAGE);
1937 XtAppInitialize(&appContext, "XBoard", shellOptions,
1938 XtNumber(shellOptions),
1939 &argc, argv, xboardResources, NULL, 0);
1940 appData.boardSize = "";
1941 InitAppData(ConvertToLine(argc, argv));
1943 if (p == NULL) p = "/tmp";
1944 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1945 gameCopyFilename = (char*) malloc(i);
1946 gamePasteFilename = (char*) malloc(i);
1947 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1948 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1950 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1951 clientResources, XtNumber(clientResources),
1954 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1955 static char buf[MSG_SIZ];
1956 EscapeExpand(buf, appData.initString);
1957 appData.initString = strdup(buf);
1958 EscapeExpand(buf, appData.secondInitString);
1959 appData.secondInitString = strdup(buf);
1960 EscapeExpand(buf, appData.firstComputerString);
1961 appData.firstComputerString = strdup(buf);
1962 EscapeExpand(buf, appData.secondComputerString);
1963 appData.secondComputerString = strdup(buf);
1966 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1969 if (chdir(chessDir) != 0) {
1970 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1976 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1977 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1978 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1979 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1982 setbuf(debugFP, NULL);
1985 /* [HGM,HR] make sure board size is acceptable */
1986 if(appData.NrFiles > BOARD_FILES ||
1987 appData.NrRanks > BOARD_RANKS )
1988 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1991 /* This feature does not work; animation needs a rewrite */
1992 appData.highlightDragging = FALSE;
1996 xDisplay = XtDisplay(shellWidget);
1997 xScreen = DefaultScreen(xDisplay);
1998 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
2000 gameInfo.variant = StringToVariant(appData.variant);
2001 InitPosition(FALSE);
2004 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
2006 if (isdigit(appData.boardSize[0])) {
2007 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
2008 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
2009 &fontPxlSize, &smallLayout, &tinyLayout);
2011 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
2012 programName, appData.boardSize);
2016 /* Find some defaults; use the nearest known size */
2017 SizeDefaults *szd, *nearest;
2018 int distance = 99999;
2019 nearest = szd = sizeDefaults;
2020 while (szd->name != NULL) {
2021 if (abs(szd->squareSize - squareSize) < distance) {
2023 distance = abs(szd->squareSize - squareSize);
2024 if (distance == 0) break;
2028 if (i < 2) lineGap = nearest->lineGap;
2029 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
2030 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
2031 if (i < 5) fontPxlSize = nearest->fontPxlSize;
2032 if (i < 6) smallLayout = nearest->smallLayout;
2033 if (i < 7) tinyLayout = nearest->tinyLayout;
2036 SizeDefaults *szd = sizeDefaults;
2037 if (*appData.boardSize == NULLCHAR) {
2038 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
2039 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
2042 if (szd->name == NULL) szd--;
2043 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
2045 while (szd->name != NULL &&
2046 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
2047 if (szd->name == NULL) {
2048 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
2049 programName, appData.boardSize);
2053 squareSize = szd->squareSize;
2054 lineGap = szd->lineGap;
2055 clockFontPxlSize = szd->clockFontPxlSize;
2056 coordFontPxlSize = szd->coordFontPxlSize;
2057 fontPxlSize = szd->fontPxlSize;
2058 smallLayout = szd->smallLayout;
2059 tinyLayout = szd->tinyLayout;
2060 // [HGM] font: use defaults from settings file if available and not overruled
2062 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
2063 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
2064 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
2065 appData.font = fontTable[MESSAGE_FONT][squareSize];
2066 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
2067 appData.coordFont = fontTable[COORD_FONT][squareSize];
2069 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
2070 if (strlen(appData.pixmapDirectory) > 0) {
2071 p = ExpandPathName(appData.pixmapDirectory);
2073 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
2074 appData.pixmapDirectory);
2077 if (appData.debugMode) {
2078 fprintf(stderr, _("\
2079 XBoard square size (hint): %d\n\
2080 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
2082 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
2083 if (appData.debugMode) {
2084 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
2087 defaultLineGap = lineGap;
2088 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
2090 /* [HR] height treated separately (hacked) */
2091 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
2092 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
2093 if (appData.showJail == 1) {
2094 /* Jail on top and bottom */
2095 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2096 XtSetArg(boardArgs[2], XtNheight,
2097 boardHeight + 2*(lineGap + squareSize));
2098 } else if (appData.showJail == 2) {
2100 XtSetArg(boardArgs[1], XtNwidth,
2101 boardWidth + 2*(lineGap + squareSize));
2102 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2105 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2106 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2110 * Determine what fonts to use.
2112 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2113 clockFontID = XLoadFont(xDisplay, appData.clockFont);
2114 clockFontStruct = XQueryFont(xDisplay, clockFontID);
2115 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2116 coordFontID = XLoadFont(xDisplay, appData.coordFont);
2117 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2118 appData.font = FindFont(appData.font, fontPxlSize);
2119 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
2120 countFontStruct = XQueryFont(xDisplay, countFontID);
2121 // appData.font = FindFont(appData.font, fontPxlSize);
2123 xdb = XtDatabase(xDisplay);
2124 XrmPutStringResource(&xdb, "*font", appData.font);
2127 * Detect if there are not enough colors available and adapt.
2129 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2130 appData.monoMode = True;
2133 forceMono = MakeColors();
2136 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2139 if (appData.bitmapDirectory == NULL ||
2140 appData.bitmapDirectory[0] == NULLCHAR)
2141 appData.bitmapDirectory = DEF_BITMAP_DIR;
2144 if (appData.lowTimeWarning && !appData.monoMode) {
2145 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2146 vFrom.size = strlen(appData.lowTimeWarningColor);
2147 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2148 if (vTo.addr == NULL)
2149 appData.monoMode = True;
2151 lowTimeWarningColor = *(Pixel *) vTo.addr;
2154 if (appData.monoMode && appData.debugMode) {
2155 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2156 (unsigned long) XWhitePixel(xDisplay, xScreen),
2157 (unsigned long) XBlackPixel(xDisplay, xScreen));
2160 ParseIcsTextColors();
2161 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2162 textColors[ColorNone].attr = 0;
2164 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2170 layoutName = "tinyLayout";
2171 } else if (smallLayout) {
2172 layoutName = "smallLayout";
2174 layoutName = "normalLayout";
2176 /* Outer layoutWidget is there only to provide a name for use in
2177 resources that depend on the layout style */
2179 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2180 layoutArgs, XtNumber(layoutArgs));
2182 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2183 formArgs, XtNumber(formArgs));
2184 XtSetArg(args[0], XtNdefaultDistance, &sep);
2185 XtGetValues(formWidget, args, 1);
2188 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2189 XtSetArg(args[0], XtNtop, XtChainTop);
2190 XtSetArg(args[1], XtNbottom, XtChainTop);
2191 XtSetArg(args[2], XtNright, XtChainLeft);
2192 XtSetValues(menuBarWidget, args, 3);
2194 widgetList[j++] = whiteTimerWidget =
2195 XtCreateWidget("whiteTime", labelWidgetClass,
2196 formWidget, timerArgs, XtNumber(timerArgs));
2197 XtSetArg(args[0], XtNfont, clockFontStruct);
2198 XtSetArg(args[1], XtNtop, XtChainTop);
2199 XtSetArg(args[2], XtNbottom, XtChainTop);
2200 XtSetValues(whiteTimerWidget, args, 3);
2202 widgetList[j++] = blackTimerWidget =
2203 XtCreateWidget("blackTime", labelWidgetClass,
2204 formWidget, timerArgs, XtNumber(timerArgs));
2205 XtSetArg(args[0], XtNfont, clockFontStruct);
2206 XtSetArg(args[1], XtNtop, XtChainTop);
2207 XtSetArg(args[2], XtNbottom, XtChainTop);
2208 XtSetValues(blackTimerWidget, args, 3);
2210 if (appData.titleInWindow) {
2211 widgetList[j++] = titleWidget =
2212 XtCreateWidget("title", labelWidgetClass, formWidget,
2213 titleArgs, XtNumber(titleArgs));
2214 XtSetArg(args[0], XtNtop, XtChainTop);
2215 XtSetArg(args[1], XtNbottom, XtChainTop);
2216 XtSetValues(titleWidget, args, 2);
2219 if (appData.showButtonBar) {
2220 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2221 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2222 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2223 XtSetArg(args[2], XtNtop, XtChainTop);
2224 XtSetArg(args[3], XtNbottom, XtChainTop);
2225 XtSetValues(buttonBarWidget, args, 4);
2228 widgetList[j++] = messageWidget =
2229 XtCreateWidget("message", labelWidgetClass, formWidget,
2230 messageArgs, XtNumber(messageArgs));
2231 XtSetArg(args[0], XtNtop, XtChainTop);
2232 XtSetArg(args[1], XtNbottom, XtChainTop);
2233 XtSetValues(messageWidget, args, 2);
2235 widgetList[j++] = boardWidget =
2236 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2237 XtNumber(boardArgs));
2239 XtManageChildren(widgetList, j);
2241 timerWidth = (boardWidth - sep) / 2;
2242 XtSetArg(args[0], XtNwidth, timerWidth);
2243 XtSetValues(whiteTimerWidget, args, 1);
2244 XtSetValues(blackTimerWidget, args, 1);
2246 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2247 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2248 XtGetValues(whiteTimerWidget, args, 2);
2250 if (appData.showButtonBar) {
2251 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2252 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2253 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2257 * formWidget uses these constraints but they are stored
2261 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2262 XtSetValues(menuBarWidget, args, i);
2263 if (appData.titleInWindow) {
2266 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2267 XtSetValues(whiteTimerWidget, args, i);
2269 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2270 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2271 XtSetValues(blackTimerWidget, args, i);
2273 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2274 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2275 XtSetValues(titleWidget, args, i);
2277 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2278 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2279 XtSetValues(messageWidget, args, i);
2280 if (appData.showButtonBar) {
2282 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2283 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2284 XtSetValues(buttonBarWidget, args, i);
2288 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2289 XtSetValues(whiteTimerWidget, args, i);
2291 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2292 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2293 XtSetValues(blackTimerWidget, args, i);
2295 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2296 XtSetValues(titleWidget, args, i);
2298 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2299 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2300 XtSetValues(messageWidget, args, i);
2301 if (appData.showButtonBar) {
2303 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2304 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2305 XtSetValues(buttonBarWidget, args, i);
2310 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2311 XtSetValues(whiteTimerWidget, args, i);
2313 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2314 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2315 XtSetValues(blackTimerWidget, args, i);
2317 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2318 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2319 XtSetValues(messageWidget, args, i);
2320 if (appData.showButtonBar) {
2322 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2323 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2324 XtSetValues(buttonBarWidget, args, i);
2328 XtSetArg(args[0], XtNfromVert, messageWidget);
2329 XtSetArg(args[1], XtNtop, XtChainTop);
2330 XtSetArg(args[2], XtNbottom, XtChainBottom);
2331 XtSetArg(args[3], XtNleft, XtChainLeft);
2332 XtSetArg(args[4], XtNright, XtChainRight);
2333 XtSetValues(boardWidget, args, 5);
2335 XtRealizeWidget(shellWidget);
2338 XtSetArg(args[0], XtNx, wpMain.x);
2339 XtSetArg(args[1], XtNy, wpMain.y);
2340 XtSetValues(shellWidget, args, 2);
2344 * Correct the width of the message and title widgets.
2345 * It is not known why some systems need the extra fudge term.
2346 * The value "2" is probably larger than needed.
2348 XawFormDoLayout(formWidget, False);
2350 #define WIDTH_FUDGE 2
2352 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2353 XtSetArg(args[i], XtNheight, &h); i++;
2354 XtGetValues(messageWidget, args, i);
2355 if (appData.showButtonBar) {
2357 XtSetArg(args[i], XtNwidth, &w); i++;
2358 XtGetValues(buttonBarWidget, args, i);
2359 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2361 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2364 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2365 if (gres != XtGeometryYes && appData.debugMode) {
2366 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2367 programName, gres, w, h, wr, hr);
2370 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2371 /* The size used for the child widget in layout lags one resize behind
2372 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2374 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2375 if (gres != XtGeometryYes && appData.debugMode) {
2376 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2377 programName, gres, w, h, wr, hr);
2380 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2381 XtSetArg(args[1], XtNright, XtChainRight);
2382 XtSetValues(messageWidget, args, 2);
2384 if (appData.titleInWindow) {
2386 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2387 XtSetArg(args[i], XtNheight, &h); i++;
2388 XtGetValues(titleWidget, args, i);
2390 w = boardWidth - 2*bor;
2392 XtSetArg(args[0], XtNwidth, &w);
2393 XtGetValues(menuBarWidget, args, 1);
2394 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2397 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2398 if (gres != XtGeometryYes && appData.debugMode) {
2400 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2401 programName, gres, w, h, wr, hr);
2404 XawFormDoLayout(formWidget, True);
2406 xBoardWindow = XtWindow(boardWidget);
2408 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2409 // not need to go into InitDrawingSizes().
2413 * Create X checkmark bitmap and initialize option menu checks.
2415 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2416 checkmark_bits, checkmark_width, checkmark_height);
2417 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2418 #ifndef OPTIONSDIALOG
2419 if (appData.alwaysPromoteToQueen) {
2420 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2423 if (appData.animateDragging) {
2424 XtSetValues(XtNameToWidget(menuBarWidget,
2425 "menuOptions.Animate Dragging"),
2428 if (appData.animate) {
2429 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2432 if (appData.autoCallFlag) {
2433 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2436 if (appData.autoFlipView) {
2437 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2440 if (appData.blindfold) {
2441 XtSetValues(XtNameToWidget(menuBarWidget,
2442 "menuOptions.Blindfold"), args, 1);
2444 if (appData.flashCount > 0) {
2445 XtSetValues(XtNameToWidget(menuBarWidget,
2446 "menuOptions.Flash Moves"),
2450 if (appData.highlightDragging) {
2451 XtSetValues(XtNameToWidget(menuBarWidget,
2452 "menuOptions.Highlight Dragging"),
2456 if (appData.highlightLastMove) {
2457 XtSetValues(XtNameToWidget(menuBarWidget,
2458 "menuOptions.Highlight Last Move"),
2461 if (appData.highlightMoveWithArrow) {
2462 XtSetValues(XtNameToWidget(menuBarWidget,
2463 "menuOptions.Arrow"),
2466 // if (appData.icsAlarm) {
2467 // XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2470 if (appData.ringBellAfterMoves) {
2471 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2474 if (appData.oneClick) {
2475 XtSetValues(XtNameToWidget(menuBarWidget,
2476 "menuOptions.OneClick"), args, 1);
2478 if (appData.periodicUpdates) {
2479 XtSetValues(XtNameToWidget(menuBarWidget,
2480 "menuOptions.Periodic Updates"), args, 1);
2482 if (appData.ponderNextMove) {
2483 XtSetValues(XtNameToWidget(menuBarWidget,
2484 "menuOptions.Ponder Next Move"), args, 1);
2486 if (appData.popupExitMessage) {
2487 XtSetValues(XtNameToWidget(menuBarWidget,
2488 "menuOptions.Popup Exit Message"), args, 1);
2490 if (appData.popupMoveErrors) {
2491 XtSetValues(XtNameToWidget(menuBarWidget,
2492 "menuOptions.Popup Move Errors"), args, 1);
2494 // if (appData.premove) {
2495 // XtSetValues(XtNameToWidget(menuBarWidget,
2496 // "menuOptions.Premove"), args, 1);
2498 if (appData.showCoords) {
2499 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2502 if (appData.hideThinkingFromHuman) {
2503 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2506 if (appData.testLegality) {
2507 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2511 if (saveSettingsOnExit) {
2512 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2519 ReadBitmap(&wIconPixmap, "icon_white.bm",
2520 icon_white_bits, icon_white_width, icon_white_height);
2521 ReadBitmap(&bIconPixmap, "icon_black.bm",
2522 icon_black_bits, icon_black_width, icon_black_height);
2523 iconPixmap = wIconPixmap;
2525 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2526 XtSetValues(shellWidget, args, i);
2529 * Create a cursor for the board widget.
2531 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2532 XChangeWindowAttributes(xDisplay, xBoardWindow,
2533 CWCursor, &window_attributes);
2536 * Inhibit shell resizing.
2538 shellArgs[0].value = (XtArgVal) &w;
2539 shellArgs[1].value = (XtArgVal) &h;
2540 XtGetValues(shellWidget, shellArgs, 2);
2541 shellArgs[4].value = shellArgs[2].value = w;
2542 shellArgs[5].value = shellArgs[3].value = h;
2543 XtSetValues(shellWidget, &shellArgs[2], 4);
2544 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2545 marginH = h - boardHeight;
2547 CatchDeleteWindow(shellWidget, "QuitProc");
2552 if (appData.bitmapDirectory[0] != NULLCHAR) {
2556 CreateXPMBoard(appData.liteBackTextureFile, 1);
2557 CreateXPMBoard(appData.darkBackTextureFile, 0);
2561 /* Create regular pieces */
2562 if (!useImages) CreatePieces();
2567 if (appData.animate || appData.animateDragging)
2570 XtAugmentTranslations(formWidget,
2571 XtParseTranslationTable(globalTranslations));
2572 XtAugmentTranslations(boardWidget,
2573 XtParseTranslationTable(boardTranslations));
2574 XtAugmentTranslations(whiteTimerWidget,
2575 XtParseTranslationTable(whiteTranslations));
2576 XtAugmentTranslations(blackTimerWidget,
2577 XtParseTranslationTable(blackTranslations));
2579 /* Why is the following needed on some versions of X instead
2580 * of a translation? */
2581 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2582 (XtEventHandler) EventProc, NULL);
2585 /* [AS] Restore layout */
2586 if( wpMoveHistory.visible ) {
2590 if( wpEvalGraph.visible )
2595 if( wpEngineOutput.visible ) {
2596 EngineOutputPopUp();
2601 if (errorExitStatus == -1) {
2602 if (appData.icsActive) {
2603 /* We now wait until we see "login:" from the ICS before
2604 sending the logon script (problems with timestamp otherwise) */
2605 /*ICSInitScript();*/
2606 if (appData.icsInputBox) ICSInputBoxPopUp();
2610 signal(SIGWINCH, TermSizeSigHandler);
2612 signal(SIGINT, IntSigHandler);
2613 signal(SIGTERM, IntSigHandler);
2614 if (*appData.cmailGameName != NULLCHAR) {
2615 signal(SIGUSR1, CmailSigHandler);
2618 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2620 XtSetKeyboardFocus(shellWidget, formWidget);
2622 XtAppMainLoop(appContext);
2623 if (appData.debugMode) fclose(debugFP); // [DM] debug
2630 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2631 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2633 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2634 unlink(gameCopyFilename);
2635 unlink(gamePasteFilename);
2638 RETSIGTYPE TermSizeSigHandler(int sig)
2651 CmailSigHandler(sig)
2657 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2659 /* Activate call-back function CmailSigHandlerCallBack() */
2660 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2662 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2666 CmailSigHandlerCallBack(isr, closure, message, count, error)
2674 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2676 /**** end signal code ****/
2682 /* try to open the icsLogon script, either in the location given
2683 * or in the users HOME directory
2690 f = fopen(appData.icsLogon, "r");
2693 homedir = getenv("HOME");
2694 if (homedir != NULL)
2696 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2697 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2698 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2699 f = fopen(buf, "r");
2704 ProcessICSInitScript(f);
2706 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2729 if (!menuBarWidget) return;
2730 w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2732 DisplayError("menuEdit.Revert", 0);
2734 XtSetSensitive(w, !grey);
2736 w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2738 DisplayError("menuEdit.Annotate", 0);
2740 XtSetSensitive(w, !grey);
2745 SetMenuEnables(enab)
2749 if (!menuBarWidget) return;
2750 while (enab->name != NULL) {
2751 w = XtNameToWidget(menuBarWidget, enab->name);
2753 DisplayError(enab->name, 0);
2755 XtSetSensitive(w, enab->value);
2761 Enables icsEnables[] = {
2762 { "menuFile.Mail Move", False },
2763 { "menuFile.Reload CMail Message", False },
2764 { "menuMode.Machine Black", False },
2765 { "menuMode.Machine White", False },
2766 { "menuMode.Analysis Mode", False },
2767 { "menuMode.Analyze File", False },
2768 { "menuMode.Two Machines", False },
2769 { "menuMode.Machine Match", False },
2771 { "menuEngine.Hint", False },
2772 { "menuEngine.Book", False },
2773 { "menuEngine.Move Now", False },
2774 #ifndef OPTIONSDIALOG
2775 { "menuOptions.Periodic Updates", False },
2776 { "menuOptions.Hide Thinking", False },
2777 { "menuOptions.Ponder Next Move", False },
2779 { "menuEngine.Engine #1 Settings", False },
2781 { "menuEngine.Engine #2 Settings", False },
2782 { "menuEdit.Annotate", False },
2786 Enables ncpEnables[] = {
2787 { "menuFile.Mail Move", False },
2788 { "menuFile.Reload CMail Message", False },
2789 { "menuMode.Machine White", False },
2790 { "menuMode.Machine Black", False },
2791 { "menuMode.Analysis Mode", False },
2792 { "menuMode.Analyze File", False },
2793 { "menuMode.Two Machines", False },
2794 { "menuMode.Machine Match", False },
2795 { "menuMode.ICS Client", False },
2796 { "menuView.ICStex", False },
2797 { "menuView.ICS Input Box", False },
2798 { "Action", False },
2799 { "menuEdit.Revert", False },
2800 { "menuEdit.Annotate", False },
2801 { "menuEngine.Engine #1 Settings", False },
2802 { "menuEngine.Engine #2 Settings", False },
2803 { "menuEngine.Move Now", False },
2804 { "menuEngine.Retract Move", False },
2805 { "menuOptions.ICS", False },
2806 #ifndef OPTIONSDIALOG
2807 { "menuOptions.Auto Flag", False },
2808 { "menuOptions.Auto Flip View", False },
2809 // { "menuOptions.ICS Alarm", False },
2810 { "menuOptions.Move Sound", False },
2811 { "menuOptions.Hide Thinking", False },
2812 { "menuOptions.Periodic Updates", False },
2813 { "menuOptions.Ponder Next Move", False },
2815 { "menuEngine.Hint", False },
2816 { "menuEngine.Book", False },
2820 Enables gnuEnables[] = {
2821 { "menuMode.ICS Client", False },
2822 { "menuView.ICStex", False },
2823 { "menuView.ICS Input Box", False },
2824 { "menuAction.Accept", False },
2825 { "menuAction.Decline", False },
2826 { "menuAction.Rematch", False },
2827 { "menuAction.Adjourn", False },
2828 { "menuAction.Stop Examining", False },
2829 { "menuAction.Stop Observing", False },
2830 { "menuAction.Upload to Examine", False },
2831 { "menuEdit.Revert", False },
2832 { "menuEdit.Annotate", False },
2833 { "menuOptions.ICS", False },
2835 /* The next two options rely on SetCmailMode being called *after* */
2836 /* SetGNUMode so that when GNU is being used to give hints these */
2837 /* menu options are still available */
2839 { "menuFile.Mail Move", False },
2840 { "menuFile.Reload CMail Message", False },
2844 Enables cmailEnables[] = {
2846 { "menuAction.Call Flag", False },
2847 { "menuAction.Draw", True },
2848 { "menuAction.Adjourn", False },
2849 { "menuAction.Abort", False },
2850 { "menuAction.Stop Observing", False },
2851 { "menuAction.Stop Examining", False },
2852 { "menuFile.Mail Move", True },
2853 { "menuFile.Reload CMail Message", True },
2857 Enables trainingOnEnables[] = {
2858 { "menuMode.Edit Comment", False },
2859 { "menuMode.Pause", False },
2860 { "menuEdit.Forward", False },
2861 { "menuEdit.Backward", False },
2862 { "menuEdit.Forward to End", False },
2863 { "menuEdit.Back to Start", False },
2864 { "menuEngine.Move Now", False },
2865 { "menuEdit.Truncate Game", False },
2869 Enables trainingOffEnables[] = {
2870 { "menuMode.Edit Comment", True },
2871 { "menuMode.Pause", True },
2872 { "menuEdit.Forward", True },
2873 { "menuEdit.Backward", True },
2874 { "menuEdit.Forward to End", True },
2875 { "menuEdit.Back to Start", True },
2876 { "menuEngine.Move Now", True },
2877 { "menuEdit.Truncate Game", True },
2881 Enables machineThinkingEnables[] = {
2882 { "menuFile.Load Game", False },
2883 // { "menuFile.Load Next Game", False },
2884 // { "menuFile.Load Previous Game", False },
2885 // { "menuFile.Reload Same Game", False },
2886 { "menuEdit.Paste Game", False },
2887 { "menuFile.Load Position", False },
2888 // { "menuFile.Load Next Position", False },
2889 // { "menuFile.Load Previous Position", False },
2890 // { "menuFile.Reload Same Position", False },
2891 { "menuEdit.Paste Position", False },
2892 { "menuMode.Machine White", False },
2893 { "menuMode.Machine Black", False },
2894 { "menuMode.Two Machines", False },
2895 { "menuMode.Machine Match", False },
2896 { "menuEngine.Retract Move", False },
2900 Enables userThinkingEnables[] = {
2901 { "menuFile.Load Game", True },
2902 // { "menuFile.Load Next Game", True },
2903 // { "menuFile.Load Previous Game", True },
2904 // { "menuFile.Reload Same Game", True },
2905 { "menuEdit.Paste Game", True },
2906 { "menuFile.Load Position", True },
2907 // { "menuFile.Load Next Position", True },
2908 // { "menuFile.Load Previous Position", True },
2909 // { "menuFile.Reload Same Position", True },
2910 { "menuEdit.Paste Position", True },
2911 { "menuMode.Machine White", True },
2912 { "menuMode.Machine Black", True },
2913 { "menuMode.Two Machines", True },
2914 { "menuMode.Machine Match", True },
2915 { "menuEngine.Retract Move", True },
2921 SetMenuEnables(icsEnables);
2924 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2925 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2932 SetMenuEnables(ncpEnables);
2938 SetMenuEnables(gnuEnables);
2944 SetMenuEnables(cmailEnables);
2950 SetMenuEnables(trainingOnEnables);
2951 if (appData.showButtonBar) {
2952 XtSetSensitive(buttonBarWidget, False);
2958 SetTrainingModeOff()
2960 SetMenuEnables(trainingOffEnables);
2961 if (appData.showButtonBar) {
2962 XtSetSensitive(buttonBarWidget, True);
2967 SetUserThinkingEnables()
2969 if (appData.noChessProgram) return;
2970 SetMenuEnables(userThinkingEnables);
2974 SetMachineThinkingEnables()
2976 if (appData.noChessProgram) return;
2977 SetMenuEnables(machineThinkingEnables);
2979 case MachinePlaysBlack:
2980 case MachinePlaysWhite:
2981 case TwoMachinesPlay:
2982 XtSetSensitive(XtNameToWidget(menuBarWidget,
2983 ModeToWidgetName(gameMode)), True);
2990 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2991 #define HISTORY_SIZE 64
2992 static char *history[HISTORY_SIZE];
2993 int histIn = 0, histP = 0;
2996 SaveInHistory(char *cmd)
2998 if (history[histIn] != NULL) {
2999 free(history[histIn]);
3000 history[histIn] = NULL;
3002 if (*cmd == NULLCHAR) return;
3003 history[histIn] = StrSave(cmd);
3004 histIn = (histIn + 1) % HISTORY_SIZE;
3005 if (history[histIn] != NULL) {
3006 free(history[histIn]);
3007 history[histIn] = NULL;
3013 PrevInHistory(char *cmd)
3016 if (histP == histIn) {
3017 if (history[histIn] != NULL) free(history[histIn]);
3018 history[histIn] = StrSave(cmd);
3020 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
3021 if (newhp == histIn || history[newhp] == NULL) return NULL;
3023 return history[histP];
3029 if (histP == histIn) return NULL;
3030 histP = (histP + 1) % HISTORY_SIZE;
3031 return history[histP];
3033 // end of borrowed code
3035 #define Abs(n) ((n)<0 ? -(n) : (n))
3038 * Find a font that matches "pattern" that is as close as
3039 * possible to the targetPxlSize. Prefer fonts that are k
3040 * pixels smaller to fonts that are k pixels larger. The
3041 * pattern must be in the X Consortium standard format,
3042 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3043 * The return value should be freed with XtFree when no
3047 FindFont(pattern, targetPxlSize)
3051 char **fonts, *p, *best, *scalable, *scalableTail;
3052 int i, j, nfonts, minerr, err, pxlSize;
3055 char **missing_list;
3057 char *def_string, *base_fnt_lst, strInt[3];
3059 XFontStruct **fnt_list;
3061 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3062 snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize);
3063 p = strstr(pattern, "--");
3064 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3065 strcat(base_fnt_lst, strInt);
3066 strcat(base_fnt_lst, strchr(p + 2, '-'));
3068 if ((fntSet = XCreateFontSet(xDisplay,
3072 &def_string)) == NULL) {
3074 fprintf(stderr, _("Unable to create font set.\n"));
3078 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3080 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3082 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3083 programName, pattern);
3091 for (i=0; i<nfonts; i++) {
3094 if (*p != '-') continue;
3096 if (*p == NULLCHAR) break;
3097 if (*p++ == '-') j++;
3099 if (j < 7) continue;
3102 scalable = fonts[i];
3105 err = pxlSize - targetPxlSize;
3106 if (Abs(err) < Abs(minerr) ||
3107 (minerr > 0 && err < 0 && -err == minerr)) {
3113 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3114 /* If the error is too big and there is a scalable font,
3115 use the scalable font. */
3116 int headlen = scalableTail - scalable;
3117 p = (char *) XtMalloc(strlen(scalable) + 10);
3118 while (isdigit(*scalableTail)) scalableTail++;
3119 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3121 p = (char *) XtMalloc(strlen(best) + 2);
3122 safeStrCpy(p, best, strlen(best)+1 );
3124 if (appData.debugMode) {
3125 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3126 pattern, targetPxlSize, p);
3129 if (missing_count > 0)
3130 XFreeStringList(missing_list);
3131 XFreeFontSet(xDisplay, fntSet);
3133 XFreeFontNames(fonts);
3139 { // [HGM] deletes GCs that are to be remade, to prevent resource leak;
3140 // must be called before all non-first callse to CreateGCs()
3141 XtReleaseGC(shellWidget, highlineGC);
3142 XtReleaseGC(shellWidget, lightSquareGC);
3143 XtReleaseGC(shellWidget, darkSquareGC);
3144 XtReleaseGC(shellWidget, lineGC);
3145 if (appData.monoMode) {
3146 if (DefaultDepth(xDisplay, xScreen) == 1) {
3147 XtReleaseGC(shellWidget, wbPieceGC);
3149 XtReleaseGC(shellWidget, bwPieceGC);
3152 XtReleaseGC(shellWidget, prelineGC);
3153 XtReleaseGC(shellWidget, jailSquareGC);
3154 XtReleaseGC(shellWidget, wdPieceGC);
3155 XtReleaseGC(shellWidget, wlPieceGC);
3156 XtReleaseGC(shellWidget, wjPieceGC);
3157 XtReleaseGC(shellWidget, bdPieceGC);
3158 XtReleaseGC(shellWidget, blPieceGC);
3159 XtReleaseGC(shellWidget, bjPieceGC);
3163 void CreateGCs(int redo)
3165 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3166 | GCBackground | GCFunction | GCPlaneMask;
3167 XGCValues gc_values;
3170 gc_values.plane_mask = AllPlanes;
3171 gc_values.line_width = lineGap;
3172 gc_values.line_style = LineSolid;
3173 gc_values.function = GXcopy;
3176 DeleteGCs(); // called a second time; clean up old GCs first
3177 } else { // [HGM] grid and font GCs created on first call only
3178 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3179 gc_values.background = XWhitePixel(xDisplay, xScreen);
3180 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3181 XSetFont(xDisplay, coordGC, coordFontID);
3183 // [HGM] make font for holdings counts (white on black)
3184 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3185 gc_values.background = XBlackPixel(xDisplay, xScreen);
3186 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3187 XSetFont(xDisplay, countGC, countFontID);
3189 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3190 gc_values.background = XBlackPixel(xDisplay, xScreen);
3191 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3193 if (appData.monoMode) {
3194 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3195 gc_values.background = XWhitePixel(xDisplay, xScreen);
3196 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3198 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3199 gc_values.background = XBlackPixel(xDisplay, xScreen);
3200 lightSquareGC = wbPieceGC
3201 = XtGetGC(shellWidget, value_mask, &gc_values);
3203 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3204 gc_values.background = XWhitePixel(xDisplay, xScreen);
3205 darkSquareGC = bwPieceGC
3206 = XtGetGC(shellWidget, value_mask, &gc_values);
3208 if (DefaultDepth(xDisplay, xScreen) == 1) {
3209 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3210 gc_values.function = GXcopyInverted;
3211 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3212 gc_values.function = GXcopy;
3213 if (XBlackPixel(xDisplay, xScreen) == 1) {
3214 bwPieceGC = darkSquareGC;
3215 wbPieceGC = copyInvertedGC;
3217 bwPieceGC = copyInvertedGC;
3218 wbPieceGC = lightSquareGC;
3222 gc_values.foreground = highlightSquareColor;
3223 gc_values.background = highlightSquareColor;
3224 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3226 gc_values.foreground = premoveHighlightColor;
3227 gc_values.background = premoveHighlightColor;
3228 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3230 gc_values.foreground = lightSquareColor;
3231 gc_values.background = darkSquareColor;
3232 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3234 gc_values.foreground = darkSquareColor;
3235 gc_values.background = lightSquareColor;
3236 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3238 gc_values.foreground = jailSquareColor;
3239 gc_values.background = jailSquareColor;
3240 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3242 gc_values.foreground = whitePieceColor;
3243 gc_values.background = darkSquareColor;
3244 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3246 gc_values.foreground = whitePieceColor;
3247 gc_values.background = lightSquareColor;
3248 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3250 gc_values.foreground = whitePieceColor;
3251 gc_values.background = jailSquareColor;
3252 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3254 gc_values.foreground = blackPieceColor;
3255 gc_values.background = darkSquareColor;
3256 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3258 gc_values.foreground = blackPieceColor;
3259 gc_values.background = lightSquareColor;
3260 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3262 gc_values.foreground = blackPieceColor;
3263 gc_values.background = jailSquareColor;
3264 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3268 void loadXIM(xim, xmask, filename, dest, mask)
3281 fp = fopen(filename, "rb");
3283 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3290 for (y=0; y<h; ++y) {
3291 for (x=0; x<h; ++x) {
3296 XPutPixel(xim, x, y, blackPieceColor);
3298 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3301 XPutPixel(xim, x, y, darkSquareColor);
3303 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3306 XPutPixel(xim, x, y, whitePieceColor);
3308 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3311 XPutPixel(xim, x, y, lightSquareColor);
3313 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3321 /* create Pixmap of piece */
3322 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3324 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3327 /* create Pixmap of clipmask
3328 Note: We assume the white/black pieces have the same
3329 outline, so we make only 6 masks. This is okay
3330 since the XPM clipmask routines do the same. */
3332 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3334 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3337 /* now create the 1-bit version */
3338 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3341 values.foreground = 1;
3342 values.background = 0;
3344 /* Don't use XtGetGC, not read only */
3345 maskGC = XCreateGC(xDisplay, *mask,
3346 GCForeground | GCBackground, &values);
3347 XCopyPlane(xDisplay, temp, *mask, maskGC,
3348 0, 0, squareSize, squareSize, 0, 0, 1);
3349 XFreePixmap(xDisplay, temp);
3354 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3356 void CreateXIMPieces()
3361 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3366 /* The XSynchronize calls were copied from CreatePieces.
3367 Not sure if needed, but can't hurt */
3368 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3371 /* temp needed by loadXIM() */
3372 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3373 0, 0, ss, ss, AllPlanes, XYPixmap);
3375 if (strlen(appData.pixmapDirectory) == 0) {
3379 if (appData.monoMode) {
3380 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3384 fprintf(stderr, _("\nLoading XIMs...\n"));
3386 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3387 fprintf(stderr, "%d", piece+1);
3388 for (kind=0; kind<4; kind++) {
3389 fprintf(stderr, ".");
3390 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3391 ExpandPathName(appData.pixmapDirectory),
3392 piece <= (int) WhiteKing ? "" : "w",
3393 pieceBitmapNames[piece],
3395 ximPieceBitmap[kind][piece] =
3396 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3397 0, 0, ss, ss, AllPlanes, XYPixmap);
3398 if (appData.debugMode)
3399 fprintf(stderr, _("(File:%s:) "), buf);
3400 loadXIM(ximPieceBitmap[kind][piece],
3402 &(xpmPieceBitmap2[kind][piece]),
3403 &(ximMaskPm2[piece]));
3404 if(piece <= (int)WhiteKing)
3405 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3407 fprintf(stderr," ");
3409 /* Load light and dark squares */
3410 /* If the LSQ and DSQ pieces don't exist, we will
3411 draw them with solid squares. */
3412 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3413 if (access(buf, 0) != 0) {
3417 fprintf(stderr, _("light square "));
3419 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3420 0, 0, ss, ss, AllPlanes, XYPixmap);
3421 if (appData.debugMode)
3422 fprintf(stderr, _("(File:%s:) "), buf);
3424 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3425 fprintf(stderr, _("dark square "));
3426 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3427 ExpandPathName(appData.pixmapDirectory), ss);
3428 if (appData.debugMode)
3429 fprintf(stderr, _("(File:%s:) "), buf);
3431 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3432 0, 0, ss, ss, AllPlanes, XYPixmap);
3433 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3434 xpmJailSquare = xpmLightSquare;
3436 fprintf(stderr, _("Done.\n"));
3438 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3441 static VariantClass oldVariant = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
3444 void CreateXPMBoard(char *s, int kind)
3448 if(s == NULL || *s == 0 || *s == '*') { useTexture &= ~(kind+1); return; }
3449 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3450 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3454 void FreeXPMPieces()
3455 { // [HGM] to prevent resoucre leak on calling CreaeXPMPieces() a second time,
3456 // thisroutine has to be called t free the old piece pixmaps
3458 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++)
3459 for (kind=0; kind<4; kind++) XFreePixmap(xDisplay, xpmPieceBitmap2[kind][piece]);
3461 XFreePixmap(xDisplay, xpmLightSquare);
3462 XFreePixmap(xDisplay, xpmDarkSquare);
3466 void CreateXPMPieces()
3470 u_int ss = squareSize;
3472 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3473 XpmColorSymbol symbols[4];
3474 static int redo = False;
3476 if(redo) FreeXPMPieces(); else redo = 1;
3478 /* The XSynchronize calls were copied from CreatePieces.
3479 Not sure if needed, but can't hurt */
3480 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3482 /* Setup translations so piece colors match square colors */
3483 symbols[0].name = "light_piece";
3484 symbols[0].value = appData.whitePieceColor;
3485 symbols[1].name = "dark_piece";
3486 symbols[1].value = appData.blackPieceColor;
3487 symbols[2].name = "light_square";
3488 symbols[2].value = appData.lightSquareColor;
3489 symbols[3].name = "dark_square";
3490 symbols[3].value = appData.darkSquareColor;
3492 attr.valuemask = XpmColorSymbols;
3493 attr.colorsymbols = symbols;
3494 attr.numsymbols = 4;
3496 if (appData.monoMode) {
3497 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3501 if (strlen(appData.pixmapDirectory) == 0) {
3502 XpmPieces* pieces = builtInXpms;
3505 while (pieces->size != squareSize && pieces->size) pieces++;
3506 if (!pieces->size) {
3507 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3510 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3511 for (kind=0; kind<4; kind++) {
3513 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3514 pieces->xpm[piece][kind],
3515 &(xpmPieceBitmap2[kind][piece]),
3516 NULL, &attr)) != 0) {
3517 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3521 if(piece <= (int) WhiteKing)
3522 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3526 xpmJailSquare = xpmLightSquare;
3530 fprintf(stderr, _("\nLoading XPMs...\n"));
3533 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3534 fprintf(stderr, "%d ", piece+1);
3535 for (kind=0; kind<4; kind++) {
3536 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3537 ExpandPathName(appData.pixmapDirectory),
3538 piece > (int) WhiteKing ? "w" : "",
3539 pieceBitmapNames[piece],
3541 if (appData.debugMode) {
3542 fprintf(stderr, _("(File:%s:) "), buf);
3544 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3545 &(xpmPieceBitmap2[kind][piece]),
3546 NULL, &attr)) != 0) {
3547 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3548 // [HGM] missing: read of unorthodox piece failed; substitute King.
3549 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3550 ExpandPathName(appData.pixmapDirectory),
3552 if (appData.debugMode) {
3553 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3555 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3556 &(xpmPieceBitmap2[kind][piece]),
3560 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3565 if(piece <= (int) WhiteKing)
3566 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3569 /* Load light and dark squares */
3570 /* If the LSQ and DSQ pieces don't exist, we will
3571 draw them with solid squares. */
3572 fprintf(stderr, _("light square "));
3573 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3574 if (access(buf, 0) != 0) {
3578 if (appData.debugMode)
3579 fprintf(stderr, _("(File:%s:) "), buf);
3581 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3582 &xpmLightSquare, NULL, &attr)) != 0) {
3583 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3586 fprintf(stderr, _("dark square "));
3587 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3588 ExpandPathName(appData.pixmapDirectory), ss);
3589 if (appData.debugMode) {
3590 fprintf(stderr, _("(File:%s:) "), buf);
3592 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3593 &xpmDarkSquare, NULL, &attr)) != 0) {
3594 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3598 xpmJailSquare = xpmLightSquare;
3599 fprintf(stderr, _("Done.\n"));
3601 oldVariant = -1; // kludge to force re-makig of animation masks
3602 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3605 #endif /* HAVE_LIBXPM */
3608 /* No built-in bitmaps */
3613 u_int ss = squareSize;
3615 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3618 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3619 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3620 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3621 pieceBitmapNames[piece],
3622 ss, kind == SOLID ? 's' : 'o');
3623 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3624 if(piece <= (int)WhiteKing)
3625 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3629 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3633 /* With built-in bitmaps */
3636 BuiltInBits* bib = builtInBits;
3639 u_int ss = squareSize;
3641 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3644 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3646 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3647 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3648 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3649 pieceBitmapNames[piece],
3650 ss, kind == SOLID ? 's' : 'o');
3651 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3652 bib->bits[kind][piece], ss, ss);
3653 if(piece <= (int)WhiteKing)
3654 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3658 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3663 void ReadBitmap(pm, name, bits, wreq, hreq)
3666 unsigned char bits[];
3672 char msg[MSG_SIZ], fullname[MSG_SIZ];
3674 if (*appData.bitmapDirectory != NULLCHAR) {
3675 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3676 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3677 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3678 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3679 &w, &h, pm, &x_hot, &y_hot);
3680 fprintf(stderr, "load %s\n", name);
3681 if (errcode != BitmapSuccess) {
3683 case BitmapOpenFailed:
3684 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3686 case BitmapFileInvalid:
3687 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3689 case BitmapNoMemory:
3690 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3694 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3698 fprintf(stderr, _("%s: %s...using built-in\n"),
3700 } else if (w != wreq || h != hreq) {
3702 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3703 programName, fullname, w, h, wreq, hreq);
3709 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3718 if (lineGap == 0) return;
3720 /* [HR] Split this into 2 loops for non-square boards. */
3722 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3723 gridSegments[i].x1 = 0;
3724 gridSegments[i].x2 =
3725 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3726 gridSegments[i].y1 = gridSegments[i].y2
3727 = lineGap / 2 + (i * (squareSize + lineGap));
3730 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3731 gridSegments[j + i].y1 = 0;
3732 gridSegments[j + i].y2 =
3733 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3734 gridSegments[j + i].x1 = gridSegments[j + i].x2
3735 = lineGap / 2 + (j * (squareSize + lineGap));
3739 static void MenuBarSelect(w, addr, index)
3744 XtActionProc proc = (XtActionProc) addr;
3746 (proc)(NULL, NULL, NULL, NULL);
3749 void CreateMenuBarPopup(parent, name, mb)
3759 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3762 XtSetArg(args[j], XtNleftMargin, 20); j++;
3763 XtSetArg(args[j], XtNrightMargin, 20); j++;
3765 while (mi->string != NULL) {
3766 if (strcmp(mi->string, "----") == 0) {
3767 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3770 XtSetArg(args[j], XtNlabel, XtNewString(mi->string));
3771 entry = XtCreateManagedWidget(mi->ref, smeBSBObjectClass,
3773 XtAddCallback(entry, XtNcallback,
3774 (XtCallbackProc) MenuBarSelect,
3775 (caddr_t) mi->proc);
3781 Widget CreateMenuBar(mb)
3785 Widget anchor, menuBar;
3787 char menuName[MSG_SIZ];
3790 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3791 XtSetArg(args[j], XtNvSpace, 0); j++;
3792 XtSetArg(args[j], XtNborderWidth, 0); j++;
3793 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3794 formWidget, args, j);
3796 while (mb->name != NULL) {
3797 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3798 strncat(menuName, mb->ref, MSG_SIZ - strlen(menuName) - 1);
3800 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3803 shortName[0] = mb->name[0];
3804 shortName[1] = NULLCHAR;
3805 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3808 XtSetArg(args[j], XtNlabel, XtNewString(mb->name)); j++;
3811 XtSetArg(args[j], XtNborderWidth, 0); j++;
3812 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3814 CreateMenuBarPopup(menuBar, menuName, mb);
3820 Widget CreateButtonBar(mi)
3824 Widget button, buttonBar;
3828 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3830 XtSetArg(args[j], XtNhSpace, 0); j++;
3832 XtSetArg(args[j], XtNborderWidth, 0); j++;
3833 XtSetArg(args[j], XtNvSpace, 0); j++;
3834 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3835 formWidget, args, j);
3837 while (mi->string != NULL) {
3840 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3841 XtSetArg(args[j], XtNborderWidth, 0); j++;
3843 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3844 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3845 buttonBar, args, j);
3846 XtAddCallback(button, XtNcallback,
3847 (XtCallbackProc) MenuBarSelect,
3848 (caddr_t) mi->proc);
3855 CreatePieceMenu(name, color)
3862 ChessSquare selection;
3864 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3865 boardWidget, args, 0);
3867 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3868 String item = pieceMenuStrings[color][i];
3870 if (strcmp(item, "----") == 0) {
3871 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3874 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3875 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3877 selection = pieceMenuTranslation[color][i];
3878 XtAddCallback(entry, XtNcallback,
3879 (XtCallbackProc) PieceMenuSelect,
3880 (caddr_t) selection);
3881 if (selection == WhitePawn || selection == BlackPawn) {
3882 XtSetArg(args[0], XtNpopupOnEntry, entry);
3883 XtSetValues(menu, args, 1);
3896 ChessSquare selection;
3898 whitePieceMenu = CreatePieceMenu("menuW", 0);
3899 blackPieceMenu = CreatePieceMenu("menuB", 1);
3901 XtRegisterGrabAction(PieceMenuPopup, True,
3902 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3903 GrabModeAsync, GrabModeAsync);
3905 XtSetArg(args[0], XtNlabel, _("Drop"));
3906 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3907 boardWidget, args, 1);
3908 for (i = 0; i < DROP_MENU_SIZE; i++) {
3909 String item = dropMenuStrings[i];
3911 if (strcmp(item, "----") == 0) {
3912 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3915 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3916 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3918 selection = dropMenuTranslation[i];
3919 XtAddCallback(entry, XtNcallback,
3920 (XtCallbackProc) DropMenuSelect,
3921 (caddr_t) selection);
3926 void SetupDropMenu()
3934 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3935 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3936 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3937 dmEnables[i].piece);
3938 XtSetSensitive(entry, p != NULL || !appData.testLegality
3939 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3940 && !appData.icsActive));
3942 while (p && *p++ == dmEnables[i].piece) count++;
3943 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3945 XtSetArg(args[j], XtNlabel, label); j++;
3946 XtSetValues(entry, args, j);
3950 void PieceMenuPopup(w, event, params, num_params)
3954 Cardinal *num_params;
3956 String whichMenu; int menuNr;
3957 shiftKey = strcmp(params[0], "menuW"); // used to indicate black
3958 if (event->type == ButtonRelease)
3959 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3960 else if (event->type == ButtonPress)
3961 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3963 case 0: whichMenu = params[0]; break;
3964 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3966 case -1: if (errorUp) ErrorPopDown();
3969 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3972 static void PieceMenuSelect(w, piece, junk)
3977 if (pmFromX < 0 || pmFromY < 0) return;
3978 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3981 static void DropMenuSelect(w, piece, junk)
3986 if (pmFromX < 0 || pmFromY < 0) return;
3987 DropMenuEvent(piece, pmFromX, pmFromY);
3990 void WhiteClock(w, event, prms, nprms)
3999 void BlackClock(w, event, prms, nprms)
4010 * If the user selects on a border boundary, return -1; if off the board,
4011 * return -2. Otherwise map the event coordinate to the square.
4013 int EventToSquare(x, limit)
4021 if ((x % (squareSize + lineGap)) >= squareSize)
4023 x /= (squareSize + lineGap);
4029 static void do_flash_delay(msec)
4035 static void drawHighlight(file, rank, gc)
4041 if (lineGap == 0) return;
4044 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
4045 (squareSize + lineGap);
4046 y = lineGap/2 + rank * (squareSize + lineGap);
4048 x = lineGap/2 + file * (squareSize + lineGap);
4049 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
4050 (squareSize + lineGap);
4053 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
4054 squareSize+lineGap, squareSize+lineGap);
4057 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
4058 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4061 SetHighlights(fromX, fromY, toX, toY)
4062 int fromX, fromY, toX, toY;
4064 if (hi1X != fromX || hi1Y != fromY) {
4065 if (hi1X >= 0 && hi1Y >= 0) {
4066 drawHighlight(hi1X, hi1Y, lineGC);
4068 } // [HGM] first erase both, then draw new!
4069 if (hi2X != toX || hi2Y != toY) {
4070 if (hi2X >= 0 && hi2Y >= 0) {
4071 drawHighlight(hi2X, hi2Y, lineGC);
4074 if (hi1X != fromX || hi1Y != fromY) {
4075 if (fromX >= 0 && fromY >= 0) {
4076 drawHighlight(fromX, fromY, highlineGC);
4079 if (hi2X != toX || hi2Y != toY) {
4080 if (toX >= 0 && toY >= 0) {
4081 drawHighlight(toX, toY, highlineGC);
4093 SetHighlights(-1, -1, -1, -1);
4098 SetPremoveHighlights(fromX, fromY, toX, toY)
4099 int fromX, fromY, toX, toY;
4101 if (pm1X != fromX || pm1Y != fromY) {
4102 if (pm1X >= 0 && pm1Y >= 0) {
4103 drawHighlight(pm1X, pm1Y, lineGC);
4105 if (fromX >= 0 && fromY >= 0) {
4106 drawHighlight(fromX, fromY, prelineGC);
4109 if (pm2X != toX || pm2Y != toY) {
4110 if (pm2X >= 0 && pm2Y >= 0) {
4111 drawHighlight(pm2X, pm2Y, lineGC);
4113 if (toX >= 0 && toY >= 0) {
4114 drawHighlight(toX, toY, prelineGC);
4124 ClearPremoveHighlights()
4126 SetPremoveHighlights(-1, -1, -1, -1);
4129 static int CutOutSquare(x, y, x0, y0, kind)
4130 int x, y, *x0, *y0, kind;
4132 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
4133 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
4135 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
4136 if(textureW[kind] < W*squareSize)
4137 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
4139 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
4140 if(textureH[kind] < H*squareSize)
4141 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
4143 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
4147 static void BlankSquare(x, y, color, piece, dest, fac)
4148 int x, y, color, fac;
4151 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
4153 if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
4154 XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
4155 squareSize, squareSize, x*fac, y*fac);
4157 if (useImages && useImageSqs) {
4161 pm = xpmLightSquare;
4166 case 2: /* neutral */
4171 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4172 squareSize, squareSize, x*fac, y*fac);
4182 case 2: /* neutral */
4187 XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
4192 I split out the routines to draw a piece so that I could
4193 make a generic flash routine.
4195 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4197 int square_color, x, y;
4200 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4201 switch (square_color) {
4203 case 2: /* neutral */
4205 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4206 ? *pieceToOutline(piece)
4207 : *pieceToSolid(piece),
4208 dest, bwPieceGC, 0, 0,
4209 squareSize, squareSize, x, y);
4212 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4213 ? *pieceToSolid(piece)
4214 : *pieceToOutline(piece),
4215 dest, wbPieceGC, 0, 0,
4216 squareSize, squareSize, x, y);
4221 static void monoDrawPiece(piece, square_color, x, y, dest)
4223 int square_color, x, y;
4226 switch (square_color) {
4228 case 2: /* neutral */
4230 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4231 ? *pieceToOutline(piece)
4232 : *pieceToSolid(piece),
4233 dest, bwPieceGC, 0, 0,
4234 squareSize, squareSize, x, y, 1);
4237 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4238 ? *pieceToSolid(piece)
4239 : *pieceToOutline(piece),
4240 dest, wbPieceGC, 0, 0,
4241 squareSize, squareSize, x, y, 1);
4246 static void colorDrawPiece(piece, square_color, x, y, dest)
4248 int square_color, x, y;
4251 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4252 switch (square_color) {
4254 XCopyPlane(xDisplay, *pieceToSolid(piece),
4255 dest, (int) piece < (int) BlackPawn
4256 ? wlPieceGC : blPieceGC, 0, 0,
4257 squareSize, squareSize, x, y, 1);
4260 XCopyPlane(xDisplay, *pieceToSolid(piece),
4261 dest, (int) piece < (int) BlackPawn
4262 ? wdPieceGC : bdPieceGC, 0, 0,
4263 squareSize, squareSize, x, y, 1);
4265 case 2: /* neutral */
4267 XCopyPlane(xDisplay, *pieceToSolid(piece),
4268 dest, (int) piece < (int) BlackPawn
4269 ? wjPieceGC : bjPieceGC, 0, 0,
4270 squareSize, squareSize, x, y, 1);
4275 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4277 int square_color, x, y;
4280 int kind, p = piece;
4282 switch (square_color) {
4284 case 2: /* neutral */
4286 if ((int)piece < (int) BlackPawn) {
4294 if ((int)piece < (int) BlackPawn) {
4302 if(appData.upsideDown && flipView) { kind ^= 2; p += p < BlackPawn ? BlackPawn : -BlackPawn; }// swap white and black pieces
4303 if(useTexture & square_color+1) {
4304 BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background
4305 XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]);
4306 XSetClipOrigin(xDisplay, wlPieceGC, x, y);
4307 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y);
4308 XSetClipMask(xDisplay, wlPieceGC, None);
4309 XSetClipOrigin(xDisplay, wlPieceGC, 0, 0);
4311 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4312 dest, wlPieceGC, 0, 0,
4313 squareSize, squareSize, x, y);
4316 typedef void (*DrawFunc)();
4318 DrawFunc ChooseDrawFunc()
4320 if (appData.monoMode) {
4321 if (DefaultDepth(xDisplay, xScreen) == 1) {
4322 return monoDrawPiece_1bit;
4324 return monoDrawPiece;
4328 return colorDrawPieceImage;
4330 return colorDrawPiece;
4334 /* [HR] determine square color depending on chess variant. */
4335 static int SquareColor(row, column)
4340 if (gameInfo.variant == VariantXiangqi) {
4341 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4343 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4345 } else if (row <= 4) {
4351 square_color = ((column + row) % 2) == 1;
4354 /* [hgm] holdings: next line makes all holdings squares light */
4355 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4357 return square_color;
4360 void DrawSquare(row, column, piece, do_flash)
4361 int row, column, do_flash;
4364 int square_color, x, y, direction, font_ascent, font_descent;
4367 XCharStruct overall;
4371 /* Calculate delay in milliseconds (2-delays per complete flash) */
4372 flash_delay = 500 / appData.flashRate;
4375 x = lineGap + ((BOARD_WIDTH-1)-column) *
4376 (squareSize + lineGap);
4377 y = lineGap + row * (squareSize + lineGap);
4379 x = lineGap + column * (squareSize + lineGap);
4380 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4381 (squareSize + lineGap);
4384 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4386 square_color = SquareColor(row, column);
4388 if ( // [HGM] holdings: blank out area between board and holdings
4389 column == BOARD_LEFT-1 || column == BOARD_RGHT
4390 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4391 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4392 BlankSquare(x, y, 2, EmptySquare, xBoardWindow, 1);
4394 // [HGM] print piece counts next to holdings
4395 string[1] = NULLCHAR;
4396 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4397 string[0] = '0' + piece;
4398 XTextExtents(countFontStruct, string, 1, &direction,
4399 &font_ascent, &font_descent, &overall);
4400 if (appData.monoMode) {
4401 XDrawImageString(xDisplay, xBoardWindow, countGC,
4402 x + squareSize - overall.width - 2,
4403 y + font_ascent + 1, string, 1);
4405 XDrawString(xDisplay, xBoardWindow, countGC,
4406 x + squareSize - overall.width - 2,
4407 y + font_ascent + 1, string, 1);
4410 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4411 string[0] = '0' + piece;
4412 XTextExtents(countFontStruct, string, 1, &direction,
4413 &font_ascent, &font_descent, &overall);
4414 if (appData.monoMode) {
4415 XDrawImageString(xDisplay, xBoardWindow, countGC,
4416 x + 2, y + font_ascent + 1, string, 1);
4418 XDrawString(xDisplay, xBoardWindow, countGC,
4419 x + 2, y + font_ascent + 1, string, 1);
4423 if (piece == EmptySquare || appData.blindfold) {
4424 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4426 drawfunc = ChooseDrawFunc();
4428 if (do_flash && appData.flashCount > 0) {
4429 for (i=0; i<appData.flashCount; ++i) {
4430 drawfunc(piece, square_color, x, y, xBoardWindow);
4431 XSync(xDisplay, False);
4432 do_flash_delay(flash_delay);
4434 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4435 XSync(xDisplay, False);
4436 do_flash_delay(flash_delay);
4439 drawfunc(piece, square_color, x, y, xBoardWindow);
4443 string[1] = NULLCHAR;
4444 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4445 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4446 string[0] = 'a' + column - BOARD_LEFT;
4447 XTextExtents(coordFontStruct, string, 1, &direction,
4448 &font_ascent, &font_descent, &overall);
4449 if (appData.monoMode) {
4450 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4451 x + squareSize - overall.width - 2,
4452 y + squareSize - font_descent - 1, string, 1);
4454 XDrawString(xDisplay, xBoardWindow, coordGC,
4455 x + squareSize - overall.width - 2,
4456 y + squareSize - font_descent - 1, string, 1);
4459 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4460 string[0] = ONE + row;
4461 XTextExtents(coordFontStruct, string, 1, &direction,
4462 &font_ascent, &font_descent, &overall);
4463 if (appData.monoMode) {
4464 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4465 x + 2, y + font_ascent + 1, string, 1);
4467 XDrawString(xDisplay, xBoardWindow, coordGC,
4468 x + 2, y + font_ascent + 1, string, 1);
4471 if(!partnerUp && marker[row][column]) {
4472 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4473 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4478 /* Why is this needed on some versions of X? */
4479 void EventProc(widget, unused, event)
4484 if (!XtIsRealized(widget))
4487 switch (event->type) {
4489 if (event->xexpose.count > 0) return; /* no clipping is done */
4490 XDrawPosition(widget, True, NULL);
4491 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4492 flipView = !flipView; partnerUp = !partnerUp;
4493 XDrawPosition(widget, True, NULL);
4494 flipView = !flipView; partnerUp = !partnerUp;
4498 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
4505 void DrawPosition(fullRedraw, board)
4506 /*Boolean*/int fullRedraw;
4509 XDrawPosition(boardWidget, fullRedraw, board);
4512 /* Returns 1 if there are "too many" differences between b1 and b2
4513 (i.e. more than 1 move was made) */
4514 static int too_many_diffs(b1, b2)
4520 for (i=0; i<BOARD_HEIGHT; ++i) {
4521 for (j=0; j<BOARD_WIDTH; ++j) {
4522 if (b1[i][j] != b2[i][j]) {
4523 if (++c > 4) /* Castling causes 4 diffs */
4531 /* Matrix describing castling maneuvers */
4532 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4533 static int castling_matrix[4][5] = {
4534 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4535 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4536 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4537 { 7, 7, 4, 5, 6 } /* 0-0, black */
4540 /* Checks whether castling occurred. If it did, *rrow and *rcol
4541 are set to the destination (row,col) of the rook that moved.
4543 Returns 1 if castling occurred, 0 if not.
4545 Note: Only handles a max of 1 castling move, so be sure
4546 to call too_many_diffs() first.
4548 static int check_castle_draw(newb, oldb, rrow, rcol)
4555 /* For each type of castling... */
4556 for (i=0; i<4; ++i) {
4557 r = castling_matrix[i];
4559 /* Check the 4 squares involved in the castling move */
4561 for (j=1; j<=4; ++j) {
4562 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4569 /* All 4 changed, so it must be a castling move */
4578 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4579 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4581 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4584 void DrawSeekBackground( int left, int top, int right, int bottom )
4586 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4589 void DrawSeekText(char *buf, int x, int y)
4591 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4594 void DrawSeekDot(int x, int y, int colorNr)
4596 int square = colorNr & 0x80;
4599 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4601 XFillRectangle(xDisplay, xBoardWindow, color,
4602 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4604 XFillArc(xDisplay, xBoardWindow, color,
4605 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4608 static int damage[2][BOARD_RANKS][BOARD_FILES];
4611 * event handler for redrawing the board
4613 void XDrawPosition(w, repaint, board)
4615 /*Boolean*/int repaint;
4619 static int lastFlipView = 0;
4620 static int lastBoardValid[2] = {0, 0};
4621 static Board lastBoard[2];
4624 int nr = twoBoards*partnerUp;
4626 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4628 if (board == NULL) {
4629 if (!lastBoardValid[nr]) return;
4630 board = lastBoard[nr];
4632 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4633 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4634 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Flip View"),
4639 * It would be simpler to clear the window with XClearWindow()
4640 * but this causes a very distracting flicker.
4643 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4645 if ( lineGap && IsDrawArrowEnabled())
4646 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4647 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4649 /* If too much changes (begin observing new game, etc.), don't
4651 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4653 /* Special check for castling so we don't flash both the king
4654 and the rook (just flash the king). */
4656 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4657 /* Draw rook with NO flashing. King will be drawn flashing later */
4658 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4659 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4663 /* First pass -- Draw (newly) empty squares and repair damage.
4664 This prevents you from having a piece show up twice while it
4665 is flashing on its new square */
4666 for (i = 0; i < BOARD_HEIGHT; i++)
4667 for (j = 0; j < BOARD_WIDTH; j++)
4668 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4669 || damage[nr][i][j]) {
4670 DrawSquare(i, j, board[i][j], 0);
4671 damage[nr][i][j] = False;
4674 /* Second pass -- Draw piece(s) in new position and flash them */
4675 for (i = 0; i < BOARD_HEIGHT; i++)
4676 for (j = 0; j < BOARD_WIDTH; j++)
4677 if (board[i][j] != lastBoard[nr][i][j]) {
4678 DrawSquare(i, j, board[i][j], do_flash);
4682 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4683 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4684 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4686 for (i = 0; i < BOARD_HEIGHT; i++)
4687 for (j = 0; j < BOARD_WIDTH; j++) {
4688 DrawSquare(i, j, board[i][j], 0);
4689 damage[nr][i][j] = False;
4693 CopyBoard(lastBoard[nr], board);
4694 lastBoardValid[nr] = 1;
4695 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4696 lastFlipView = flipView;
4698 /* Draw highlights */
4699 if (pm1X >= 0 && pm1Y >= 0) {
4700 drawHighlight(pm1X, pm1Y, prelineGC);
4702 if (pm2X >= 0 && pm2Y >= 0) {
4703 drawHighlight(pm2X, pm2Y, prelineGC);
4705 if (hi1X >= 0 && hi1Y >= 0) {
4706 drawHighlight(hi1X, hi1Y, highlineGC);
4708 if (hi2X >= 0 && hi2Y >= 0) {
4709 drawHighlight(hi2X, hi2Y, highlineGC);
4711 DrawArrowHighlight(hi1X, hi1Y, hi2X, hi2Y);
4713 /* If piece being dragged around board, must redraw that too */
4716 XSync(xDisplay, False);
4721 * event handler for redrawing the board
4723 void DrawPositionProc(w, event, prms, nprms)
4729 XDrawPosition(w, True, NULL);
4734 * event handler for parsing user moves
4736 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4737 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4738 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4739 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4740 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4741 // and at the end FinishMove() to perform the move after optional promotion popups.
4742 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4743 void HandleUserMove(w, event, prms, nprms)
4749 if (w != boardWidget || errorExitStatus != -1) return;
4750 if(nprms) shiftKey = !strcmp(prms[0], "1");
4753 if (event->type == ButtonPress) {
4754 XtPopdown(promotionShell);
4755 XtDestroyWidget(promotionShell);
4756 promotionUp = False;
4764 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4765 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4766 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4769 void AnimateUserMove (Widget w, XEvent * event,
4770 String * params, Cardinal * nParams)
4772 if(!PromoScroll(event->xmotion.x, event->xmotion.y))
4773 DragPieceMove(event->xmotion.x, event->xmotion.y);
4776 void HandlePV (Widget w, XEvent * event,
4777 String * params, Cardinal * nParams)
4778 { // [HGM] pv: walk PV
4779 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4782 static int savedIndex; /* gross that this is global */
4784 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
4787 XawTextPosition index, dummy;
4790 XawTextGetSelectionPos(w, &index, &dummy);
4791 XtSetArg(arg, XtNstring, &val);
4792 XtGetValues(w, &arg, 1);
4793 ReplaceComment(savedIndex, val);
4794 if(savedIndex != currentMove) ToNrEvent(savedIndex);
4795 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
4798 void EditCommentPopUp(index, title, text)
4803 if (text == NULL) text = "";
4804 NewCommentPopup(title, text, index);
4807 void ICSInputBoxPopUp()
4812 extern Option boxOptions[];
4814 void ICSInputSendText()
4821 edit = boxOptions[0].handle;
4823 XtSetArg(args[j], XtNstring, &val); j++;
4824 XtGetValues(edit, args, j);
4826 SendMultiLineToICS(val);
4827 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4828 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4831 void ICSInputBoxPopDown()
4836 void CommentPopUp(title, text)
4839 savedIndex = currentMove; // [HGM] vari
4840 NewCommentPopup(title, text, currentMove);
4843 void CommentPopDown()
4848 void FileNamePopUp(label, def, filter, proc, openMode)
4855 fileProc = proc; /* I can't see a way not */
4856 fileOpenMode = openMode; /* to use globals here */
4857 { // [HGM] use file-selector dialog stolen from Ghostview
4859 int index; // this is not supported yet
4861 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
4862 (def[0] ? def : NULL), filter, openMode, NULL, &name))
4863 (void) (*fileProc)(f, index=0, name);
4867 void FileNamePopDown()
4869 if (!filenameUp) return;
4870 XtPopdown(fileNameShell);
4871 XtDestroyWidget(fileNameShell);
4876 void FileNameCallback(w, client_data, call_data)
4878 XtPointer client_data, call_data;
4883 XtSetArg(args[0], XtNlabel, &name);
4884 XtGetValues(w, args, 1);
4886 if (strcmp(name, _("cancel")) == 0) {
4891 FileNameAction(w, NULL, NULL, NULL);
4894 void FileNameAction(w, event, prms, nprms)
4906 name = XawDialogGetValueString(w = XtParent(w));
4908 if ((name != NULL) && (*name != NULLCHAR)) {
4909 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
4910 XtPopdown(w = XtParent(XtParent(w)));
4914 p = strrchr(buf, ' ');
4921 fullname = ExpandPathName(buf);
4923 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
4926 f = fopen(fullname, fileOpenMode);
4928 DisplayError(_("Failed to open file"), errno);
4930 (void) (*fileProc)(f, index, buf);
4937 XtPopdown(w = XtParent(XtParent(w)));
4943 void PromotionPopUp()
4946 Widget dialog, layout;
4948 Dimension bw_width, pw_width;
4952 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4953 XtGetValues(boardWidget, args, j);
4956 XtSetArg(args[j], XtNresizable, True); j++;
4957 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
4959 XtCreatePopupShell("Promotion", transientShellWidgetClass,
4960 shellWidget, args, j);
4962 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
4963 layoutArgs, XtNumber(layoutArgs));
4966 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
4967 XtSetArg(args[j], XtNborderWidth, 0); j++;
4968 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
4971 if(gameInfo.variant != VariantShogi) {
4972 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) {
4973 XawDialogAddButton(dialog, _("Warlord"), PromotionCallback,
4974 (XtPointer) dialog);
4975 XawDialogAddButton(dialog, _("General"), PromotionCallback,
4976 (XtPointer) dialog);
4977 XawDialogAddButton(dialog, _("Lieutenant"), PromotionCallback,
4978 (XtPointer) dialog);
4979 XawDialogAddButton(dialog, _("Captain"), PromotionCallback,
4980 (XtPointer) dialog);
4982 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
4983 (XtPointer) dialog);
4984 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
4985 (XtPointer) dialog);
4986 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
4987 (XtPointer) dialog);
4988 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
4989 (XtPointer) dialog);
4991 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
4992 gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
\r
4993 gameInfo.variant == VariantGiveaway) {
4994 XawDialogAddButton(dialog, _("King"), PromotionCallback,
4995 (XtPointer) dialog);
4997 if(gameInfo.variant == VariantCapablanca ||
4998 gameInfo.variant == VariantGothic ||
4999 gameInfo.variant == VariantCapaRandom) {
5000 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5001 (XtPointer) dialog);
5002 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5003 (XtPointer) dialog);
5005 } else // [HGM] shogi
5007 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5008 (XtPointer) dialog);
5009 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5010 (XtPointer) dialog);
5012 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5013 (XtPointer) dialog);
5015 XtRealizeWidget(promotionShell);
5016 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5019 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5020 XtGetValues(promotionShell, args, j);
5022 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5023 lineGap + squareSize/3 +
5024 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5025 0 : 6*(squareSize + lineGap)), &x, &y);
5028 XtSetArg(args[j], XtNx, x); j++;
5029 XtSetArg(args[j], XtNy, y); j++;
5030 XtSetValues(promotionShell, args, j);
5032 XtPopup(promotionShell, XtGrabNone);
5037 void PromotionPopDown()
5039 if (!promotionUp) return;
5040 XtPopdown(promotionShell);
5041 XtDestroyWidget(promotionShell);
5042 promotionUp = False;
5045 void PromotionCallback(w, client_data, call_data)
5047 XtPointer client_data, call_data;
5053 XtSetArg(args[0], XtNlabel, &name);
5054 XtGetValues(w, args, 1);
5058 if (fromX == -1) return;
5060 if (strcmp(name, _("cancel")) == 0) {
5064 } else if (strcmp(name, _("Knight")) == 0) {
5066 } else if (strcmp(name, _("Promote")) == 0) {
5068 } else if (strcmp(name, _("Defer")) == 0) {
5071 promoChar = ToLower(name[0]);
5074 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5076 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5077 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5082 void ErrorCallback(w, client_data, call_data)
5084 XtPointer client_data, call_data;
5087 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5089 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5095 if (!errorUp) return;
5097 XtPopdown(errorShell);
5098 XtDestroyWidget(errorShell);
5099 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5102 void ErrorPopUp(title, label, modal)
5103 char *title, *label;
5107 Widget dialog, layout;
5111 Dimension bw_width, pw_width;
5112 Dimension pw_height;
5116 XtSetArg(args[i], XtNresizable, True); i++;
5117 XtSetArg(args[i], XtNtitle, title); i++;
5119 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5120 shellWidget, args, i);
5122 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5123 layoutArgs, XtNumber(layoutArgs));
5126 XtSetArg(args[i], XtNlabel, label); i++;
5127 XtSetArg(args[i], XtNborderWidth, 0); i++;
5128 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5131 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5133 XtRealizeWidget(errorShell);
5134 CatchDeleteWindow(errorShell, "ErrorPopDown");
5137 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5138 XtGetValues(boardWidget, args, i);
5140 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5141 XtSetArg(args[i], XtNheight, &pw_height); i++;
5142 XtGetValues(errorShell, args, i);
5145 /* This code seems to tickle an X bug if it is executed too soon
5146 after xboard starts up. The coordinates get transformed as if
5147 the main window was positioned at (0, 0).
5149 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5150 0 - pw_height + squareSize / 3, &x, &y);
5152 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5153 RootWindowOfScreen(XtScreen(boardWidget)),
5154 (bw_width - pw_width) / 2,
5155 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5159 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5162 XtSetArg(args[i], XtNx, x); i++;
5163 XtSetArg(args[i], XtNy, y); i++;
5164 XtSetValues(errorShell, args, i);
5167 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5170 /* Disable all user input other than deleting the window */
5171 static int frozen = 0;
5175 /* Grab by a widget that doesn't accept input */
5176 XtAddGrab(messageWidget, TRUE, FALSE);
5180 /* Undo a FreezeUI */
5183 if (!frozen) return;
5184 XtRemoveGrab(messageWidget);
5188 char *ModeToWidgetName(mode)
5192 case BeginningOfGame:
5193 if (appData.icsActive)
5194 return "menuMode.ICS Client";
5195 else if (appData.noChessProgram ||
5196 *appData.cmailGameName != NULLCHAR)
5197 return "menuMode.Edit Game";
5199 return "menuMode.Machine Black";
5200 case MachinePlaysBlack:
5201 return "menuMode.Machine Black";
5202 case MachinePlaysWhite:
5203 return "menuMode.Machine White";
5205 return "menuMode.Analysis Mode";
5207 return "menuMode.Analyze File";
5208 case TwoMachinesPlay:
5209 return "menuMode.Two Machines";
5211 return "menuMode.Edit Game";
5212 case PlayFromGameFile:
5213 return "menuFile.Load Game";
5215 return "menuMode.Edit Position";
5217 return "menuMode.Training";
5218 case IcsPlayingWhite:
5219 case IcsPlayingBlack:
5223 return "menuMode.ICS Client";
5230 void ModeHighlight()
5233 static int oldPausing = FALSE;
5234 static GameMode oldmode = (GameMode) -1;
5237 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5239 if (pausing != oldPausing) {
5240 oldPausing = pausing;
5242 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5244 XtSetArg(args[0], XtNleftBitmap, None);
5246 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5249 if (appData.showButtonBar) {
5250 /* Always toggle, don't set. Previous code messes up when
5251 invoked while the button is pressed, as releasing it
5252 toggles the state again. */
5255 XtSetArg(args[0], XtNbackground, &oldbg);
5256 XtSetArg(args[1], XtNforeground, &oldfg);
5257 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5259 XtSetArg(args[0], XtNbackground, oldfg);
5260 XtSetArg(args[1], XtNforeground, oldbg);
5262 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5266 wname = ModeToWidgetName(oldmode);
5267 if (wname != NULL) {
5268 XtSetArg(args[0], XtNleftBitmap, None);
5269 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5271 wname = ModeToWidgetName(gameMode);
5272 if (wname != NULL) {
5273 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5274 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5278 /* Maybe all the enables should be handled here, not just this one */
5279 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5280 gameMode == Training || gameMode == PlayFromGameFile);
5285 * Button/menu procedures
5287 void ResetProc(w, event, prms, nprms)
5296 int LoadGamePopUp(f, gameNumber, title)
5301 cmailMsgLoaded = FALSE;
5302 if (gameNumber == 0) {
5303 int error = GameListBuild(f);
5305 DisplayError(_("Cannot build game list"), error);
5306 } else if (!ListEmpty(&gameList) &&
5307 ((ListGame *) gameList.tailPred)->number > 1) {
5308 GameListPopUp(f, title);
5314 return LoadGame(f, gameNumber, title, FALSE);
5317 void LoadGameProc(w, event, prms, nprms)
5323 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5326 FileNamePopUp(_("Load game file name?"), "", ".pgn .game", LoadGamePopUp, "rb");
5329 void LoadNextGameProc(w, event, prms, nprms)
5338 void LoadPrevGameProc(w, event, prms, nprms)
5347 void ReloadGameProc(w, event, prms, nprms)
5356 void LoadNextPositionProc(w, event, prms, nprms)
5365 void LoadPrevPositionProc(w, event, prms, nprms)
5374 void ReloadPositionProc(w, event, prms, nprms)
5383 void LoadPositionProc(w, event, prms, nprms)
5389 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5392 FileNamePopUp(_("Load position file name?"), "", ".fen .epd .pos", LoadPosition, "rb");
5395 void SaveGameProc(w, event, prms, nprms)
5401 FileNamePopUp(_("Save game file name?"),
5402 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5403 appData.oldSaveStyle ? ".game" : ".pgn",
5407 void SavePositionProc(w, event, prms, nprms)
5413 FileNamePopUp(_("Save position file name?"),
5414 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5415 appData.oldSaveStyle ? ".pos" : ".fen",
5419 void ReloadCmailMsgProc(w, event, prms, nprms)
5425 ReloadCmailMsgEvent(FALSE);
5428 void MailMoveProc(w, event, prms, nprms)
5437 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5438 char *selected_fen_position=NULL;
5441 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5442 Atom *type_return, XtPointer *value_return,
5443 unsigned long *length_return, int *format_return)
5445 char *selection_tmp;
5447 if (!selected_fen_position) return False; /* should never happen */
5448 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5449 /* note: since no XtSelectionDoneProc was registered, Xt will
5450 * automatically call XtFree on the value returned. So have to
5451 * make a copy of it allocated with XtMalloc */
5452 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5453 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
5455 *value_return=selection_tmp;
5456 *length_return=strlen(selection_tmp);
5457 *type_return=*target;
5458 *format_return = 8; /* bits per byte */
5460 } else if (*target == XA_TARGETS(xDisplay)) {
5461 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5462 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5463 targets_tmp[1] = XA_STRING;
5464 *value_return = targets_tmp;
5465 *type_return = XA_ATOM;
5467 *format_return = 8 * sizeof(Atom);
5468 if (*format_return > 32) {
5469 *length_return *= *format_return / 32;
5470 *format_return = 32;
5478 /* note: when called from menu all parameters are NULL, so no clue what the
5479 * Widget which was clicked on was, or what the click event was
5481 void CopyPositionProc(w, event, prms, nprms)
5488 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5489 * have a notion of a position that is selected but not copied.
5490 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5492 if(gameMode == EditPosition) EditPositionDone(TRUE);
5493 if (selected_fen_position) free(selected_fen_position);
5494 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5495 if (!selected_fen_position) return;
5496 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5498 SendPositionSelection,
5499 NULL/* lose_ownership_proc */ ,
5500 NULL/* transfer_done_proc */);
5501 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5503 SendPositionSelection,
5504 NULL/* lose_ownership_proc */ ,
5505 NULL/* transfer_done_proc */);
5508 /* function called when the data to Paste is ready */
5510 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5511 Atom *type, XtPointer value, unsigned long *len, int *format)
5514 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5515 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5516 EditPositionPasteFEN(fenstr);
5520 /* called when Paste Position button is pressed,
5521 * all parameters will be NULL */
5522 void PastePositionProc(w, event, prms, nprms)
5528 XtGetSelectionValue(menuBarWidget,
5529 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5530 /* (XtSelectionCallbackProc) */ PastePositionCB,
5531 NULL, /* client_data passed to PastePositionCB */
5533 /* better to use the time field from the event that triggered the
5534 * call to this function, but that isn't trivial to get
5542 SendGameSelection(Widget w, Atom *selection, Atom *target,
5543 Atom *type_return, XtPointer *value_return,
5544 unsigned long *length_return, int *format_return)
5546 char *selection_tmp;
5548 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5549 FILE* f = fopen(gameCopyFilename, "r");
5552 if (f == NULL) return False;
5556 selection_tmp = XtMalloc(len + 1);
5557 count = fread(selection_tmp, 1, len, f);
5560 XtFree(selection_tmp);
5563 selection_tmp[len] = NULLCHAR;
5564 *value_return = selection_tmp;
5565 *length_return = len;
5566 *type_return = *target;
5567 *format_return = 8; /* bits per byte */
5569 } else if (*target == XA_TARGETS(xDisplay)) {
5570 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5571 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5572 targets_tmp[1] = XA_STRING;
5573 *value_return = targets_tmp;
5574 *type_return = XA_ATOM;
5576 *format_return = 8 * sizeof(Atom);
5577 if (*format_return > 32) {
5578 *length_return *= *format_return / 32;
5579 *format_return = 32;
5587 void CopySomething()
5592 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5593 * have a notion of a game that is selected but not copied.
5594 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5596 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5599 NULL/* lose_ownership_proc */ ,
5600 NULL/* transfer_done_proc */);
5601 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5604 NULL/* lose_ownership_proc */ ,
5605 NULL/* transfer_done_proc */);
5608 /* note: when called from menu all parameters are NULL, so no clue what the
5609 * Widget which was clicked on was, or what the click event was
5611 void CopyGameProc(w, event, prms, nprms)
5619 ret = SaveGameToFile(gameCopyFilename, FALSE);
5625 void CopyGameListProc(w, event, prms, nprms)
5631 if(!SaveGameListAsText(fopen(gameCopyFilename, "w"))) return;
5635 /* function called when the data to Paste is ready */
5637 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5638 Atom *type, XtPointer value, unsigned long *len, int *format)
5641 if (value == NULL || *len == 0) {
5642 return; /* nothing had been selected to copy */
5644 f = fopen(gamePasteFilename, "w");
5646 DisplayError(_("Can't open temp file"), errno);
5649 fwrite(value, 1, *len, f);
5652 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5655 /* called when Paste Game button is pressed,
5656 * all parameters will be NULL */
5657 void PasteGameProc(w, event, prms, nprms)
5663 XtGetSelectionValue(menuBarWidget,
5664 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5665 /* (XtSelectionCallbackProc) */ PasteGameCB,
5666 NULL, /* client_data passed to PasteGameCB */
5668 /* better to use the time field from the event that triggered the
5669 * call to this function, but that isn't trivial to get
5679 SaveGameProc(NULL, NULL, NULL, NULL);
5683 void QuitProc(w, event, prms, nprms)
5692 void PauseProc(w, event, prms, nprms)
5702 void MachineBlackProc(w, event, prms, nprms)
5708 MachineBlackEvent();
5711 void MachineWhiteProc(w, event, prms, nprms)
5717 MachineWhiteEvent();
5720 void AnalyzeModeProc(w, event, prms, nprms)
5728 if (!first.analysisSupport) {
5729 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5730 DisplayError(buf, 0);
5733 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5734 if (appData.icsActive) {
5735 if (gameMode != IcsObserving) {
5736 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
5737 DisplayError(buf, 0);
5739 if (appData.icsEngineAnalyze) {
5740 if (appData.debugMode)
5741 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5747 /* if enable, use want disable icsEngineAnalyze */
5748 if (appData.icsEngineAnalyze) {
5753 appData.icsEngineAnalyze = TRUE;
5754 if (appData.debugMode)
5755 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5757 #ifndef OPTIONSDIALOG
5758 if (!appData.showThinking)
5759 ShowThinkingProc(w,event,prms,nprms);
5765 void AnalyzeFileProc(w, event, prms, nprms)
5771 if (!first.analysisSupport) {
5773 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5774 DisplayError(buf, 0);
5778 #ifndef OPTIONSDIALOG
5779 if (!appData.showThinking)
5780 ShowThinkingProc(w,event,prms,nprms);
5783 FileNamePopUp(_("File to analyze"), "", ".pgn .game", LoadGamePopUp, "rb");
5784 AnalysisPeriodicEvent(1);
5787 void TwoMachinesProc(w, event, prms, nprms)
5796 void MatchProc(w, event, prms, nprms)
5802 if(gameMode != BeginningOfGame) { DisplayError(_("You can only start a match from the initial position."), 0); return; }
5803 appData.matchGames = appData.defaultMatchGames;
5807 void IcsClientProc(w, event, prms, nprms)
5816 void EditGameProc(w, event, prms, nprms)
5825 void EditPositionProc(w, event, prms, nprms)
5831 EditPositionEvent();
5834 void TrainingProc(w, event, prms, nprms)
5843 void EditCommentProc(w, event, prms, nprms)
5851 if (PopDown(1)) { // popdown succesful
5853 XtSetArg(args[j], XtNleftBitmap, None); j++;
5854 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"), args, j);
5855 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"), args, j);
5856 } else // was not up
5860 void IcsInputBoxProc(w, event, prms, nprms)
5866 if (!PopDown(4)) ICSInputBoxPopUp();
5869 void AcceptProc(w, event, prms, nprms)
5878 void DeclineProc(w, event, prms, nprms)
5887 void RematchProc(w, event, prms, nprms)
5896 void CallFlagProc(w, event, prms, nprms)
5905 void DrawProc(w, event, prms, nprms)
5914 void AbortProc(w, event, prms, nprms)
5923 void AdjournProc(w, event, prms, nprms)
5932 void ResignProc(w, event, prms, nprms)
5941 void AdjuWhiteProc(w, event, prms, nprms)
5947 UserAdjudicationEvent(+1);
5950 void AdjuBlackProc(w, event, prms, nprms)
5956 UserAdjudicationEvent(-1);
5959 void AdjuDrawProc(w, event, prms, nprms)
5965 UserAdjudicationEvent(0);
5968 void EnterKeyProc(w, event, prms, nprms)
5974 if (shellUp[4] == True)
5978 void UpKeyProc(w, event, prms, nprms)
5983 { // [HGM] input: let up-arrow recall previous line from history
5990 if (!shellUp[4]) return;
5991 edit = boxOptions[0].handle;
5993 XtSetArg(args[j], XtNstring, &val); j++;
5994 XtGetValues(edit, args, j);
5995 val = PrevInHistory(val);
5996 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5997 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5999 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6000 XawTextReplace(edit, 0, 0, &t);
6001 XawTextSetInsertionPoint(edit, 9999);
6005 void DownKeyProc(w, event, prms, nprms)
6010 { // [HGM] input: let down-arrow recall next line from history
6015 if (!shellUp[4]) return;
6016 edit = boxOptions[0].handle;
6017 val = NextInHistory();
6018 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6019 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6021 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6022 XawTextReplace(edit, 0, 0, &t);
6023 XawTextSetInsertionPoint(edit, 9999);
6027 void StopObservingProc(w, event, prms, nprms)
6033 StopObservingEvent();
6036 void StopExaminingProc(w, event, prms, nprms)
6042 StopExaminingEvent();
6045 void UploadProc(w, event, prms, nprms)
6055 void ForwardProc(w, event, prms, nprms)
6065 void BackwardProc(w, event, prms, nprms)
6074 void ToStartProc(w, event, prms, nprms)
6083 void ToEndProc(w, event, prms, nprms)
6092 void RevertProc(w, event, prms, nprms)
6101 void AnnotateProc(w, event, prms, nprms)
6110 void TruncateGameProc(w, event, prms, nprms)
6116 TruncateGameEvent();
6118 void RetractMoveProc(w, event, prms, nprms)
6127 void MoveNowProc(w, event, prms, nprms)
6136 void FlipViewProc(w, event, prms, nprms)
6142 flipView = !flipView;
6143 DrawPosition(True, NULL);
6146 void PonderNextMoveProc(w, event, prms, nprms)
6154 PonderNextMoveEvent(!appData.ponderNextMove);
6155 #ifndef OPTIONSDIALOG
6156 if (appData.ponderNextMove) {
6157 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6159 XtSetArg(args[0], XtNleftBitmap, None);
6161 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6166 #ifndef OPTIONSDIALOG
6167 void AlwaysQueenProc(w, event, prms, nprms)
6175 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6177 if (appData.alwaysPromoteToQueen) {
6178 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6180 XtSetArg(args[0], XtNleftBitmap, None);
6182 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6186 void AnimateDraggingProc(w, event, prms, nprms)
6194 appData.animateDragging = !appData.animateDragging;
6196 if (appData.animateDragging) {
6197 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6200 XtSetArg(args[0], XtNleftBitmap, None);
6202 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6206 void AnimateMovingProc(w, event, prms, nprms)
6214 appData.animate = !appData.animate;
6216 if (appData.animate) {
6217 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6220 XtSetArg(args[0], XtNleftBitmap, None);
6222 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6226 void AutoflagProc(w, event, prms, nprms)
6234 appData.autoCallFlag = !appData.autoCallFlag;
6236 if (appData.autoCallFlag) {
6237 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6239 XtSetArg(args[0], XtNleftBitmap, None);
6241 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6245 void AutoflipProc(w, event, prms, nprms)
6253 appData.autoFlipView = !appData.autoFlipView;
6255 if (appData.autoFlipView) {
6256 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6258 XtSetArg(args[0], XtNleftBitmap, None);
6260 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6264 void BlindfoldProc(w, event, prms, nprms)
6272 appData.blindfold = !appData.blindfold;
6274 if (appData.blindfold) {
6275 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6277 XtSetArg(args[0], XtNleftBitmap, None);
6279 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6282 DrawPosition(True, NULL);
6285 void TestLegalityProc(w, event, prms, nprms)
6293 appData.testLegality = !appData.testLegality;
6295 if (appData.testLegality) {
6296 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6298 XtSetArg(args[0], XtNleftBitmap, None);
6300 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6305 void FlashMovesProc(w, event, prms, nprms)
6313 if (appData.flashCount == 0) {
6314 appData.flashCount = 3;
6316 appData.flashCount = -appData.flashCount;
6319 if (appData.flashCount > 0) {
6320 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6322 XtSetArg(args[0], XtNleftBitmap, None);
6324 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6329 void HighlightDraggingProc(w, event, prms, nprms)
6337 appData.highlightDragging = !appData.highlightDragging;
6339 if (appData.highlightDragging) {
6340 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6342 XtSetArg(args[0], XtNleftBitmap, None);
6344 XtSetValues(XtNameToWidget(menuBarWidget,
6345 "menuOptions.Highlight Dragging"), args, 1);
6349 void HighlightLastMoveProc(w, event, prms, nprms)
6357 appData.highlightLastMove = !appData.highlightLastMove;
6359 if (appData.highlightLastMove) {
6360 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6362 XtSetArg(args[0], XtNleftBitmap, None);
6364 XtSetValues(XtNameToWidget(menuBarWidget,
6365 "menuOptions.Highlight Last Move"), args, 1);
6368 void HighlightArrowProc(w, event, prms, nprms)
6376 appData.highlightMoveWithArrow = !appData.highlightMoveWithArrow;
6378 if (appData.highlightMoveWithArrow) {
6379 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6381 XtSetArg(args[0], XtNleftBitmap, None);
6383 XtSetValues(XtNameToWidget(menuBarWidget,
6384 "menuOptions.Arrow"), args, 1);
6388 void IcsAlarmProc(w, event, prms, nprms)
6396 appData.icsAlarm = !appData.icsAlarm;
6398 if (appData.icsAlarm) {
6399 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6401 XtSetArg(args[0], XtNleftBitmap, None);
6403 XtSetValues(XtNameToWidget(menuBarWidget,
6404 "menuOptions.ICS Alarm"), args, 1);
6408 void MoveSoundProc(w, event, prms, nprms)
6416 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6418 if (appData.ringBellAfterMoves) {
6419 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6421 XtSetArg(args[0], XtNleftBitmap, None);
6423 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6427 void OneClickProc(w, event, prms, nprms)
6435 appData.oneClick = !appData.oneClick;
6437 if (appData.oneClick) {
6438 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6440 XtSetArg(args[0], XtNleftBitmap, None);
6442 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.OneClick"),
6446 void PeriodicUpdatesProc(w, event, prms, nprms)
6454 PeriodicUpdatesEvent(!appData.periodicUpdates);
6456 if (appData.periodicUpdates) {
6457 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6459 XtSetArg(args[0], XtNleftBitmap, None);
6461 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6465 void PopupExitMessageProc(w, event, prms, nprms)
6473 appData.popupExitMessage = !appData.popupExitMessage;
6475 if (appData.popupExitMessage) {
6476 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6478 XtSetArg(args[0], XtNleftBitmap, None);
6480 XtSetValues(XtNameToWidget(menuBarWidget,
6481 "menuOptions.Popup Exit Message"), args, 1);
6484 void PopupMoveErrorsProc(w, event, prms, nprms)
6492 appData.popupMoveErrors = !appData.popupMoveErrors;
6494 if (appData.popupMoveErrors) {
6495 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6497 XtSetArg(args[0], XtNleftBitmap, None);
6499 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6504 void PremoveProc(w, event, prms, nprms)
6512 appData.premove = !appData.premove;
6514 if (appData.premove) {
6515 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6517 XtSetArg(args[0], XtNleftBitmap, None);
6519 XtSetValues(XtNameToWidget(menuBarWidget,
6520 "menuOptions.Premove"), args, 1);
6524 void ShowCoordsProc(w, event, prms, nprms)
6532 appData.showCoords = !appData.showCoords;
6534 if (appData.showCoords) {
6535 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6537 XtSetArg(args[0], XtNleftBitmap, None);
6539 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6542 DrawPosition(True, NULL);
6545 void ShowThinkingProc(w, event, prms, nprms)
6551 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6552 ShowThinkingEvent();
6555 void HideThinkingProc(w, event, prms, nprms)
6563 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6564 ShowThinkingEvent();
6566 if (appData.hideThinkingFromHuman) {
6567 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6569 XtSetArg(args[0], XtNleftBitmap, None);
6571 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6576 void SaveOnExitProc(w, event, prms, nprms)
6584 saveSettingsOnExit = !saveSettingsOnExit;
6586 if (saveSettingsOnExit) {
6587 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6589 XtSetArg(args[0], XtNleftBitmap, None);
6591 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6595 void SaveSettingsProc(w, event, prms, nprms)
6601 SaveSettings(settingsFileName);
6604 void InfoProc(w, event, prms, nprms)
6611 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6616 void ManProc(w, event, prms, nprms)
6624 if (nprms && *nprms > 0)
6628 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6632 void HintProc(w, event, prms, nprms)
6641 void BookProc(w, event, prms, nprms)
6650 void AboutProc(w, event, prms, nprms)
6658 char *zippy = " (with Zippy code)";
6662 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6663 programVersion, zippy,
6664 "Copyright 1991 Digital Equipment Corporation",
6665 "Enhancements Copyright 1992-2009 Free Software Foundation",
6666 "Enhancements Copyright 2005 Alessandro Scotti",
6667 PACKAGE, " is free software and carries NO WARRANTY;",
6668 "see the file COPYING for more information.");
6669 ErrorPopUp(_("About XBoard"), buf, FALSE);
6672 void DebugProc(w, event, prms, nprms)
6678 appData.debugMode = !appData.debugMode;
6681 void AboutGameProc(w, event, prms, nprms)
6690 void NothingProc(w, event, prms, nprms)
6699 void Iconify(w, event, prms, nprms)
6708 XtSetArg(args[0], XtNiconic, True);
6709 XtSetValues(shellWidget, args, 1);
6712 void DisplayMessage(message, extMessage)
6713 char *message, *extMessage;
6715 /* display a message in the message widget */
6724 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
6729 message = extMessage;
6733 /* need to test if messageWidget already exists, since this function
6734 can also be called during the startup, if for example a Xresource
6735 is not set up correctly */
6738 XtSetArg(arg, XtNlabel, message);
6739 XtSetValues(messageWidget, &arg, 1);
6745 void DisplayTitle(text)
6750 char title[MSG_SIZ];
6753 if (text == NULL) text = "";
6755 if (appData.titleInWindow) {
6757 XtSetArg(args[i], XtNlabel, text); i++;
6758 XtSetValues(titleWidget, args, i);
6761 if (*text != NULLCHAR) {
6762 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
6763 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
6764 } else if (appData.icsActive) {
6765 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
6766 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
6767 } else if (appData.cmailGameName[0] != NULLCHAR) {
6768 snprintf(icon, sizeof(icon), "%s", "CMail");
6769 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
6771 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
6772 } else if (gameInfo.variant == VariantGothic) {
6773 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6774 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
6777 } else if (gameInfo.variant == VariantFalcon) {
6778 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6779 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
6781 } else if (appData.noChessProgram) {
6782 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6783 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
6785 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
6786 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
6789 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
6790 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
6791 XtSetValues(shellWidget, args, i);
6796 DisplayError(message, error)
6803 if (appData.debugMode || appData.matchMode) {
6804 fprintf(stderr, "%s: %s\n", programName, message);
6807 if (appData.debugMode || appData.matchMode) {
6808 fprintf(stderr, "%s: %s: %s\n",
6809 programName, message, strerror(error));
6811 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6814 ErrorPopUp(_("Error"), message, FALSE);
6818 void DisplayMoveError(message)
6823 DrawPosition(FALSE, NULL);
6824 if (appData.debugMode || appData.matchMode) {
6825 fprintf(stderr, "%s: %s\n", programName, message);
6827 if (appData.popupMoveErrors) {
6828 ErrorPopUp(_("Error"), message, FALSE);
6830 DisplayMessage(message, "");
6835 void DisplayFatalError(message, error, status)
6841 errorExitStatus = status;
6843 fprintf(stderr, "%s: %s\n", programName, message);
6845 fprintf(stderr, "%s: %s: %s\n",
6846 programName, message, strerror(error));
6847 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6850 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
6851 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
6857 void DisplayInformation(message)
6861 ErrorPopUp(_("Information"), message, TRUE);
6864 void DisplayNote(message)
6868 ErrorPopUp(_("Note"), message, FALSE);
6872 NullXErrorCheck(dpy, error_event)
6874 XErrorEvent *error_event;
6879 void DisplayIcsInteractionTitle(message)
6882 if (oldICSInteractionTitle == NULL) {
6883 /* Magic to find the old window title, adapted from vim */
6884 char *wina = getenv("WINDOWID");
6886 Window win = (Window) atoi(wina);
6887 Window root, parent, *children;
6888 unsigned int nchildren;
6889 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
6891 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
6892 if (!XQueryTree(xDisplay, win, &root, &parent,
6893 &children, &nchildren)) break;
6894 if (children) XFree((void *)children);
6895 if (parent == root || parent == 0) break;
6898 XSetErrorHandler(oldHandler);
6900 if (oldICSInteractionTitle == NULL) {
6901 oldICSInteractionTitle = "xterm";
6904 printf("\033]0;%s\007", message);
6908 char pendingReplyPrefix[MSG_SIZ];
6909 ProcRef pendingReplyPR;
6911 void AskQuestionProc(w, event, prms, nprms)
6918 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
6922 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
6925 void AskQuestionPopDown()
6927 if (!askQuestionUp) return;
6928 XtPopdown(askQuestionShell);
6929 XtDestroyWidget(askQuestionShell);
6930 askQuestionUp = False;
6933 void AskQuestionReplyAction(w, event, prms, nprms)
6943 reply = XawDialogGetValueString(w = XtParent(w));
6944 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
6945 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
6946 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
6947 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
6948 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
6949 AskQuestionPopDown();
6951 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
6954 void AskQuestionCallback(w, client_data, call_data)
6956 XtPointer client_data, call_data;
6961 XtSetArg(args[0], XtNlabel, &name);
6962 XtGetValues(w, args, 1);
6964 if (strcmp(name, _("cancel")) == 0) {
6965 AskQuestionPopDown();
6967 AskQuestionReplyAction(w, NULL, NULL, NULL);
6971 void AskQuestion(title, question, replyPrefix, pr)
6972 char *title, *question, *replyPrefix;
6976 Widget popup, layout, dialog, edit;
6982 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
6983 pendingReplyPR = pr;
6986 XtSetArg(args[i], XtNresizable, True); i++;
6987 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
6988 askQuestionShell = popup =
6989 XtCreatePopupShell(title, transientShellWidgetClass,
6990 shellWidget, args, i);
6993 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
6994 layoutArgs, XtNumber(layoutArgs));
6997 XtSetArg(args[i], XtNlabel, question); i++;
6998 XtSetArg(args[i], XtNvalue, ""); i++;
6999 XtSetArg(args[i], XtNborderWidth, 0); i++;
7000 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7003 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7004 (XtPointer) dialog);
7005 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7006 (XtPointer) dialog);
7008 XtRealizeWidget(popup);
7009 CatchDeleteWindow(popup, "AskQuestionPopDown");
7011 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7012 &x, &y, &win_x, &win_y, &mask);
7014 XtSetArg(args[0], XtNx, x - 10);
7015 XtSetArg(args[1], XtNy, y - 30);
7016 XtSetValues(popup, args, 2);
7018 XtPopup(popup, XtGrabExclusive);
7019 askQuestionUp = True;
7021 edit = XtNameToWidget(dialog, "*value");
7022 XtSetKeyboardFocus(popup, edit);
7030 if (*name == NULLCHAR) {
7032 } else if (strcmp(name, "$") == 0) {
7033 putc(BELLCHAR, stderr);
7036 char *prefix = "", *sep = "";
7037 if(!strchr(name, '/')) { prefix = appData.soundDirectory; sep = "/"; }
7038 snprintf(buf, sizeof(buf), "%s '%s%s%s' &", appData.soundProgram, prefix, sep, name);
7046 PlaySound(appData.soundMove);
7052 PlaySound(appData.soundIcsWin);
7058 PlaySound(appData.soundIcsLoss);
7064 PlaySound(appData.soundIcsDraw);
7068 PlayIcsUnfinishedSound()
7070 PlaySound(appData.soundIcsUnfinished);
7076 PlaySound(appData.soundIcsAlarm);
7082 system("stty echo");
7088 system("stty -echo");
7092 Colorize(cc, continuation)
7097 int count, outCount, error;
7099 if (textColors[(int)cc].bg > 0) {
7100 if (textColors[(int)cc].fg > 0) {
7101 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7102 textColors[(int)cc].fg, textColors[(int)cc].bg);
7104 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7105 textColors[(int)cc].bg);
7108 if (textColors[(int)cc].fg > 0) {
7109 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7110 textColors[(int)cc].fg);
7112 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7115 count = strlen(buf);
7116 outCount = OutputToProcess(NoProc, buf, count, &error);
7117 if (outCount < count) {
7118 DisplayFatalError(_("Error writing to display"), error, 1);
7121 if (continuation) return;
7124 PlaySound(appData.soundShout);
7127 PlaySound(appData.soundSShout);
7130 PlaySound(appData.soundChannel1);
7133 PlaySound(appData.soundChannel);
7136 PlaySound(appData.soundKibitz);
7139 PlaySound(appData.soundTell);
7141 case ColorChallenge:
7142 PlaySound(appData.soundChallenge);
7145 PlaySound(appData.soundRequest);
7148 PlaySound(appData.soundSeek);
7159 return getpwuid(getuid())->pw_name;
7163 ExpandPathName(path)
7166 static char static_buf[4*MSG_SIZ];
7167 char *d, *s, buf[4*MSG_SIZ];
7173 while (*s && isspace(*s))
7182 if (*(s+1) == '/') {
7183 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7187 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7188 { char *p; if(p = strchr(buf, '/')) *p = 0; }
7189 pwd = getpwnam(buf);
7192 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7196 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7197 strcat(d, strchr(s+1, '/'));
7201 safeStrCpy(d, s, 4*MSG_SIZ );
7208 static char host_name[MSG_SIZ];
7210 #if HAVE_GETHOSTNAME
7211 gethostname(host_name, MSG_SIZ);
7213 #else /* not HAVE_GETHOSTNAME */
7214 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7215 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7217 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7219 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7220 #endif /* not HAVE_GETHOSTNAME */
7223 XtIntervalId delayedEventTimerXID = 0;
7224 DelayedEventCallback delayedEventCallback = 0;
7229 delayedEventTimerXID = 0;
7230 delayedEventCallback();
7234 ScheduleDelayedEvent(cb, millisec)
7235 DelayedEventCallback cb; long millisec;
7237 if(delayedEventTimerXID && delayedEventCallback == cb)
7238 // [HGM] alive: replace, rather than add or flush identical event
7239 XtRemoveTimeOut(delayedEventTimerXID);
7240 delayedEventCallback = cb;
7241 delayedEventTimerXID =
7242 XtAppAddTimeOut(appContext, millisec,
7243 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7246 DelayedEventCallback
7249 if (delayedEventTimerXID) {
7250 return delayedEventCallback;
7257 CancelDelayedEvent()
7259 if (delayedEventTimerXID) {
7260 XtRemoveTimeOut(delayedEventTimerXID);
7261 delayedEventTimerXID = 0;
7265 XtIntervalId loadGameTimerXID = 0;
7267 int LoadGameTimerRunning()
7269 return loadGameTimerXID != 0;
7272 int StopLoadGameTimer()
7274 if (loadGameTimerXID != 0) {
7275 XtRemoveTimeOut(loadGameTimerXID);
7276 loadGameTimerXID = 0;
7284 LoadGameTimerCallback(arg, id)
7288 loadGameTimerXID = 0;
7293 StartLoadGameTimer(millisec)
7297 XtAppAddTimeOut(appContext, millisec,
7298 (XtTimerCallbackProc) LoadGameTimerCallback,
7302 XtIntervalId analysisClockXID = 0;
7305 AnalysisClockCallback(arg, id)
7309 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7310 || appData.icsEngineAnalyze) { // [DM]
7311 AnalysisPeriodicEvent(0);
7312 StartAnalysisClock();
7317 StartAnalysisClock()
7320 XtAppAddTimeOut(appContext, 2000,
7321 (XtTimerCallbackProc) AnalysisClockCallback,
7325 XtIntervalId clockTimerXID = 0;
7327 int ClockTimerRunning()
7329 return clockTimerXID != 0;
7332 int StopClockTimer()
7334 if (clockTimerXID != 0) {
7335 XtRemoveTimeOut(clockTimerXID);
7344 ClockTimerCallback(arg, id)
7353 StartClockTimer(millisec)
7357 XtAppAddTimeOut(appContext, millisec,
7358 (XtTimerCallbackProc) ClockTimerCallback,
7363 DisplayTimerLabel(w, color, timer, highlight)
7372 /* check for low time warning */
7373 Pixel foregroundOrWarningColor = timerForegroundPixel;
7376 appData.lowTimeWarning &&
7377 (timer / 1000) < appData.icsAlarmTime)
7378 foregroundOrWarningColor = lowTimeWarningColor;
7380 if (appData.clockMode) {
7381 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7382 XtSetArg(args[0], XtNlabel, buf);
7384 snprintf(buf, MSG_SIZ, "%s ", color);
7385 XtSetArg(args[0], XtNlabel, buf);
7390 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7391 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7393 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7394 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7397 XtSetValues(w, args, 3);
7401 DisplayWhiteClock(timeRemaining, highlight)
7407 if(appData.noGUI) return;
7408 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7409 if (highlight && iconPixmap == bIconPixmap) {
7410 iconPixmap = wIconPixmap;
7411 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7412 XtSetValues(shellWidget, args, 1);
7417 DisplayBlackClock(timeRemaining, highlight)
7423 if(appData.noGUI) return;
7424 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7425 if (highlight && iconPixmap == wIconPixmap) {
7426 iconPixmap = bIconPixmap;
7427 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7428 XtSetValues(shellWidget, args, 1);
7446 int StartChildProcess(cmdLine, dir, pr)
7453 int to_prog[2], from_prog[2];
7457 if (appData.debugMode) {
7458 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7461 /* We do NOT feed the cmdLine to the shell; we just
7462 parse it into blank-separated arguments in the
7463 most simple-minded way possible.
7466 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7469 while(*p == ' ') p++;
7471 if(*p == '"' || *p == '\'')
7472 p = strchr(++argv[i-1], *p);
7473 else p = strchr(p, ' ');
7474 if (p == NULL) break;
7479 SetUpChildIO(to_prog, from_prog);
7481 if ((pid = fork()) == 0) {
7483 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7484 close(to_prog[1]); // first close the unused pipe ends
7485 close(from_prog[0]);
7486 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7487 dup2(from_prog[1], 1);
7488 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7489 close(from_prog[1]); // and closing again loses one of the pipes!
7490 if(fileno(stderr) >= 2) // better safe than sorry...
7491 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7493 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7498 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7500 execvp(argv[0], argv);
7502 /* If we get here, exec failed */
7507 /* Parent process */
7509 close(from_prog[1]);
7511 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7514 cp->fdFrom = from_prog[0];
7515 cp->fdTo = to_prog[1];
7520 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7521 static RETSIGTYPE AlarmCallBack(int n)
7527 DestroyChildProcess(pr, signalType)
7531 ChildProc *cp = (ChildProc *) pr;
7533 if (cp->kind != CPReal) return;
7535 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7536 signal(SIGALRM, AlarmCallBack);
7538 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7539 kill(cp->pid, SIGKILL); // kill it forcefully
7540 wait((int *) 0); // and wait again
7544 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7546 /* Process is exiting either because of the kill or because of
7547 a quit command sent by the backend; either way, wait for it to die.
7556 InterruptChildProcess(pr)
7559 ChildProc *cp = (ChildProc *) pr;
7561 if (cp->kind != CPReal) return;
7562 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7565 int OpenTelnet(host, port, pr)
7570 char cmdLine[MSG_SIZ];
7572 if (port[0] == NULLCHAR) {
7573 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7575 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7577 return StartChildProcess(cmdLine, "", pr);
7580 int OpenTCP(host, port, pr)
7586 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7587 #else /* !OMIT_SOCKETS */
7589 struct sockaddr_in sa;
7591 unsigned short uport;
7594 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7598 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7599 sa.sin_family = AF_INET;
7600 sa.sin_addr.s_addr = INADDR_ANY;
7601 uport = (unsigned short) 0;
7602 sa.sin_port = htons(uport);
7603 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7607 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7608 if (!(hp = gethostbyname(host))) {
7610 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7611 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7612 hp->h_addrtype = AF_INET;
7614 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7615 hp->h_addr_list[0] = (char *) malloc(4);
7616 hp->h_addr_list[0][0] = b0;
7617 hp->h_addr_list[0][1] = b1;
7618 hp->h_addr_list[0][2] = b2;
7619 hp->h_addr_list[0][3] = b3;
7624 sa.sin_family = hp->h_addrtype;
7625 uport = (unsigned short) atoi(port);
7626 sa.sin_port = htons(uport);
7627 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7629 if (connect(s, (struct sockaddr *) &sa,
7630 sizeof(struct sockaddr_in)) < 0) {
7634 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7641 #endif /* !OMIT_SOCKETS */
7646 int OpenCommPort(name, pr)
7653 fd = open(name, 2, 0);
7654 if (fd < 0) return errno;
7656 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7666 int OpenLoopback(pr)
7672 SetUpChildIO(to, from);
7674 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7677 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7684 int OpenRcmd(host, user, cmd, pr)
7685 char *host, *user, *cmd;
7688 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7692 #define INPUT_SOURCE_BUF_SIZE 8192
7701 char buf[INPUT_SOURCE_BUF_SIZE];
7706 DoInputCallback(closure, source, xid)
7711 InputSource *is = (InputSource *) closure;
7716 if (is->lineByLine) {
7717 count = read(is->fd, is->unused,
7718 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7720 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7723 is->unused += count;
7725 while (p < is->unused) {
7726 q = memchr(p, '\n', is->unused - p);
7727 if (q == NULL) break;
7729 (is->func)(is, is->closure, p, q - p, 0);
7733 while (p < is->unused) {
7738 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
7743 (is->func)(is, is->closure, is->buf, count, error);
7747 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
7754 ChildProc *cp = (ChildProc *) pr;
7756 is = (InputSource *) calloc(1, sizeof(InputSource));
7757 is->lineByLine = lineByLine;
7761 is->fd = fileno(stdin);
7763 is->kind = cp->kind;
7764 is->fd = cp->fdFrom;
7767 is->unused = is->buf;
7770 is->xid = XtAppAddInput(appContext, is->fd,
7771 (XtPointer) (XtInputReadMask),
7772 (XtInputCallbackProc) DoInputCallback,
7774 is->closure = closure;
7775 return (InputSourceRef) is;
7779 RemoveInputSource(isr)
7782 InputSource *is = (InputSource *) isr;
7784 if (is->xid == 0) return;
7785 XtRemoveInput(is->xid);
7789 int OutputToProcess(pr, message, count, outError)
7795 static int line = 0;
7796 ChildProc *cp = (ChildProc *) pr;
7801 if (appData.noJoin || !appData.useInternalWrap)
7802 outCount = fwrite(message, 1, count, stdout);
7805 int width = get_term_width();
7806 int len = wrap(NULL, message, count, width, &line);
7807 char *msg = malloc(len);
7811 outCount = fwrite(message, 1, count, stdout);
7814 dbgchk = wrap(msg, message, count, width, &line);
7815 if (dbgchk != len && appData.debugMode)
7816 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
7817 outCount = fwrite(msg, 1, dbgchk, stdout);
7823 outCount = write(cp->fdTo, message, count);
7833 /* Output message to process, with "ms" milliseconds of delay
7834 between each character. This is needed when sending the logon
7835 script to ICC, which for some reason doesn't like the
7836 instantaneous send. */
7837 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
7844 ChildProc *cp = (ChildProc *) pr;
7849 r = write(cp->fdTo, message++, 1);
7862 /**** Animation code by Hugh Fisher, DCS, ANU.
7864 Known problem: if a window overlapping the board is
7865 moved away while a piece is being animated underneath,
7866 the newly exposed area won't be updated properly.
7867 I can live with this.
7869 Known problem: if you look carefully at the animation
7870 of pieces in mono mode, they are being drawn as solid
7871 shapes without interior detail while moving. Fixing
7872 this would be a major complication for minimal return.
7875 /* Masks for XPM pieces. Black and white pieces can have
7876 different shapes, but in the interest of retaining my
7877 sanity pieces must have the same outline on both light
7878 and dark squares, and all pieces must use the same
7879 background square colors/images. */
7881 static int xpmDone = 0;
7884 CreateAnimMasks (pieceDepth)
7891 unsigned long plane;
7894 /* Need a bitmap just to get a GC with right depth */
7895 buf = XCreatePixmap(xDisplay, xBoardWindow,
7897 values.foreground = 1;
7898 values.background = 0;
7899 /* Don't use XtGetGC, not read only */
7900 maskGC = XCreateGC(xDisplay, buf,
7901 GCForeground | GCBackground, &values);
7902 XFreePixmap(xDisplay, buf);
7904 buf = XCreatePixmap(xDisplay, xBoardWindow,
7905 squareSize, squareSize, pieceDepth);
7906 values.foreground = XBlackPixel(xDisplay, xScreen);
7907 values.background = XWhitePixel(xDisplay, xScreen);
7908 bufGC = XCreateGC(xDisplay, buf,
7909 GCForeground | GCBackground, &values);
7911 for (piece = WhitePawn; piece <= BlackKing; piece++) {
7912 /* Begin with empty mask */
7913 if(!xpmDone) // [HGM] pieces: keep using existing
7914 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
7915 squareSize, squareSize, 1);
7916 XSetFunction(xDisplay, maskGC, GXclear);
7917 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
7918 0, 0, squareSize, squareSize);
7920 /* Take a copy of the piece */
7925 XSetFunction(xDisplay, bufGC, GXcopy);
7926 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
7928 0, 0, squareSize, squareSize, 0, 0);
7930 /* XOR the background (light) over the piece */
7931 XSetFunction(xDisplay, bufGC, GXxor);
7933 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
7934 0, 0, squareSize, squareSize, 0, 0);
7936 XSetForeground(xDisplay, bufGC, lightSquareColor);
7937 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
7940 /* We now have an inverted piece image with the background
7941 erased. Construct mask by just selecting all the non-zero
7942 pixels - no need to reconstruct the original image. */
7943 XSetFunction(xDisplay, maskGC, GXor);
7945 /* Might be quicker to download an XImage and create bitmap
7946 data from it rather than this N copies per piece, but it
7947 only takes a fraction of a second and there is a much
7948 longer delay for loading the pieces. */
7949 for (n = 0; n < pieceDepth; n ++) {
7950 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
7951 0, 0, squareSize, squareSize,
7957 XFreePixmap(xDisplay, buf);
7958 XFreeGC(xDisplay, bufGC);
7959 XFreeGC(xDisplay, maskGC);
7963 InitAnimState (anim, info)
7965 XWindowAttributes * info;
7970 /* Each buffer is square size, same depth as window */
7971 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
7972 squareSize, squareSize, info->depth);
7973 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
7974 squareSize, squareSize, info->depth);
7976 /* Create a plain GC for blitting */
7977 mask = GCForeground | GCBackground | GCFunction |
7978 GCPlaneMask | GCGraphicsExposures;
7979 values.foreground = XBlackPixel(xDisplay, xScreen);
7980 values.background = XWhitePixel(xDisplay, xScreen);
7981 values.function = GXcopy;
7982 values.plane_mask = AllPlanes;
7983 values.graphics_exposures = False;
7984 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
7986 /* Piece will be copied from an existing context at
7987 the start of each new animation/drag. */
7988 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
7990 /* Outline will be a read-only copy of an existing */
7991 anim->outlineGC = None;
7997 XWindowAttributes info;
7999 if (xpmDone && gameInfo.variant == oldVariant) return;
8000 if(xpmDone) oldVariant = gameInfo.variant; // first time pieces might not be created yet
8001 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8003 InitAnimState(&game, &info);
8004 InitAnimState(&player, &info);
8006 /* For XPM pieces, we need bitmaps to use as masks. */
8008 CreateAnimMasks(info.depth);
8014 static Boolean frameWaiting;
8016 static RETSIGTYPE FrameAlarm (sig)
8019 frameWaiting = False;
8020 /* In case System-V style signals. Needed?? */
8021 signal(SIGALRM, FrameAlarm);
8028 struct itimerval delay;
8030 XSync(xDisplay, False);
8033 frameWaiting = True;
8034 signal(SIGALRM, FrameAlarm);
8035 delay.it_interval.tv_sec =
8036 delay.it_value.tv_sec = time / 1000;
8037 delay.it_interval.tv_usec =
8038 delay.it_value.tv_usec = (time % 1000) * 1000;
8039 setitimer(ITIMER_REAL, &delay, NULL);
8040 while (frameWaiting) pause();
8041 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8042 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8043 setitimer(ITIMER_REAL, &delay, NULL);
8053 XSync(xDisplay, False);
8055 usleep(time * 1000);
8060 /* Convert board position to corner of screen rect and color */
8063 ScreenSquare(column, row, pt, color)
8064 int column; int row; XPoint * pt; int * color;
8067 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8068 pt->y = lineGap + row * (squareSize + lineGap);
8070 pt->x = lineGap + column * (squareSize + lineGap);
8071 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8073 *color = SquareColor(row, column);
8076 /* Convert window coords to square */
8079 BoardSquare(x, y, column, row)
8080 int x; int y; int * column; int * row;
8082 *column = EventToSquare(x, BOARD_WIDTH);
8083 if (flipView && *column >= 0)
8084 *column = BOARD_WIDTH - 1 - *column;
8085 *row = EventToSquare(y, BOARD_HEIGHT);
8086 if (!flipView && *row >= 0)
8087 *row = BOARD_HEIGHT - 1 - *row;
8092 #undef Max /* just in case */
8094 #define Max(a, b) ((a) > (b) ? (a) : (b))
8095 #define Min(a, b) ((a) < (b) ? (a) : (b))
8098 SetRect(rect, x, y, width, height)
8099 XRectangle * rect; int x; int y; int width; int height;
8103 rect->width = width;
8104 rect->height = height;
8107 /* Test if two frames overlap. If they do, return
8108 intersection rect within old and location of
8109 that rect within new. */
8112 Intersect(old, new, size, area, pt)
8113 XPoint * old; XPoint * new;
8114 int size; XRectangle * area; XPoint * pt;
8116 if (old->x > new->x + size || new->x > old->x + size ||
8117 old->y > new->y + size || new->y > old->y + size) {
8120 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8121 size - abs(old->x - new->x), size - abs(old->y - new->y));
8122 pt->x = Max(old->x - new->x, 0);
8123 pt->y = Max(old->y - new->y, 0);
8128 /* For two overlapping frames, return the rect(s)
8129 in the old that do not intersect with the new. */
8132 CalcUpdateRects(old, new, size, update, nUpdates)
8133 XPoint * old; XPoint * new; int size;
8134 XRectangle update[]; int * nUpdates;
8138 /* If old = new (shouldn't happen) then nothing to draw */
8139 if (old->x == new->x && old->y == new->y) {
8143 /* Work out what bits overlap. Since we know the rects
8144 are the same size we don't need a full intersect calc. */
8146 /* Top or bottom edge? */
8147 if (new->y > old->y) {
8148 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8150 } else if (old->y > new->y) {
8151 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8152 size, old->y - new->y);
8155 /* Left or right edge - don't overlap any update calculated above. */
8156 if (new->x > old->x) {
8157 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8158 new->x - old->x, size - abs(new->y - old->y));
8160 } else if (old->x > new->x) {
8161 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8162 old->x - new->x, size - abs(new->y - old->y));
8169 /* Generate a series of frame coords from start->mid->finish.
8170 The movement rate doubles until the half way point is
8171 reached, then halves back down to the final destination,
8172 which gives a nice slow in/out effect. The algorithmn
8173 may seem to generate too many intermediates for short
8174 moves, but remember that the purpose is to attract the
8175 viewers attention to the piece about to be moved and
8176 then to where it ends up. Too few frames would be less
8180 Tween(start, mid, finish, factor, frames, nFrames)
8181 XPoint * start; XPoint * mid;
8182 XPoint * finish; int factor;
8183 XPoint frames[]; int * nFrames;
8185 int fraction, n, count;
8189 /* Slow in, stepping 1/16th, then 1/8th, ... */
8191 for (n = 0; n < factor; n++)
8193 for (n = 0; n < factor; n++) {
8194 frames[count].x = start->x + (mid->x - start->x) / fraction;
8195 frames[count].y = start->y + (mid->y - start->y) / fraction;
8197 fraction = fraction / 2;
8201 frames[count] = *mid;
8204 /* Slow out, stepping 1/2, then 1/4, ... */
8206 for (n = 0; n < factor; n++) {
8207 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8208 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8210 fraction = fraction * 2;
8215 /* Draw a piece on the screen without disturbing what's there */
8218 SelectGCMask(piece, clip, outline, mask)
8219 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8223 /* Bitmap for piece being moved. */
8224 if (appData.monoMode) {
8225 *mask = *pieceToSolid(piece);
8226 } else if (useImages) {
8228 *mask = xpmMask[piece];
8230 *mask = ximMaskPm[piece];
8233 *mask = *pieceToSolid(piece);
8236 /* GC for piece being moved. Square color doesn't matter, but
8237 since it gets modified we make a copy of the original. */
8239 if (appData.monoMode)
8244 if (appData.monoMode)
8249 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8251 /* Outline only used in mono mode and is not modified */
8253 *outline = bwPieceGC;
8255 *outline = wbPieceGC;
8259 OverlayPiece(piece, clip, outline, dest)
8260 ChessSquare piece; GC clip; GC outline; Drawable dest;
8265 /* Draw solid rectangle which will be clipped to shape of piece */
8266 XFillRectangle(xDisplay, dest, clip,
8267 0, 0, squareSize, squareSize);
8268 if (appData.monoMode)
8269 /* Also draw outline in contrasting color for black
8270 on black / white on white cases */
8271 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8272 0, 0, squareSize, squareSize, 0, 0, 1);
8274 /* Copy the piece */
8279 if(appData.upsideDown && flipView) kind ^= 2;
8280 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8282 0, 0, squareSize, squareSize,
8287 /* Animate the movement of a single piece */
8290 BeginAnimation(anim, piece, startColor, start)
8298 if(appData.upsideDown && flipView) piece += piece < BlackPawn ? BlackPawn : -BlackPawn;
8299 /* The old buffer is initialised with the start square (empty) */
8300 BlankSquare(start->x, start->y, startColor, EmptySquare, anim->saveBuf, 0);
8301 anim->prevFrame = *start;
8303 /* The piece will be drawn using its own bitmap as a matte */
8304 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8305 XSetClipMask(xDisplay, anim->pieceGC, mask);
8309 AnimationFrame(anim, frame, piece)
8314 XRectangle updates[4];
8319 /* Save what we are about to draw into the new buffer */
8320 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8321 frame->x, frame->y, squareSize, squareSize,
8324 /* Erase bits of the previous frame */
8325 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8326 /* Where the new frame overlapped the previous,
8327 the contents in newBuf are wrong. */
8328 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8329 overlap.x, overlap.y,
8330 overlap.width, overlap.height,
8332 /* Repaint the areas in the old that don't overlap new */
8333 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8334 for (i = 0; i < count; i++)
8335 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8336 updates[i].x - anim->prevFrame.x,
8337 updates[i].y - anim->prevFrame.y,
8338 updates[i].width, updates[i].height,
8339 updates[i].x, updates[i].y);
8341 /* Easy when no overlap */
8342 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8343 0, 0, squareSize, squareSize,
8344 anim->prevFrame.x, anim->prevFrame.y);
8347 /* Save this frame for next time round */
8348 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8349 0, 0, squareSize, squareSize,
8351 anim->prevFrame = *frame;
8353 /* Draw piece over original screen contents, not current,
8354 and copy entire rect. Wipes out overlapping piece images. */
8355 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8356 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8357 0, 0, squareSize, squareSize,
8358 frame->x, frame->y);
8362 EndAnimation (anim, finish)
8366 XRectangle updates[4];
8371 /* The main code will redraw the final square, so we
8372 only need to erase the bits that don't overlap. */
8373 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8374 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8375 for (i = 0; i < count; i++)
8376 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8377 updates[i].x - anim->prevFrame.x,
8378 updates[i].y - anim->prevFrame.y,
8379 updates[i].width, updates[i].height,
8380 updates[i].x, updates[i].y);
8382 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8383 0, 0, squareSize, squareSize,
8384 anim->prevFrame.x, anim->prevFrame.y);
8389 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8391 ChessSquare piece; int startColor;
8392 XPoint * start; XPoint * finish;
8393 XPoint frames[]; int nFrames;
8397 BeginAnimation(anim, piece, startColor, start);
8398 for (n = 0; n < nFrames; n++) {
8399 AnimationFrame(anim, &(frames[n]), piece);
8400 FrameDelay(appData.animSpeed);
8402 EndAnimation(anim, finish);
8406 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
8409 ChessSquare piece = board[fromY][toY];
8410 board[fromY][toY] = EmptySquare;
8411 DrawPosition(FALSE, board);
8413 x = lineGap + ((BOARD_WIDTH-1)-toX) * (squareSize + lineGap);
8414 y = lineGap + toY * (squareSize + lineGap);
8416 x = lineGap + toX * (squareSize + lineGap);
8417 y = lineGap + ((BOARD_HEIGHT-1)-toY) * (squareSize + lineGap);
8419 for(i=1; i<4*kFactor; i++) {
8420 int r = squareSize * 9 * i/(20*kFactor - 5);
8421 XFillArc(xDisplay, xBoardWindow, highlineGC,
8422 x + squareSize/2 - r, y+squareSize/2 - r, 2*r, 2*r, 0, 64*360);
8423 FrameDelay(appData.animSpeed);
8425 board[fromY][toY] = piece;
8428 /* Main control logic for deciding what to animate and how */
8431 AnimateMove(board, fromX, fromY, toX, toY)
8440 XPoint start, finish, mid;
8441 XPoint frames[kFactor * 2 + 1];
8442 int nFrames, startColor, endColor;
8444 /* Are we animating? */
8445 if (!appData.animate || appData.blindfold)
8448 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8449 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8450 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8452 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8453 piece = board[fromY][fromX];
8454 if (piece >= EmptySquare) return;
8459 hop = abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1;
8462 if (appData.debugMode) {
8463 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8464 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8465 piece, fromX, fromY, toX, toY); }
8467 ScreenSquare(fromX, fromY, &start, &startColor);
8468 ScreenSquare(toX, toY, &finish, &endColor);
8471 /* Knight: make straight movement then diagonal */
8472 if (abs(toY - fromY) < abs(toX - fromX)) {
8473 mid.x = start.x + (finish.x - start.x) / 2;
8477 mid.y = start.y + (finish.y - start.y) / 2;
8480 mid.x = start.x + (finish.x - start.x) / 2;
8481 mid.y = start.y + (finish.y - start.y) / 2;
8484 /* Don't use as many frames for very short moves */
8485 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8486 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8488 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8489 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8490 if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged
8492 for(i=0; i<BOARD_WIDTH; i++) for(j=0; j<BOARD_HEIGHT; j++)
8493 if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] = True;
8496 /* Be sure end square is redrawn */
8497 damage[0][toY][toX] = True;
8501 DragPieceBegin(x, y)
8504 int boardX, boardY, color;
8507 /* Are we animating? */
8508 if (!appData.animateDragging || appData.blindfold)
8511 /* Figure out which square we start in and the
8512 mouse position relative to top left corner. */
8513 BoardSquare(x, y, &boardX, &boardY);
8514 player.startBoardX = boardX;
8515 player.startBoardY = boardY;
8516 ScreenSquare(boardX, boardY, &corner, &color);
8517 player.startSquare = corner;
8518 player.startColor = color;
8519 /* As soon as we start dragging, the piece will jump slightly to
8520 be centered over the mouse pointer. */
8521 player.mouseDelta.x = squareSize/2;
8522 player.mouseDelta.y = squareSize/2;
8523 /* Initialise animation */
8524 player.dragPiece = PieceForSquare(boardX, boardY);
8526 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8527 player.dragActive = True;
8528 BeginAnimation(&player, player.dragPiece, color, &corner);
8529 /* Mark this square as needing to be redrawn. Note that
8530 we don't remove the piece though, since logically (ie
8531 as seen by opponent) the move hasn't been made yet. */
8532 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8533 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8534 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8535 corner.x, corner.y, squareSize, squareSize,
8536 0, 0); // [HGM] zh: unstack in stead of grab
8537 if(gatingPiece != EmptySquare) {
8538 /* Kludge alert: When gating we want the introduced
8539 piece to appear on the from square. To generate an
8540 image of it, we draw it on the board, copy the image,
8541 and draw the original piece again. */
8542 ChessSquare piece = boards[currentMove][boardY][boardX];
8543 DrawSquare(boardY, boardX, gatingPiece, 0);
8544 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8545 corner.x, corner.y, squareSize, squareSize, 0, 0);
8546 DrawSquare(boardY, boardX, piece, 0);
8548 damage[0][boardY][boardX] = True;
8550 player.dragActive = False;
8555 ChangeDragPiece(ChessSquare piece)
8558 player.dragPiece = piece;
8559 /* The piece will be drawn using its own bitmap as a matte */
8560 SelectGCMask(piece, &player.pieceGC, &player.outlineGC, &mask);
8561 XSetClipMask(xDisplay, player.pieceGC, mask);
8570 /* Are we animating? */
8571 if (!appData.animateDragging || appData.blindfold)
8575 if (! player.dragActive)
8577 /* Move piece, maintaining same relative position
8578 of mouse within square */
8579 corner.x = x - player.mouseDelta.x;
8580 corner.y = y - player.mouseDelta.y;
8581 AnimationFrame(&player, &corner, player.dragPiece);
8583 if (appData.highlightDragging) {
8585 BoardSquare(x, y, &boardX, &boardY);
8586 SetHighlights(fromX, fromY, boardX, boardY);
8595 int boardX, boardY, color;
8598 /* Are we animating? */
8599 if (!appData.animateDragging || appData.blindfold)
8603 if (! player.dragActive)
8605 /* Last frame in sequence is square piece is
8606 placed on, which may not match mouse exactly. */
8607 BoardSquare(x, y, &boardX, &boardY);
8608 ScreenSquare(boardX, boardY, &corner, &color);
8609 EndAnimation(&player, &corner);
8611 /* Be sure end square is redrawn */
8612 damage[0][boardY][boardX] = True;
8614 /* This prevents weird things happening with fast successive
8615 clicks which on my Sun at least can cause motion events
8616 without corresponding press/release. */
8617 player.dragActive = False;
8620 /* Handle expose event while piece being dragged */
8625 if (!player.dragActive || appData.blindfold)
8628 /* What we're doing: logically, the move hasn't been made yet,
8629 so the piece is still in it's original square. But visually
8630 it's being dragged around the board. So we erase the square
8631 that the piece is on and draw it at the last known drag point. */
8632 BlankSquare(player.startSquare.x, player.startSquare.y,
8633 player.startColor, EmptySquare, xBoardWindow, 1);
8634 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8635 damage[0][player.startBoardY][player.startBoardX] = TRUE;
8638 #include <sys/ioctl.h>
8639 int get_term_width()
8641 int fd, default_width;
8644 default_width = 79; // this is FICS default anyway...
8646 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8648 if (!ioctl(fd, TIOCGSIZE, &win))
8649 default_width = win.ts_cols;
8650 #elif defined(TIOCGWINSZ)
8652 if (!ioctl(fd, TIOCGWINSZ, &win))
8653 default_width = win.ws_col;
8655 return default_width;
8661 static int old_width = 0;
8662 int new_width = get_term_width();
8664 if (old_width != new_width)
8665 ics_printf("set width %d\n", new_width);
8666 old_width = new_width;
8669 void NotifyFrontendLogin()
8674 /* [AS] Arrow highlighting support */
8676 static double A_WIDTH = 5; /* Width of arrow body */
8678 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
8679 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
8681 static double Sqr( double x )
8686 static int Round( double x )
8688 return (int) (x + 0.5);
8691 void SquareToPos(int rank, int file, int *x, int *y)
8694 *x = lineGap + ((BOARD_WIDTH-1)-file) * (squareSize + lineGap);
8695 *y = lineGap + rank * (squareSize + lineGap);
8697 *x = lineGap + file * (squareSize + lineGap);
8698 *y = lineGap + ((BOARD_HEIGHT-1)-rank) * (squareSize + lineGap);
8702 /* Draw an arrow between two points using current settings */
8703 void DrawArrowBetweenPoints( int s_x, int s_y, int d_x, int d_y )
8706 double dx, dy, j, k, x, y;
8709 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
8711 arrow[0].x = s_x + A_WIDTH + 0.5;
8714 arrow[1].x = s_x + A_WIDTH + 0.5;
8715 arrow[1].y = d_y - h;
8717 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8718 arrow[2].y = d_y - h;
8723 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
8724 arrow[5].y = d_y - h;
8726 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8727 arrow[4].y = d_y - h;
8729 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
8732 else if( d_y == s_y ) {
8733 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
8736 arrow[0].y = s_y + A_WIDTH + 0.5;
8738 arrow[1].x = d_x - w;
8739 arrow[1].y = s_y + A_WIDTH + 0.5;
8741 arrow[2].x = d_x - w;
8742 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8747 arrow[5].x = d_x - w;
8748 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
8750 arrow[4].x = d_x - w;
8751 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8754 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
8757 /* [AS] Needed a lot of paper for this! :-) */
8758 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
8759 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
8761 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
8763 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
8768 arrow[0].x = Round(x - j);
8769 arrow[0].y = Round(y + j*dx);
8771 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
8772 arrow[1].y = Round(arrow[0].y - 2*j*dx);
8775 x = (double) d_x - k;
8776 y = (double) d_y - k*dy;
8779 x = (double) d_x + k;
8780 y = (double) d_y + k*dy;
8783 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
8785 arrow[6].x = Round(x - j);
8786 arrow[6].y = Round(y + j*dx);
8788 arrow[2].x = Round(arrow[6].x + 2*j);
8789 arrow[2].y = Round(arrow[6].y - 2*j*dx);
8791 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
8792 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
8797 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
8798 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
8801 XFillPolygon(xDisplay, xBoardWindow, highlineGC, arrow, 7, Nonconvex, CoordModeOrigin);
8802 // Polygon( hdc, arrow, 7 );
8805 /* [AS] Draw an arrow between two squares */
8806 void DrawArrowBetweenSquares( int s_col, int s_row, int d_col, int d_row )
8808 int s_x, s_y, d_x, d_y, hor, vert, i;
8810 if( s_col == d_col && s_row == d_row ) {
8814 /* Get source and destination points */
8815 SquareToPos( s_row, s_col, &s_x, &s_y);
8816 SquareToPos( d_row, d_col, &d_x, &d_y);
8819 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
8821 else if( d_y < s_y ) {
8822 d_y += squareSize / 2 + squareSize / 4;
8825 d_y += squareSize / 2;
8829 d_x += squareSize / 2 - squareSize / 4;
8831 else if( d_x < s_x ) {
8832 d_x += squareSize / 2 + squareSize / 4;
8835 d_x += squareSize / 2;
8838 s_x += squareSize / 2;
8839 s_y += squareSize / 2;
8842 A_WIDTH = squareSize / 14.; //[HGM] make float
8844 DrawArrowBetweenPoints( s_x, s_y, d_x, d_y );
8846 hor = 64*s_col + 32; vert = 64*s_row + 32;
8847 for(i=0; i<= 64; i++) {
8848 damage[0][vert+6>>6][hor+6>>6] = True;
8849 damage[0][vert-6>>6][hor+6>>6] = True;
8850 damage[0][vert+6>>6][hor-6>>6] = True;
8851 damage[0][vert-6>>6][hor-6>>6] = True;
8852 hor += d_col - s_col; vert += d_row - s_row;
8856 Boolean IsDrawArrowEnabled()
8858 return appData.highlightMoveWithArrow && squareSize >= 32;
8861 void DrawArrowHighlight(int fromX, int fromY, int toX,int toY)
8863 if( IsDrawArrowEnabled() && fromX >= 0 && fromY >= 0 && toX >= 0 && toY >= 0)
8864 DrawArrowBetweenSquares(fromX, fromY, toX, toY);