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 matchMode = 2; // This is back-end, really
\r
5804 appData.matchGames = appData.defaultMatchGames;
\r
5806 first.matchWins = second.matchWins = 0;
\r
5810 void IcsClientProc(w, event, prms, nprms)
5819 void EditGameProc(w, event, prms, nprms)
5828 void EditPositionProc(w, event, prms, nprms)
5834 EditPositionEvent();
5837 void TrainingProc(w, event, prms, nprms)
5846 void EditCommentProc(w, event, prms, nprms)
5854 if (PopDown(1)) { // popdown succesful
5856 XtSetArg(args[j], XtNleftBitmap, None); j++;
5857 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"), args, j);
5858 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"), args, j);
5859 } else // was not up
5863 void IcsInputBoxProc(w, event, prms, nprms)
5869 if (!PopDown(4)) ICSInputBoxPopUp();
5872 void AcceptProc(w, event, prms, nprms)
5881 void DeclineProc(w, event, prms, nprms)
5890 void RematchProc(w, event, prms, nprms)
5899 void CallFlagProc(w, event, prms, nprms)
5908 void DrawProc(w, event, prms, nprms)
5917 void AbortProc(w, event, prms, nprms)
5926 void AdjournProc(w, event, prms, nprms)
5935 void ResignProc(w, event, prms, nprms)
5944 void AdjuWhiteProc(w, event, prms, nprms)
5950 UserAdjudicationEvent(+1);
5953 void AdjuBlackProc(w, event, prms, nprms)
5959 UserAdjudicationEvent(-1);
5962 void AdjuDrawProc(w, event, prms, nprms)
5968 UserAdjudicationEvent(0);
5971 void EnterKeyProc(w, event, prms, nprms)
5977 if (shellUp[4] == True)
5981 void UpKeyProc(w, event, prms, nprms)
5986 { // [HGM] input: let up-arrow recall previous line from history
5993 if (!shellUp[4]) return;
5994 edit = boxOptions[0].handle;
5996 XtSetArg(args[j], XtNstring, &val); j++;
5997 XtGetValues(edit, args, j);
5998 val = PrevInHistory(val);
5999 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6000 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6002 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6003 XawTextReplace(edit, 0, 0, &t);
6004 XawTextSetInsertionPoint(edit, 9999);
6008 void DownKeyProc(w, event, prms, nprms)
6013 { // [HGM] input: let down-arrow recall next line from history
6018 if (!shellUp[4]) return;
6019 edit = boxOptions[0].handle;
6020 val = NextInHistory();
6021 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6022 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6024 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6025 XawTextReplace(edit, 0, 0, &t);
6026 XawTextSetInsertionPoint(edit, 9999);
6030 void StopObservingProc(w, event, prms, nprms)
6036 StopObservingEvent();
6039 void StopExaminingProc(w, event, prms, nprms)
6045 StopExaminingEvent();
6048 void UploadProc(w, event, prms, nprms)
6058 void ForwardProc(w, event, prms, nprms)
6068 void BackwardProc(w, event, prms, nprms)
6077 void ToStartProc(w, event, prms, nprms)
6086 void ToEndProc(w, event, prms, nprms)
6095 void RevertProc(w, event, prms, nprms)
6104 void AnnotateProc(w, event, prms, nprms)
6113 void TruncateGameProc(w, event, prms, nprms)
6119 TruncateGameEvent();
6121 void RetractMoveProc(w, event, prms, nprms)
6130 void MoveNowProc(w, event, prms, nprms)
6139 void FlipViewProc(w, event, prms, nprms)
6145 flipView = !flipView;
6146 DrawPosition(True, NULL);
6149 void PonderNextMoveProc(w, event, prms, nprms)
6157 PonderNextMoveEvent(!appData.ponderNextMove);
6158 #ifndef OPTIONSDIALOG
6159 if (appData.ponderNextMove) {
6160 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6162 XtSetArg(args[0], XtNleftBitmap, None);
6164 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6169 #ifndef OPTIONSDIALOG
6170 void AlwaysQueenProc(w, event, prms, nprms)
6178 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6180 if (appData.alwaysPromoteToQueen) {
6181 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6183 XtSetArg(args[0], XtNleftBitmap, None);
6185 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6189 void AnimateDraggingProc(w, event, prms, nprms)
6197 appData.animateDragging = !appData.animateDragging;
6199 if (appData.animateDragging) {
6200 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6203 XtSetArg(args[0], XtNleftBitmap, None);
6205 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6209 void AnimateMovingProc(w, event, prms, nprms)
6217 appData.animate = !appData.animate;
6219 if (appData.animate) {
6220 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6223 XtSetArg(args[0], XtNleftBitmap, None);
6225 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6229 void AutoflagProc(w, event, prms, nprms)
6237 appData.autoCallFlag = !appData.autoCallFlag;
6239 if (appData.autoCallFlag) {
6240 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6242 XtSetArg(args[0], XtNleftBitmap, None);
6244 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6248 void AutoflipProc(w, event, prms, nprms)
6256 appData.autoFlipView = !appData.autoFlipView;
6258 if (appData.autoFlipView) {
6259 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6261 XtSetArg(args[0], XtNleftBitmap, None);
6263 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6267 void BlindfoldProc(w, event, prms, nprms)
6275 appData.blindfold = !appData.blindfold;
6277 if (appData.blindfold) {
6278 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6280 XtSetArg(args[0], XtNleftBitmap, None);
6282 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6285 DrawPosition(True, NULL);
6288 void TestLegalityProc(w, event, prms, nprms)
6296 appData.testLegality = !appData.testLegality;
6298 if (appData.testLegality) {
6299 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6301 XtSetArg(args[0], XtNleftBitmap, None);
6303 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6308 void FlashMovesProc(w, event, prms, nprms)
6316 if (appData.flashCount == 0) {
6317 appData.flashCount = 3;
6319 appData.flashCount = -appData.flashCount;
6322 if (appData.flashCount > 0) {
6323 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6325 XtSetArg(args[0], XtNleftBitmap, None);
6327 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6332 void HighlightDraggingProc(w, event, prms, nprms)
6340 appData.highlightDragging = !appData.highlightDragging;
6342 if (appData.highlightDragging) {
6343 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6345 XtSetArg(args[0], XtNleftBitmap, None);
6347 XtSetValues(XtNameToWidget(menuBarWidget,
6348 "menuOptions.Highlight Dragging"), args, 1);
6352 void HighlightLastMoveProc(w, event, prms, nprms)
6360 appData.highlightLastMove = !appData.highlightLastMove;
6362 if (appData.highlightLastMove) {
6363 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6365 XtSetArg(args[0], XtNleftBitmap, None);
6367 XtSetValues(XtNameToWidget(menuBarWidget,
6368 "menuOptions.Highlight Last Move"), args, 1);
6371 void HighlightArrowProc(w, event, prms, nprms)
6379 appData.highlightMoveWithArrow = !appData.highlightMoveWithArrow;
6381 if (appData.highlightMoveWithArrow) {
6382 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6384 XtSetArg(args[0], XtNleftBitmap, None);
6386 XtSetValues(XtNameToWidget(menuBarWidget,
6387 "menuOptions.Arrow"), args, 1);
6391 void IcsAlarmProc(w, event, prms, nprms)
6399 appData.icsAlarm = !appData.icsAlarm;
6401 if (appData.icsAlarm) {
6402 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6404 XtSetArg(args[0], XtNleftBitmap, None);
6406 XtSetValues(XtNameToWidget(menuBarWidget,
6407 "menuOptions.ICS Alarm"), args, 1);
6411 void MoveSoundProc(w, event, prms, nprms)
6419 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6421 if (appData.ringBellAfterMoves) {
6422 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6424 XtSetArg(args[0], XtNleftBitmap, None);
6426 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6430 void OneClickProc(w, event, prms, nprms)
6438 appData.oneClick = !appData.oneClick;
6440 if (appData.oneClick) {
6441 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6443 XtSetArg(args[0], XtNleftBitmap, None);
6445 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.OneClick"),
6449 void PeriodicUpdatesProc(w, event, prms, nprms)
6457 PeriodicUpdatesEvent(!appData.periodicUpdates);
6459 if (appData.periodicUpdates) {
6460 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6462 XtSetArg(args[0], XtNleftBitmap, None);
6464 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6468 void PopupExitMessageProc(w, event, prms, nprms)
6476 appData.popupExitMessage = !appData.popupExitMessage;
6478 if (appData.popupExitMessage) {
6479 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6481 XtSetArg(args[0], XtNleftBitmap, None);
6483 XtSetValues(XtNameToWidget(menuBarWidget,
6484 "menuOptions.Popup Exit Message"), args, 1);
6487 void PopupMoveErrorsProc(w, event, prms, nprms)
6495 appData.popupMoveErrors = !appData.popupMoveErrors;
6497 if (appData.popupMoveErrors) {
6498 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6500 XtSetArg(args[0], XtNleftBitmap, None);
6502 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6507 void PremoveProc(w, event, prms, nprms)
6515 appData.premove = !appData.premove;
6517 if (appData.premove) {
6518 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6520 XtSetArg(args[0], XtNleftBitmap, None);
6522 XtSetValues(XtNameToWidget(menuBarWidget,
6523 "menuOptions.Premove"), args, 1);
6527 void ShowCoordsProc(w, event, prms, nprms)
6535 appData.showCoords = !appData.showCoords;
6537 if (appData.showCoords) {
6538 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6540 XtSetArg(args[0], XtNleftBitmap, None);
6542 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6545 DrawPosition(True, NULL);
6548 void ShowThinkingProc(w, event, prms, nprms)
6554 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6555 ShowThinkingEvent();
6558 void HideThinkingProc(w, event, prms, nprms)
6566 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6567 ShowThinkingEvent();
6569 if (appData.hideThinkingFromHuman) {
6570 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6572 XtSetArg(args[0], XtNleftBitmap, None);
6574 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6579 void SaveOnExitProc(w, event, prms, nprms)
6587 saveSettingsOnExit = !saveSettingsOnExit;
6589 if (saveSettingsOnExit) {
6590 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6592 XtSetArg(args[0], XtNleftBitmap, None);
6594 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6598 void SaveSettingsProc(w, event, prms, nprms)
6604 SaveSettings(settingsFileName);
6607 void InfoProc(w, event, prms, nprms)
6614 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6619 void ManProc(w, event, prms, nprms)
6627 if (nprms && *nprms > 0)
6631 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6635 void HintProc(w, event, prms, nprms)
6644 void BookProc(w, event, prms, nprms)
6653 void AboutProc(w, event, prms, nprms)
6661 char *zippy = " (with Zippy code)";
6665 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6666 programVersion, zippy,
6667 "Copyright 1991 Digital Equipment Corporation",
6668 "Enhancements Copyright 1992-2009 Free Software Foundation",
6669 "Enhancements Copyright 2005 Alessandro Scotti",
6670 PACKAGE, " is free software and carries NO WARRANTY;",
6671 "see the file COPYING for more information.");
6672 ErrorPopUp(_("About XBoard"), buf, FALSE);
6675 void DebugProc(w, event, prms, nprms)
6681 appData.debugMode = !appData.debugMode;
6684 void AboutGameProc(w, event, prms, nprms)
6693 void NothingProc(w, event, prms, nprms)
6702 void Iconify(w, event, prms, nprms)
6711 XtSetArg(args[0], XtNiconic, True);
6712 XtSetValues(shellWidget, args, 1);
6715 void DisplayMessage(message, extMessage)
6716 char *message, *extMessage;
6718 /* display a message in the message widget */
6727 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
6732 message = extMessage;
6736 /* need to test if messageWidget already exists, since this function
6737 can also be called during the startup, if for example a Xresource
6738 is not set up correctly */
6741 XtSetArg(arg, XtNlabel, message);
6742 XtSetValues(messageWidget, &arg, 1);
6748 void DisplayTitle(text)
6753 char title[MSG_SIZ];
6756 if (text == NULL) text = "";
6758 if (appData.titleInWindow) {
6760 XtSetArg(args[i], XtNlabel, text); i++;
6761 XtSetValues(titleWidget, args, i);
6764 if (*text != NULLCHAR) {
6765 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
6766 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
6767 } else if (appData.icsActive) {
6768 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
6769 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
6770 } else if (appData.cmailGameName[0] != NULLCHAR) {
6771 snprintf(icon, sizeof(icon), "%s", "CMail");
6772 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
6774 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
6775 } else if (gameInfo.variant == VariantGothic) {
6776 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6777 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
6780 } else if (gameInfo.variant == VariantFalcon) {
6781 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6782 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
6784 } else if (appData.noChessProgram) {
6785 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6786 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
6788 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
6789 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
6792 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
6793 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
6794 XtSetValues(shellWidget, args, i);
6799 DisplayError(message, error)
6806 if (appData.debugMode || appData.matchMode) {
6807 fprintf(stderr, "%s: %s\n", programName, message);
6810 if (appData.debugMode || appData.matchMode) {
6811 fprintf(stderr, "%s: %s: %s\n",
6812 programName, message, strerror(error));
6814 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6817 ErrorPopUp(_("Error"), message, FALSE);
6821 void DisplayMoveError(message)
6826 DrawPosition(FALSE, NULL);
6827 if (appData.debugMode || appData.matchMode) {
6828 fprintf(stderr, "%s: %s\n", programName, message);
6830 if (appData.popupMoveErrors) {
6831 ErrorPopUp(_("Error"), message, FALSE);
6833 DisplayMessage(message, "");
6838 void DisplayFatalError(message, error, status)
6844 errorExitStatus = status;
6846 fprintf(stderr, "%s: %s\n", programName, message);
6848 fprintf(stderr, "%s: %s: %s\n",
6849 programName, message, strerror(error));
6850 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6853 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
6854 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
6860 void DisplayInformation(message)
6864 ErrorPopUp(_("Information"), message, TRUE);
6867 void DisplayNote(message)
6871 ErrorPopUp(_("Note"), message, FALSE);
6875 NullXErrorCheck(dpy, error_event)
6877 XErrorEvent *error_event;
6882 void DisplayIcsInteractionTitle(message)
6885 if (oldICSInteractionTitle == NULL) {
6886 /* Magic to find the old window title, adapted from vim */
6887 char *wina = getenv("WINDOWID");
6889 Window win = (Window) atoi(wina);
6890 Window root, parent, *children;
6891 unsigned int nchildren;
6892 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
6894 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
6895 if (!XQueryTree(xDisplay, win, &root, &parent,
6896 &children, &nchildren)) break;
6897 if (children) XFree((void *)children);
6898 if (parent == root || parent == 0) break;
6901 XSetErrorHandler(oldHandler);
6903 if (oldICSInteractionTitle == NULL) {
6904 oldICSInteractionTitle = "xterm";
6907 printf("\033]0;%s\007", message);
6911 char pendingReplyPrefix[MSG_SIZ];
6912 ProcRef pendingReplyPR;
6914 void AskQuestionProc(w, event, prms, nprms)
6921 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
6925 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
6928 void AskQuestionPopDown()
6930 if (!askQuestionUp) return;
6931 XtPopdown(askQuestionShell);
6932 XtDestroyWidget(askQuestionShell);
6933 askQuestionUp = False;
6936 void AskQuestionReplyAction(w, event, prms, nprms)
6946 reply = XawDialogGetValueString(w = XtParent(w));
6947 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
6948 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
6949 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
6950 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
6951 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
6952 AskQuestionPopDown();
6954 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
6957 void AskQuestionCallback(w, client_data, call_data)
6959 XtPointer client_data, call_data;
6964 XtSetArg(args[0], XtNlabel, &name);
6965 XtGetValues(w, args, 1);
6967 if (strcmp(name, _("cancel")) == 0) {
6968 AskQuestionPopDown();
6970 AskQuestionReplyAction(w, NULL, NULL, NULL);
6974 void AskQuestion(title, question, replyPrefix, pr)
6975 char *title, *question, *replyPrefix;
6979 Widget popup, layout, dialog, edit;
6985 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
6986 pendingReplyPR = pr;
6989 XtSetArg(args[i], XtNresizable, True); i++;
6990 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
6991 askQuestionShell = popup =
6992 XtCreatePopupShell(title, transientShellWidgetClass,
6993 shellWidget, args, i);
6996 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
6997 layoutArgs, XtNumber(layoutArgs));
7000 XtSetArg(args[i], XtNlabel, question); i++;
7001 XtSetArg(args[i], XtNvalue, ""); i++;
7002 XtSetArg(args[i], XtNborderWidth, 0); i++;
7003 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7006 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7007 (XtPointer) dialog);
7008 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7009 (XtPointer) dialog);
7011 XtRealizeWidget(popup);
7012 CatchDeleteWindow(popup, "AskQuestionPopDown");
7014 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7015 &x, &y, &win_x, &win_y, &mask);
7017 XtSetArg(args[0], XtNx, x - 10);
7018 XtSetArg(args[1], XtNy, y - 30);
7019 XtSetValues(popup, args, 2);
7021 XtPopup(popup, XtGrabExclusive);
7022 askQuestionUp = True;
7024 edit = XtNameToWidget(dialog, "*value");
7025 XtSetKeyboardFocus(popup, edit);
7033 if (*name == NULLCHAR) {
7035 } else if (strcmp(name, "$") == 0) {
7036 putc(BELLCHAR, stderr);
7039 char *prefix = "", *sep = "";
7040 if(!strchr(name, '/')) { prefix = appData.soundDirectory; sep = "/"; }
7041 snprintf(buf, sizeof(buf), "%s '%s%s%s' &", appData.soundProgram, prefix, sep, name);
7049 PlaySound(appData.soundMove);
7055 PlaySound(appData.soundIcsWin);
7061 PlaySound(appData.soundIcsLoss);
7067 PlaySound(appData.soundIcsDraw);
7071 PlayIcsUnfinishedSound()
7073 PlaySound(appData.soundIcsUnfinished);
7079 PlaySound(appData.soundIcsAlarm);
7085 system("stty echo");
7091 system("stty -echo");
7095 Colorize(cc, continuation)
7100 int count, outCount, error;
7102 if (textColors[(int)cc].bg > 0) {
7103 if (textColors[(int)cc].fg > 0) {
7104 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7105 textColors[(int)cc].fg, textColors[(int)cc].bg);
7107 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7108 textColors[(int)cc].bg);
7111 if (textColors[(int)cc].fg > 0) {
7112 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7113 textColors[(int)cc].fg);
7115 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7118 count = strlen(buf);
7119 outCount = OutputToProcess(NoProc, buf, count, &error);
7120 if (outCount < count) {
7121 DisplayFatalError(_("Error writing to display"), error, 1);
7124 if (continuation) return;
7127 PlaySound(appData.soundShout);
7130 PlaySound(appData.soundSShout);
7133 PlaySound(appData.soundChannel1);
7136 PlaySound(appData.soundChannel);
7139 PlaySound(appData.soundKibitz);
7142 PlaySound(appData.soundTell);
7144 case ColorChallenge:
7145 PlaySound(appData.soundChallenge);
7148 PlaySound(appData.soundRequest);
7151 PlaySound(appData.soundSeek);
7162 return getpwuid(getuid())->pw_name;
7166 ExpandPathName(path)
7169 static char static_buf[4*MSG_SIZ];
7170 char *d, *s, buf[4*MSG_SIZ];
7176 while (*s && isspace(*s))
7185 if (*(s+1) == '/') {
7186 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7190 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7191 { char *p; if(p = strchr(buf, '/')) *p = 0; }
7192 pwd = getpwnam(buf);
7195 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7199 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7200 strcat(d, strchr(s+1, '/'));
7204 safeStrCpy(d, s, 4*MSG_SIZ );
7211 static char host_name[MSG_SIZ];
7213 #if HAVE_GETHOSTNAME
7214 gethostname(host_name, MSG_SIZ);
7216 #else /* not HAVE_GETHOSTNAME */
7217 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7218 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7220 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7222 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7223 #endif /* not HAVE_GETHOSTNAME */
7226 XtIntervalId delayedEventTimerXID = 0;
7227 DelayedEventCallback delayedEventCallback = 0;
7232 delayedEventTimerXID = 0;
7233 delayedEventCallback();
7237 ScheduleDelayedEvent(cb, millisec)
7238 DelayedEventCallback cb; long millisec;
7240 if(delayedEventTimerXID && delayedEventCallback == cb)
7241 // [HGM] alive: replace, rather than add or flush identical event
7242 XtRemoveTimeOut(delayedEventTimerXID);
7243 delayedEventCallback = cb;
7244 delayedEventTimerXID =
7245 XtAppAddTimeOut(appContext, millisec,
7246 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7249 DelayedEventCallback
7252 if (delayedEventTimerXID) {
7253 return delayedEventCallback;
7260 CancelDelayedEvent()
7262 if (delayedEventTimerXID) {
7263 XtRemoveTimeOut(delayedEventTimerXID);
7264 delayedEventTimerXID = 0;
7268 XtIntervalId loadGameTimerXID = 0;
7270 int LoadGameTimerRunning()
7272 return loadGameTimerXID != 0;
7275 int StopLoadGameTimer()
7277 if (loadGameTimerXID != 0) {
7278 XtRemoveTimeOut(loadGameTimerXID);
7279 loadGameTimerXID = 0;
7287 LoadGameTimerCallback(arg, id)
7291 loadGameTimerXID = 0;
7296 StartLoadGameTimer(millisec)
7300 XtAppAddTimeOut(appContext, millisec,
7301 (XtTimerCallbackProc) LoadGameTimerCallback,
7305 XtIntervalId analysisClockXID = 0;
7308 AnalysisClockCallback(arg, id)
7312 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7313 || appData.icsEngineAnalyze) { // [DM]
7314 AnalysisPeriodicEvent(0);
7315 StartAnalysisClock();
7320 StartAnalysisClock()
7323 XtAppAddTimeOut(appContext, 2000,
7324 (XtTimerCallbackProc) AnalysisClockCallback,
7328 XtIntervalId clockTimerXID = 0;
7330 int ClockTimerRunning()
7332 return clockTimerXID != 0;
7335 int StopClockTimer()
7337 if (clockTimerXID != 0) {
7338 XtRemoveTimeOut(clockTimerXID);
7347 ClockTimerCallback(arg, id)
7356 StartClockTimer(millisec)
7360 XtAppAddTimeOut(appContext, millisec,
7361 (XtTimerCallbackProc) ClockTimerCallback,
7366 DisplayTimerLabel(w, color, timer, highlight)
7375 /* check for low time warning */
7376 Pixel foregroundOrWarningColor = timerForegroundPixel;
7379 appData.lowTimeWarning &&
7380 (timer / 1000) < appData.icsAlarmTime)
7381 foregroundOrWarningColor = lowTimeWarningColor;
7383 if (appData.clockMode) {
7384 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7385 XtSetArg(args[0], XtNlabel, buf);
7387 snprintf(buf, MSG_SIZ, "%s ", color);
7388 XtSetArg(args[0], XtNlabel, buf);
7393 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7394 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7396 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7397 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7400 XtSetValues(w, args, 3);
7404 DisplayWhiteClock(timeRemaining, highlight)
7410 if(appData.noGUI) return;
7411 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7412 if (highlight && iconPixmap == bIconPixmap) {
7413 iconPixmap = wIconPixmap;
7414 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7415 XtSetValues(shellWidget, args, 1);
7420 DisplayBlackClock(timeRemaining, highlight)
7426 if(appData.noGUI) return;
7427 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7428 if (highlight && iconPixmap == wIconPixmap) {
7429 iconPixmap = bIconPixmap;
7430 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7431 XtSetValues(shellWidget, args, 1);
7449 int StartChildProcess(cmdLine, dir, pr)
7456 int to_prog[2], from_prog[2];
7460 if (appData.debugMode) {
7461 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7464 /* We do NOT feed the cmdLine to the shell; we just
7465 parse it into blank-separated arguments in the
7466 most simple-minded way possible.
7469 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7472 while(*p == ' ') p++;
7474 if(*p == '"' || *p == '\'')
7475 p = strchr(++argv[i-1], *p);
7476 else p = strchr(p, ' ');
7477 if (p == NULL) break;
7482 SetUpChildIO(to_prog, from_prog);
7484 if ((pid = fork()) == 0) {
7486 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7487 close(to_prog[1]); // first close the unused pipe ends
7488 close(from_prog[0]);
7489 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7490 dup2(from_prog[1], 1);
7491 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7492 close(from_prog[1]); // and closing again loses one of the pipes!
7493 if(fileno(stderr) >= 2) // better safe than sorry...
7494 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7496 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7501 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7503 execvp(argv[0], argv);
7505 /* If we get here, exec failed */
7510 /* Parent process */
7512 close(from_prog[1]);
7514 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7517 cp->fdFrom = from_prog[0];
7518 cp->fdTo = to_prog[1];
7523 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7524 static RETSIGTYPE AlarmCallBack(int n)
7530 DestroyChildProcess(pr, signalType)
7534 ChildProc *cp = (ChildProc *) pr;
7536 if (cp->kind != CPReal) return;
7538 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7539 signal(SIGALRM, AlarmCallBack);
7541 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7542 kill(cp->pid, SIGKILL); // kill it forcefully
7543 wait((int *) 0); // and wait again
7547 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7549 /* Process is exiting either because of the kill or because of
7550 a quit command sent by the backend; either way, wait for it to die.
7559 InterruptChildProcess(pr)
7562 ChildProc *cp = (ChildProc *) pr;
7564 if (cp->kind != CPReal) return;
7565 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7568 int OpenTelnet(host, port, pr)
7573 char cmdLine[MSG_SIZ];
7575 if (port[0] == NULLCHAR) {
7576 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7578 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7580 return StartChildProcess(cmdLine, "", pr);
7583 int OpenTCP(host, port, pr)
7589 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7590 #else /* !OMIT_SOCKETS */
7592 struct sockaddr_in sa;
7594 unsigned short uport;
7597 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7601 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7602 sa.sin_family = AF_INET;
7603 sa.sin_addr.s_addr = INADDR_ANY;
7604 uport = (unsigned short) 0;
7605 sa.sin_port = htons(uport);
7606 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7610 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7611 if (!(hp = gethostbyname(host))) {
7613 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7614 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7615 hp->h_addrtype = AF_INET;
7617 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7618 hp->h_addr_list[0] = (char *) malloc(4);
7619 hp->h_addr_list[0][0] = b0;
7620 hp->h_addr_list[0][1] = b1;
7621 hp->h_addr_list[0][2] = b2;
7622 hp->h_addr_list[0][3] = b3;
7627 sa.sin_family = hp->h_addrtype;
7628 uport = (unsigned short) atoi(port);
7629 sa.sin_port = htons(uport);
7630 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7632 if (connect(s, (struct sockaddr *) &sa,
7633 sizeof(struct sockaddr_in)) < 0) {
7637 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7644 #endif /* !OMIT_SOCKETS */
7649 int OpenCommPort(name, pr)
7656 fd = open(name, 2, 0);
7657 if (fd < 0) return errno;
7659 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7669 int OpenLoopback(pr)
7675 SetUpChildIO(to, from);
7677 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7680 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7687 int OpenRcmd(host, user, cmd, pr)
7688 char *host, *user, *cmd;
7691 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7695 #define INPUT_SOURCE_BUF_SIZE 8192
7704 char buf[INPUT_SOURCE_BUF_SIZE];
7709 DoInputCallback(closure, source, xid)
7714 InputSource *is = (InputSource *) closure;
7719 if (is->lineByLine) {
7720 count = read(is->fd, is->unused,
7721 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7723 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7726 is->unused += count;
7728 while (p < is->unused) {
7729 q = memchr(p, '\n', is->unused - p);
7730 if (q == NULL) break;
7732 (is->func)(is, is->closure, p, q - p, 0);
7736 while (p < is->unused) {
7741 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
7746 (is->func)(is, is->closure, is->buf, count, error);
7750 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
7757 ChildProc *cp = (ChildProc *) pr;
7759 is = (InputSource *) calloc(1, sizeof(InputSource));
7760 is->lineByLine = lineByLine;
7764 is->fd = fileno(stdin);
7766 is->kind = cp->kind;
7767 is->fd = cp->fdFrom;
7770 is->unused = is->buf;
7773 is->xid = XtAppAddInput(appContext, is->fd,
7774 (XtPointer) (XtInputReadMask),
7775 (XtInputCallbackProc) DoInputCallback,
7777 is->closure = closure;
7778 return (InputSourceRef) is;
7782 RemoveInputSource(isr)
7785 InputSource *is = (InputSource *) isr;
7787 if (is->xid == 0) return;
7788 XtRemoveInput(is->xid);
7792 int OutputToProcess(pr, message, count, outError)
7798 static int line = 0;
7799 ChildProc *cp = (ChildProc *) pr;
7804 if (appData.noJoin || !appData.useInternalWrap)
7805 outCount = fwrite(message, 1, count, stdout);
7808 int width = get_term_width();
7809 int len = wrap(NULL, message, count, width, &line);
7810 char *msg = malloc(len);
7814 outCount = fwrite(message, 1, count, stdout);
7817 dbgchk = wrap(msg, message, count, width, &line);
7818 if (dbgchk != len && appData.debugMode)
7819 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
7820 outCount = fwrite(msg, 1, dbgchk, stdout);
7826 outCount = write(cp->fdTo, message, count);
7836 /* Output message to process, with "ms" milliseconds of delay
7837 between each character. This is needed when sending the logon
7838 script to ICC, which for some reason doesn't like the
7839 instantaneous send. */
7840 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
7847 ChildProc *cp = (ChildProc *) pr;
7852 r = write(cp->fdTo, message++, 1);
7865 /**** Animation code by Hugh Fisher, DCS, ANU.
7867 Known problem: if a window overlapping the board is
7868 moved away while a piece is being animated underneath,
7869 the newly exposed area won't be updated properly.
7870 I can live with this.
7872 Known problem: if you look carefully at the animation
7873 of pieces in mono mode, they are being drawn as solid
7874 shapes without interior detail while moving. Fixing
7875 this would be a major complication for minimal return.
7878 /* Masks for XPM pieces. Black and white pieces can have
7879 different shapes, but in the interest of retaining my
7880 sanity pieces must have the same outline on both light
7881 and dark squares, and all pieces must use the same
7882 background square colors/images. */
7884 static int xpmDone = 0;
7887 CreateAnimMasks (pieceDepth)
7894 unsigned long plane;
7897 /* Need a bitmap just to get a GC with right depth */
7898 buf = XCreatePixmap(xDisplay, xBoardWindow,
7900 values.foreground = 1;
7901 values.background = 0;
7902 /* Don't use XtGetGC, not read only */
7903 maskGC = XCreateGC(xDisplay, buf,
7904 GCForeground | GCBackground, &values);
7905 XFreePixmap(xDisplay, buf);
7907 buf = XCreatePixmap(xDisplay, xBoardWindow,
7908 squareSize, squareSize, pieceDepth);
7909 values.foreground = XBlackPixel(xDisplay, xScreen);
7910 values.background = XWhitePixel(xDisplay, xScreen);
7911 bufGC = XCreateGC(xDisplay, buf,
7912 GCForeground | GCBackground, &values);
7914 for (piece = WhitePawn; piece <= BlackKing; piece++) {
7915 /* Begin with empty mask */
7916 if(!xpmDone) // [HGM] pieces: keep using existing
7917 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
7918 squareSize, squareSize, 1);
7919 XSetFunction(xDisplay, maskGC, GXclear);
7920 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
7921 0, 0, squareSize, squareSize);
7923 /* Take a copy of the piece */
7928 XSetFunction(xDisplay, bufGC, GXcopy);
7929 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
7931 0, 0, squareSize, squareSize, 0, 0);
7933 /* XOR the background (light) over the piece */
7934 XSetFunction(xDisplay, bufGC, GXxor);
7936 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
7937 0, 0, squareSize, squareSize, 0, 0);
7939 XSetForeground(xDisplay, bufGC, lightSquareColor);
7940 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
7943 /* We now have an inverted piece image with the background
7944 erased. Construct mask by just selecting all the non-zero
7945 pixels - no need to reconstruct the original image. */
7946 XSetFunction(xDisplay, maskGC, GXor);
7948 /* Might be quicker to download an XImage and create bitmap
7949 data from it rather than this N copies per piece, but it
7950 only takes a fraction of a second and there is a much
7951 longer delay for loading the pieces. */
7952 for (n = 0; n < pieceDepth; n ++) {
7953 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
7954 0, 0, squareSize, squareSize,
7960 XFreePixmap(xDisplay, buf);
7961 XFreeGC(xDisplay, bufGC);
7962 XFreeGC(xDisplay, maskGC);
7966 InitAnimState (anim, info)
7968 XWindowAttributes * info;
7973 /* Each buffer is square size, same depth as window */
7974 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
7975 squareSize, squareSize, info->depth);
7976 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
7977 squareSize, squareSize, info->depth);
7979 /* Create a plain GC for blitting */
7980 mask = GCForeground | GCBackground | GCFunction |
7981 GCPlaneMask | GCGraphicsExposures;
7982 values.foreground = XBlackPixel(xDisplay, xScreen);
7983 values.background = XWhitePixel(xDisplay, xScreen);
7984 values.function = GXcopy;
7985 values.plane_mask = AllPlanes;
7986 values.graphics_exposures = False;
7987 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
7989 /* Piece will be copied from an existing context at
7990 the start of each new animation/drag. */
7991 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
7993 /* Outline will be a read-only copy of an existing */
7994 anim->outlineGC = None;
8000 XWindowAttributes info;
8002 if (xpmDone && gameInfo.variant == oldVariant) return;
8003 if(xpmDone) oldVariant = gameInfo.variant; // first time pieces might not be created yet
8004 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8006 InitAnimState(&game, &info);
8007 InitAnimState(&player, &info);
8009 /* For XPM pieces, we need bitmaps to use as masks. */
8011 CreateAnimMasks(info.depth);
8017 static Boolean frameWaiting;
8019 static RETSIGTYPE FrameAlarm (sig)
8022 frameWaiting = False;
8023 /* In case System-V style signals. Needed?? */
8024 signal(SIGALRM, FrameAlarm);
8031 struct itimerval delay;
8033 XSync(xDisplay, False);
8036 frameWaiting = True;
8037 signal(SIGALRM, FrameAlarm);
8038 delay.it_interval.tv_sec =
8039 delay.it_value.tv_sec = time / 1000;
8040 delay.it_interval.tv_usec =
8041 delay.it_value.tv_usec = (time % 1000) * 1000;
8042 setitimer(ITIMER_REAL, &delay, NULL);
8043 while (frameWaiting) pause();
8044 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8045 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8046 setitimer(ITIMER_REAL, &delay, NULL);
8056 XSync(xDisplay, False);
8058 usleep(time * 1000);
8063 /* Convert board position to corner of screen rect and color */
8066 ScreenSquare(column, row, pt, color)
8067 int column; int row; XPoint * pt; int * color;
8070 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8071 pt->y = lineGap + row * (squareSize + lineGap);
8073 pt->x = lineGap + column * (squareSize + lineGap);
8074 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8076 *color = SquareColor(row, column);
8079 /* Convert window coords to square */
8082 BoardSquare(x, y, column, row)
8083 int x; int y; int * column; int * row;
8085 *column = EventToSquare(x, BOARD_WIDTH);
8086 if (flipView && *column >= 0)
8087 *column = BOARD_WIDTH - 1 - *column;
8088 *row = EventToSquare(y, BOARD_HEIGHT);
8089 if (!flipView && *row >= 0)
8090 *row = BOARD_HEIGHT - 1 - *row;
8095 #undef Max /* just in case */
8097 #define Max(a, b) ((a) > (b) ? (a) : (b))
8098 #define Min(a, b) ((a) < (b) ? (a) : (b))
8101 SetRect(rect, x, y, width, height)
8102 XRectangle * rect; int x; int y; int width; int height;
8106 rect->width = width;
8107 rect->height = height;
8110 /* Test if two frames overlap. If they do, return
8111 intersection rect within old and location of
8112 that rect within new. */
8115 Intersect(old, new, size, area, pt)
8116 XPoint * old; XPoint * new;
8117 int size; XRectangle * area; XPoint * pt;
8119 if (old->x > new->x + size || new->x > old->x + size ||
8120 old->y > new->y + size || new->y > old->y + size) {
8123 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8124 size - abs(old->x - new->x), size - abs(old->y - new->y));
8125 pt->x = Max(old->x - new->x, 0);
8126 pt->y = Max(old->y - new->y, 0);
8131 /* For two overlapping frames, return the rect(s)
8132 in the old that do not intersect with the new. */
8135 CalcUpdateRects(old, new, size, update, nUpdates)
8136 XPoint * old; XPoint * new; int size;
8137 XRectangle update[]; int * nUpdates;
8141 /* If old = new (shouldn't happen) then nothing to draw */
8142 if (old->x == new->x && old->y == new->y) {
8146 /* Work out what bits overlap. Since we know the rects
8147 are the same size we don't need a full intersect calc. */
8149 /* Top or bottom edge? */
8150 if (new->y > old->y) {
8151 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8153 } else if (old->y > new->y) {
8154 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8155 size, old->y - new->y);
8158 /* Left or right edge - don't overlap any update calculated above. */
8159 if (new->x > old->x) {
8160 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8161 new->x - old->x, size - abs(new->y - old->y));
8163 } else if (old->x > new->x) {
8164 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8165 old->x - new->x, size - abs(new->y - old->y));
8172 /* Generate a series of frame coords from start->mid->finish.
8173 The movement rate doubles until the half way point is
8174 reached, then halves back down to the final destination,
8175 which gives a nice slow in/out effect. The algorithmn
8176 may seem to generate too many intermediates for short
8177 moves, but remember that the purpose is to attract the
8178 viewers attention to the piece about to be moved and
8179 then to where it ends up. Too few frames would be less
8183 Tween(start, mid, finish, factor, frames, nFrames)
8184 XPoint * start; XPoint * mid;
8185 XPoint * finish; int factor;
8186 XPoint frames[]; int * nFrames;
8188 int fraction, n, count;
8192 /* Slow in, stepping 1/16th, then 1/8th, ... */
8194 for (n = 0; n < factor; n++)
8196 for (n = 0; n < factor; n++) {
8197 frames[count].x = start->x + (mid->x - start->x) / fraction;
8198 frames[count].y = start->y + (mid->y - start->y) / fraction;
8200 fraction = fraction / 2;
8204 frames[count] = *mid;
8207 /* Slow out, stepping 1/2, then 1/4, ... */
8209 for (n = 0; n < factor; n++) {
8210 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8211 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8213 fraction = fraction * 2;
8218 /* Draw a piece on the screen without disturbing what's there */
8221 SelectGCMask(piece, clip, outline, mask)
8222 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8226 /* Bitmap for piece being moved. */
8227 if (appData.monoMode) {
8228 *mask = *pieceToSolid(piece);
8229 } else if (useImages) {
8231 *mask = xpmMask[piece];
8233 *mask = ximMaskPm[piece];
8236 *mask = *pieceToSolid(piece);
8239 /* GC for piece being moved. Square color doesn't matter, but
8240 since it gets modified we make a copy of the original. */
8242 if (appData.monoMode)
8247 if (appData.monoMode)
8252 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8254 /* Outline only used in mono mode and is not modified */
8256 *outline = bwPieceGC;
8258 *outline = wbPieceGC;
8262 OverlayPiece(piece, clip, outline, dest)
8263 ChessSquare piece; GC clip; GC outline; Drawable dest;
8268 /* Draw solid rectangle which will be clipped to shape of piece */
8269 XFillRectangle(xDisplay, dest, clip,
8270 0, 0, squareSize, squareSize);
8271 if (appData.monoMode)
8272 /* Also draw outline in contrasting color for black
8273 on black / white on white cases */
8274 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8275 0, 0, squareSize, squareSize, 0, 0, 1);
8277 /* Copy the piece */
8282 if(appData.upsideDown && flipView) kind ^= 2;
8283 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8285 0, 0, squareSize, squareSize,
8290 /* Animate the movement of a single piece */
8293 BeginAnimation(anim, piece, startColor, start)
8301 if(appData.upsideDown && flipView) piece += piece < BlackPawn ? BlackPawn : -BlackPawn;
8302 /* The old buffer is initialised with the start square (empty) */
8303 BlankSquare(start->x, start->y, startColor, EmptySquare, anim->saveBuf, 0);
8304 anim->prevFrame = *start;
8306 /* The piece will be drawn using its own bitmap as a matte */
8307 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8308 XSetClipMask(xDisplay, anim->pieceGC, mask);
8312 AnimationFrame(anim, frame, piece)
8317 XRectangle updates[4];
8322 /* Save what we are about to draw into the new buffer */
8323 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8324 frame->x, frame->y, squareSize, squareSize,
8327 /* Erase bits of the previous frame */
8328 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8329 /* Where the new frame overlapped the previous,
8330 the contents in newBuf are wrong. */
8331 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8332 overlap.x, overlap.y,
8333 overlap.width, overlap.height,
8335 /* Repaint the areas in the old that don't overlap new */
8336 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8337 for (i = 0; i < count; i++)
8338 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8339 updates[i].x - anim->prevFrame.x,
8340 updates[i].y - anim->prevFrame.y,
8341 updates[i].width, updates[i].height,
8342 updates[i].x, updates[i].y);
8344 /* Easy when no overlap */
8345 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8346 0, 0, squareSize, squareSize,
8347 anim->prevFrame.x, anim->prevFrame.y);
8350 /* Save this frame for next time round */
8351 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8352 0, 0, squareSize, squareSize,
8354 anim->prevFrame = *frame;
8356 /* Draw piece over original screen contents, not current,
8357 and copy entire rect. Wipes out overlapping piece images. */
8358 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8359 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8360 0, 0, squareSize, squareSize,
8361 frame->x, frame->y);
8365 EndAnimation (anim, finish)
8369 XRectangle updates[4];
8374 /* The main code will redraw the final square, so we
8375 only need to erase the bits that don't overlap. */
8376 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8377 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8378 for (i = 0; i < count; i++)
8379 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8380 updates[i].x - anim->prevFrame.x,
8381 updates[i].y - anim->prevFrame.y,
8382 updates[i].width, updates[i].height,
8383 updates[i].x, updates[i].y);
8385 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8386 0, 0, squareSize, squareSize,
8387 anim->prevFrame.x, anim->prevFrame.y);
8392 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8394 ChessSquare piece; int startColor;
8395 XPoint * start; XPoint * finish;
8396 XPoint frames[]; int nFrames;
8400 BeginAnimation(anim, piece, startColor, start);
8401 for (n = 0; n < nFrames; n++) {
8402 AnimationFrame(anim, &(frames[n]), piece);
8403 FrameDelay(appData.animSpeed);
8405 EndAnimation(anim, finish);
8409 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
8412 ChessSquare piece = board[fromY][toY];
8413 board[fromY][toY] = EmptySquare;
8414 DrawPosition(FALSE, board);
8416 x = lineGap + ((BOARD_WIDTH-1)-toX) * (squareSize + lineGap);
8417 y = lineGap + toY * (squareSize + lineGap);
8419 x = lineGap + toX * (squareSize + lineGap);
8420 y = lineGap + ((BOARD_HEIGHT-1)-toY) * (squareSize + lineGap);
8422 for(i=1; i<4*kFactor; i++) {
8423 int r = squareSize * 9 * i/(20*kFactor - 5);
8424 XFillArc(xDisplay, xBoardWindow, highlineGC,
8425 x + squareSize/2 - r, y+squareSize/2 - r, 2*r, 2*r, 0, 64*360);
8426 FrameDelay(appData.animSpeed);
8428 board[fromY][toY] = piece;
8431 /* Main control logic for deciding what to animate and how */
8434 AnimateMove(board, fromX, fromY, toX, toY)
8443 XPoint start, finish, mid;
8444 XPoint frames[kFactor * 2 + 1];
8445 int nFrames, startColor, endColor;
8447 /* Are we animating? */
8448 if (!appData.animate || appData.blindfold)
8451 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8452 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8453 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8455 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8456 piece = board[fromY][fromX];
8457 if (piece >= EmptySquare) return;
8462 hop = abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1;
8465 if (appData.debugMode) {
8466 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8467 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8468 piece, fromX, fromY, toX, toY); }
8470 ScreenSquare(fromX, fromY, &start, &startColor);
8471 ScreenSquare(toX, toY, &finish, &endColor);
8474 /* Knight: make straight movement then diagonal */
8475 if (abs(toY - fromY) < abs(toX - fromX)) {
8476 mid.x = start.x + (finish.x - start.x) / 2;
8480 mid.y = start.y + (finish.y - start.y) / 2;
8483 mid.x = start.x + (finish.x - start.x) / 2;
8484 mid.y = start.y + (finish.y - start.y) / 2;
8487 /* Don't use as many frames for very short moves */
8488 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8489 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8491 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8492 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8493 if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged
8495 for(i=0; i<BOARD_WIDTH; i++) for(j=0; j<BOARD_HEIGHT; j++)
8496 if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] = True;
8499 /* Be sure end square is redrawn */
8500 damage[0][toY][toX] = True;
8504 DragPieceBegin(x, y)
8507 int boardX, boardY, color;
8510 /* Are we animating? */
8511 if (!appData.animateDragging || appData.blindfold)
8514 /* Figure out which square we start in and the
8515 mouse position relative to top left corner. */
8516 BoardSquare(x, y, &boardX, &boardY);
8517 player.startBoardX = boardX;
8518 player.startBoardY = boardY;
8519 ScreenSquare(boardX, boardY, &corner, &color);
8520 player.startSquare = corner;
8521 player.startColor = color;
8522 /* As soon as we start dragging, the piece will jump slightly to
8523 be centered over the mouse pointer. */
8524 player.mouseDelta.x = squareSize/2;
8525 player.mouseDelta.y = squareSize/2;
8526 /* Initialise animation */
8527 player.dragPiece = PieceForSquare(boardX, boardY);
8529 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8530 player.dragActive = True;
8531 BeginAnimation(&player, player.dragPiece, color, &corner);
8532 /* Mark this square as needing to be redrawn. Note that
8533 we don't remove the piece though, since logically (ie
8534 as seen by opponent) the move hasn't been made yet. */
8535 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8536 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8537 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8538 corner.x, corner.y, squareSize, squareSize,
8539 0, 0); // [HGM] zh: unstack in stead of grab
8540 if(gatingPiece != EmptySquare) {
8541 /* Kludge alert: When gating we want the introduced
8542 piece to appear on the from square. To generate an
8543 image of it, we draw it on the board, copy the image,
8544 and draw the original piece again. */
8545 ChessSquare piece = boards[currentMove][boardY][boardX];
8546 DrawSquare(boardY, boardX, gatingPiece, 0);
8547 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8548 corner.x, corner.y, squareSize, squareSize, 0, 0);
8549 DrawSquare(boardY, boardX, piece, 0);
8551 damage[0][boardY][boardX] = True;
8553 player.dragActive = False;
8558 ChangeDragPiece(ChessSquare piece)
8561 player.dragPiece = piece;
8562 /* The piece will be drawn using its own bitmap as a matte */
8563 SelectGCMask(piece, &player.pieceGC, &player.outlineGC, &mask);
8564 XSetClipMask(xDisplay, player.pieceGC, mask);
8573 /* Are we animating? */
8574 if (!appData.animateDragging || appData.blindfold)
8578 if (! player.dragActive)
8580 /* Move piece, maintaining same relative position
8581 of mouse within square */
8582 corner.x = x - player.mouseDelta.x;
8583 corner.y = y - player.mouseDelta.y;
8584 AnimationFrame(&player, &corner, player.dragPiece);
8586 if (appData.highlightDragging) {
8588 BoardSquare(x, y, &boardX, &boardY);
8589 SetHighlights(fromX, fromY, boardX, boardY);
8598 int boardX, boardY, color;
8601 /* Are we animating? */
8602 if (!appData.animateDragging || appData.blindfold)
8606 if (! player.dragActive)
8608 /* Last frame in sequence is square piece is
8609 placed on, which may not match mouse exactly. */
8610 BoardSquare(x, y, &boardX, &boardY);
8611 ScreenSquare(boardX, boardY, &corner, &color);
8612 EndAnimation(&player, &corner);
8614 /* Be sure end square is redrawn */
8615 damage[0][boardY][boardX] = True;
8617 /* This prevents weird things happening with fast successive
8618 clicks which on my Sun at least can cause motion events
8619 without corresponding press/release. */
8620 player.dragActive = False;
8623 /* Handle expose event while piece being dragged */
8628 if (!player.dragActive || appData.blindfold)
8631 /* What we're doing: logically, the move hasn't been made yet,
8632 so the piece is still in it's original square. But visually
8633 it's being dragged around the board. So we erase the square
8634 that the piece is on and draw it at the last known drag point. */
8635 BlankSquare(player.startSquare.x, player.startSquare.y,
8636 player.startColor, EmptySquare, xBoardWindow, 1);
8637 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8638 damage[0][player.startBoardY][player.startBoardX] = TRUE;
8641 #include <sys/ioctl.h>
8642 int get_term_width()
8644 int fd, default_width;
8647 default_width = 79; // this is FICS default anyway...
8649 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8651 if (!ioctl(fd, TIOCGSIZE, &win))
8652 default_width = win.ts_cols;
8653 #elif defined(TIOCGWINSZ)
8655 if (!ioctl(fd, TIOCGWINSZ, &win))
8656 default_width = win.ws_col;
8658 return default_width;
8664 static int old_width = 0;
8665 int new_width = get_term_width();
8667 if (old_width != new_width)
8668 ics_printf("set width %d\n", new_width);
8669 old_width = new_width;
8672 void NotifyFrontendLogin()
8677 /* [AS] Arrow highlighting support */
8679 static double A_WIDTH = 5; /* Width of arrow body */
8681 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
8682 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
8684 static double Sqr( double x )
8689 static int Round( double x )
8691 return (int) (x + 0.5);
8694 void SquareToPos(int rank, int file, int *x, int *y)
8697 *x = lineGap + ((BOARD_WIDTH-1)-file) * (squareSize + lineGap);
8698 *y = lineGap + rank * (squareSize + lineGap);
8700 *x = lineGap + file * (squareSize + lineGap);
8701 *y = lineGap + ((BOARD_HEIGHT-1)-rank) * (squareSize + lineGap);
8705 /* Draw an arrow between two points using current settings */
8706 void DrawArrowBetweenPoints( int s_x, int s_y, int d_x, int d_y )
8709 double dx, dy, j, k, x, y;
8712 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
8714 arrow[0].x = s_x + A_WIDTH + 0.5;
8717 arrow[1].x = s_x + A_WIDTH + 0.5;
8718 arrow[1].y = d_y - h;
8720 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8721 arrow[2].y = d_y - h;
8726 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
8727 arrow[5].y = d_y - h;
8729 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8730 arrow[4].y = d_y - h;
8732 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
8735 else if( d_y == s_y ) {
8736 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
8739 arrow[0].y = s_y + A_WIDTH + 0.5;
8741 arrow[1].x = d_x - w;
8742 arrow[1].y = s_y + A_WIDTH + 0.5;
8744 arrow[2].x = d_x - w;
8745 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8750 arrow[5].x = d_x - w;
8751 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
8753 arrow[4].x = d_x - w;
8754 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8757 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
8760 /* [AS] Needed a lot of paper for this! :-) */
8761 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
8762 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
8764 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
8766 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
8771 arrow[0].x = Round(x - j);
8772 arrow[0].y = Round(y + j*dx);
8774 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
8775 arrow[1].y = Round(arrow[0].y - 2*j*dx);
8778 x = (double) d_x - k;
8779 y = (double) d_y - k*dy;
8782 x = (double) d_x + k;
8783 y = (double) d_y + k*dy;
8786 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
8788 arrow[6].x = Round(x - j);
8789 arrow[6].y = Round(y + j*dx);
8791 arrow[2].x = Round(arrow[6].x + 2*j);
8792 arrow[2].y = Round(arrow[6].y - 2*j*dx);
8794 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
8795 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
8800 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
8801 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
8804 XFillPolygon(xDisplay, xBoardWindow, highlineGC, arrow, 7, Nonconvex, CoordModeOrigin);
8805 // Polygon( hdc, arrow, 7 );
8808 /* [AS] Draw an arrow between two squares */
8809 void DrawArrowBetweenSquares( int s_col, int s_row, int d_col, int d_row )
8811 int s_x, s_y, d_x, d_y, hor, vert, i;
8813 if( s_col == d_col && s_row == d_row ) {
8817 /* Get source and destination points */
8818 SquareToPos( s_row, s_col, &s_x, &s_y);
8819 SquareToPos( d_row, d_col, &d_x, &d_y);
8822 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
8824 else if( d_y < s_y ) {
8825 d_y += squareSize / 2 + squareSize / 4;
8828 d_y += squareSize / 2;
8832 d_x += squareSize / 2 - squareSize / 4;
8834 else if( d_x < s_x ) {
8835 d_x += squareSize / 2 + squareSize / 4;
8838 d_x += squareSize / 2;
8841 s_x += squareSize / 2;
8842 s_y += squareSize / 2;
8845 A_WIDTH = squareSize / 14.; //[HGM] make float
8847 DrawArrowBetweenPoints( s_x, s_y, d_x, d_y );
8849 hor = 64*s_col + 32; vert = 64*s_row + 32;
8850 for(i=0; i<= 64; i++) {
8851 damage[0][vert+6>>6][hor+6>>6] = True;
8852 damage[0][vert-6>>6][hor+6>>6] = True;
8853 damage[0][vert+6>>6][hor-6>>6] = True;
8854 damage[0][vert-6>>6][hor-6>>6] = True;
8855 hor += d_col - s_col; vert += d_row - s_row;
8859 Boolean IsDrawArrowEnabled()
8861 return appData.highlightMoveWithArrow && squareSize >= 32;
8864 void DrawArrowHighlight(int fromX, int fromY, int toX,int toY)
8866 if( IsDrawArrowEnabled() && fromX >= 0 && fromY >= 0 && toX >= 0 && toY >= 0)
8867 DrawArrowBetweenSquares(fromX, fromY, toX, toY);