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 PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
326 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
327 void SavePositionProc P((Widget w, XEvent *event,
328 String *prms, Cardinal *nprms));
329 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
330 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
332 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
333 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
334 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
336 void MachineWhiteProc P((Widget w, XEvent *event,
337 String *prms, Cardinal *nprms));
338 void AnalyzeModeProc P((Widget w, XEvent *event,
339 String *prms, Cardinal *nprms));
340 void AnalyzeFileProc P((Widget w, XEvent *event,
341 String *prms, Cardinal *nprms));
342 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
344 void MatchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
345 void MatchOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
346 void IcsClientProc P((Widget w, XEvent *event, String *prms,
348 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
349 void EditPositionProc P((Widget w, XEvent *event,
350 String *prms, Cardinal *nprms));
351 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
352 void EditCommentProc P((Widget w, XEvent *event,
353 String *prms, Cardinal *nprms));
354 void IcsInputBoxProc P((Widget w, XEvent *event,
355 String *prms, Cardinal *nprms));
356 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
357 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
358 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
359 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
365 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
369 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
370 void StopObservingProc P((Widget w, XEvent *event, String *prms,
372 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
374 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
375 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
376 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
377 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
379 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
380 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
383 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
385 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
386 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
388 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
390 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
392 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
393 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
394 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
395 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
397 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
398 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
400 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
402 void HighlightArrowProc P((Widget w, XEvent *event, String *prms,
404 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
405 //void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
406 void OneClickProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
407 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
409 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
411 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
413 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
415 //void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
416 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
418 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
420 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
422 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
424 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
425 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
426 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
427 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
428 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
429 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
430 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
431 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
432 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
433 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
434 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
435 void DisplayMove P((int moveNumber));
436 void DisplayTitle P((char *title));
437 void ICSInitScript P((void));
438 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
439 void ErrorPopUp P((char *title, char *text, int modal));
440 void ErrorPopDown P((void));
441 static char *ExpandPathName P((char *path));
442 static void CreateAnimVars P((void));
443 static void DragPieceMove P((int x, int y));
444 static void DrawDragPiece P((void));
445 char *ModeToWidgetName P((GameMode mode));
446 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
447 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
448 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
449 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
450 void OptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
451 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
452 void IcsTextProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
453 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
454 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
455 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
456 void IcsOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
457 void SoundOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
458 void BoardOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
459 void LoadOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
460 void SaveOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
461 void GameListOptionsPopDown P(());
462 void ShufflePopDown P(());
463 void TimeControlPopDown P(());
464 void GenericPopDown P(());
465 void update_ics_width P(());
466 int get_term_width P(());
467 int CopyMemoProc P(());
468 void DrawArrowHighlight P((int fromX, int fromY, int toX,int toY));
469 Boolean IsDrawArrowEnabled P(());
472 * XBoard depends on Xt R4 or higher
474 int xtVersion = XtSpecificationRelease;
479 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
480 jailSquareColor, highlightSquareColor, premoveHighlightColor;
481 Pixel lowTimeWarningColor;
482 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
483 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
484 wjPieceGC, bjPieceGC, prelineGC, countGC;
485 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
486 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
487 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
488 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
489 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
490 ICSInputShell, fileNameShell, askQuestionShell;
491 Widget historyShell, evalGraphShell, gameListShell;
492 int hOffset; // [HGM] dual
493 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
494 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
495 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
496 Font clockFontID, coordFontID, countFontID;
497 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
498 XtAppContext appContext;
500 char *oldICSInteractionTitle;
504 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
506 Position commentX = -1, commentY = -1;
507 Dimension commentW, commentH;
508 typedef unsigned int BoardSize;
510 Boolean chessProgram;
512 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
513 int squareSize, smallLayout = 0, tinyLayout = 0,
514 marginW, marginH, // [HGM] for run-time resizing
515 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
516 ICSInputBoxUp = False, askQuestionUp = False,
517 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
518 errorUp = False, errorExitStatus = -1, lineGap, defaultLineGap;
519 Pixel timerForegroundPixel, timerBackgroundPixel;
520 Pixel buttonForegroundPixel, buttonBackgroundPixel;
521 char *chessDir, *programName, *programVersion,
522 *gameCopyFilename, *gamePasteFilename;
523 Boolean alwaysOnTop = False;
524 Boolean saveSettingsOnExit;
525 char *settingsFileName;
526 char *icsTextMenuString;
528 char *firstChessProgramNames;
529 char *secondChessProgramNames;
531 WindowPlacement wpMain;
532 WindowPlacement wpConsole;
533 WindowPlacement wpComment;
534 WindowPlacement wpMoveHistory;
535 WindowPlacement wpEvalGraph;
536 WindowPlacement wpEngineOutput;
537 WindowPlacement wpGameList;
538 WindowPlacement wpTags;
540 extern Widget shells[];
541 extern Boolean shellUp[];
545 Pixmap pieceBitmap[2][(int)BlackPawn];
546 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
547 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
548 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
549 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
550 Pixmap xpmBoardBitmap[2];
551 int useImages, useImageSqs, useTexture, textureW[2], textureH[2];
552 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
553 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
554 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
555 XImage *ximLightSquare, *ximDarkSquare;
558 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
559 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
561 #define White(piece) ((int)(piece) < (int)BlackPawn)
563 /* Variables for doing smooth animation. This whole thing
564 would be much easier if the board was double-buffered,
565 but that would require a fairly major rewrite. */
570 GC blitGC, pieceGC, outlineGC;
571 XPoint startSquare, prevFrame, mouseDelta;
575 int startBoardX, startBoardY;
578 /* There can be two pieces being animated at once: a player
579 can begin dragging a piece before the remote opponent has moved. */
581 static AnimState game, player;
583 /* Bitmaps for use as masks when drawing XPM pieces.
584 Need one for each black and white piece. */
585 static Pixmap xpmMask[BlackKing + 1];
587 /* This magic number is the number of intermediate frames used
588 in each half of the animation. For short moves it's reduced
589 by 1. The total number of frames will be factor * 2 + 1. */
592 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
594 MenuItem fileMenu[] = {
595 {N_("New Game Ctrl+N"), "New Game", ResetProc},
596 {N_("New Shuffle Game ..."), "New Shuffle Game", ShuffleMenuProc},
597 {N_("New Variant ... Alt+Shift+V"), "New Variant", NewVariantProc}, // [HGM] variant: not functional yet
598 {"----", NULL, NothingProc},
599 {N_("Load Game Ctrl+O"), "Load Game", LoadGameProc},
600 {N_("Load Position Ctrl+Shift+O"), "Load Position", LoadPositionProc},
601 // {N_("Load Next Game"), "Load Next Game", LoadNextGameProc},
602 // {N_("Load Previous Game"), "Load Previous Game", LoadPrevGameProc},
603 // {N_("Reload Same Game"), "Reload Same Game", ReloadGameProc},
604 {N_("Next Position Shift+PgDn"), "Load Next Position", LoadNextPositionProc},
605 {N_("Prev Position Shift+PgUp"), "Load Previous Position", LoadPrevPositionProc},
606 {"----", NULL, NothingProc},
607 // {N_("Reload Same Position"), "Reload Same Position", ReloadPositionProc},
608 {N_("Save Game Ctrl+S"), "Save Game", SaveGameProc},
609 {N_("Save Position Ctrl+Shift+S"), "Save Position", SavePositionProc},
610 {"----", NULL, NothingProc},
611 {N_("Mail Move"), "Mail Move", MailMoveProc},
612 {N_("Reload CMail Message"), "Reload CMail Message", ReloadCmailMsgProc},
613 {"----", NULL, NothingProc},
614 {N_("Quit Ctr+Q"), "Exit", QuitProc},
618 MenuItem editMenu[] = {
619 {N_("Copy Game Ctrl+C"), "Copy Game", CopyGameProc},
620 {N_("Copy Position Ctrl+Shift+C"), "Copy Position", CopyPositionProc},
621 {"----", NULL, NothingProc},
622 {N_("Paste Game Ctrl+V"), "Paste Game", PasteGameProc},
623 {N_("Paste Position Ctrl+Shift+V"), "Paste Position", PastePositionProc},
624 {"----", NULL, NothingProc},
625 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
626 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
627 {N_("Edit Tags"), "Edit Tags", EditTagsProc},
628 {N_("Edit Comment"), "Edit Comment", EditCommentProc},
629 {"----", NULL, NothingProc},
630 {N_("Revert Home"), "Revert", RevertProc},
631 {N_("Annotate"), "Annotate", AnnotateProc},
632 {N_("Truncate Game End"), "Truncate Game", TruncateGameProc},
633 {"----", NULL, NothingProc},
634 {N_("Backward Alt+Left"), "Backward", BackwardProc},
635 {N_("Forward Alt+Right"), "Forward", ForwardProc},
636 {N_("Back to Start Alt+Home"), "Back to Start", ToStartProc},
637 {N_("Forward to End Alt+End"), "Forward to End", ToEndProc},
641 MenuItem viewMenu[] = {
642 {N_("Flip View F2"), "Flip View", FlipViewProc},
643 {"----", NULL, NothingProc},
644 {N_("Engine Output Alt+Shift+O"), "Show Engine Output", EngineOutputProc},
645 {N_("Move History Alt+Shift+H"), "Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
646 {N_("Evaluation Graph Alt+Shift+E"), "Show Evaluation Graph", EvalGraphProc},
647 {N_("Game List Alt+Shift+G"), "Show Game List", ShowGameListProc},
648 {N_("ICS text menu"), "ICStex", IcsTextProc},
649 {"----", NULL, NothingProc},
650 {N_("Tags"), "Show Tags", EditTagsProc},
651 {N_("Comments"), "Show Comments", EditCommentProc},
652 {N_("ICS Input Box"), "ICS Input Box", IcsInputBoxProc},
653 {"----", NULL, NothingProc},
654 {N_("Board..."), "Board Options", BoardOptionsProc},
655 {N_("Game List Tags..."), "Game List", GameListOptionsPopUp},
659 MenuItem modeMenu[] = {
660 {N_("Machine White Ctrl+W"), "Machine White", MachineWhiteProc},
661 {N_("Machine Black Ctrl+B"), "Machine Black", MachineBlackProc},
662 {N_("Two Machines Ctrl+T"), "Two Machines", TwoMachinesProc},
663 {N_("Analysis Mode Ctrl+A"), "Analysis Mode", AnalyzeModeProc},
664 {N_("Analyze File Ctrl+F"), "Analyze File", AnalyzeFileProc },
665 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
666 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
667 {N_("Training"), "Training", TrainingProc},
668 {N_("ICS Client"), "ICS Client", IcsClientProc},
669 {"----", NULL, NothingProc},
670 {N_("Machine Match"), "Machine Match", MatchProc},
671 {N_("Pause Pause"), "Pause", PauseProc},
675 MenuItem actionMenu[] = {
676 {N_("Accept F3"), "Accept", AcceptProc},
677 {N_("Decline F4"), "Decline", DeclineProc},
678 {N_("Rematch F12"), "Rematch", RematchProc},
679 {"----", NULL, NothingProc},
680 {N_("Call Flag F5"), "Call Flag", CallFlagProc},
681 {N_("Draw F6"), "Draw", DrawProc},
682 {N_("Adjourn F7"), "Adjourn", AdjournProc},
683 {N_("Abort F8"),"Abort", AbortProc},
684 {N_("Resign F9"), "Resign", ResignProc},
685 {"----", NULL, NothingProc},
686 {N_("Stop Observing F10"), "Stop Observing", StopObservingProc},
687 {N_("Stop Examining F11"), "Stop Examining", StopExaminingProc},
688 {N_("Upload to Examine"), "Upload to Examine", UploadProc},
689 {"----", NULL, NothingProc},
690 {N_("Adjudicate to White"), "Adjudicate to White", AdjuWhiteProc},
691 {N_("Adjudicate to Black"), "Adjudicate to Black", AdjuBlackProc},
692 {N_("Adjudicate Draw"), "Adjudicate Draw", AdjuDrawProc},
696 MenuItem engineMenu[] = {
697 {N_("Engine #1 Settings ..."), "Engine #1 Settings", FirstSettingsProc},
698 {N_("Engine #2 Settings ..."), "Engine #2 Settings", SecondSettingsProc},
699 {"----", NULL, NothingProc},
700 {N_("Hint"), "Hint", HintProc},
701 {N_("Book"), "Book", BookProc},
702 {"----", NULL, NothingProc},
703 {N_("Move Now Ctrl+M"), "Move Now", MoveNowProc},
704 {N_("Retract Move Ctrl+X"), "Retract Move", RetractMoveProc},
708 MenuItem optionsMenu[] = {
709 #define OPTIONSDIALOG
711 {N_("General ..."), "General", OptionsProc},
713 {N_("Time Control ... Alt+Shift+T"), "Time Control", TimeControlProc},
714 {N_("Common Engine ... Alt+Shift+U"), "Common Engine", UciMenuProc},
715 {N_("Adjudications ... Alt+Shift+J"), "Adjudications", EngineMenuProc},
716 {N_("ICS ..."), "ICS", IcsOptionsProc},
717 {N_("Match ..."), "Match", MatchOptionsProc},
718 {N_("Load Game ..."), "Load Game", LoadOptionsProc},
719 {N_("Save Game ..."), "Save Game", SaveOptionsProc},
720 // {N_(" ..."), "", OptionsProc},
721 {N_("Game List ..."), "Game List", GameListOptionsPopUp},
722 {N_("Sounds ..."), "Sounds", SoundOptionsProc},
723 {"----", NULL, NothingProc},
724 #ifndef OPTIONSDIALOG
725 {N_("Always Queen Ctrl+Shift+Q"), "Always Queen", AlwaysQueenProc},
726 {N_("Animate Dragging"), "Animate Dragging", AnimateDraggingProc},
727 {N_("Animate Moving Ctrl+Shift+A"), "Animate Moving", AnimateMovingProc},
728 {N_("Auto Flag Ctrl+Shift+F"), "Auto Flag", AutoflagProc},
729 {N_("Auto Flip View"), "Auto Flip View", AutoflipProc},
730 {N_("Blindfold"), "Blindfold", BlindfoldProc},
731 {N_("Flash Moves"), "Flash Moves", FlashMovesProc},
733 {N_("Highlight Dragging"), "Highlight Dragging", HighlightDraggingProc},
735 {N_("Highlight Last Move"), "Highlight Last Move", HighlightLastMoveProc},
736 {N_("Highlight With Arrow"), "Arrow", HighlightArrowProc},
737 {N_("Move Sound"), "Move Sound", MoveSoundProc},
738 // {N_("ICS Alarm"), "ICS Alarm", IcsAlarmProc},
739 {N_("One-Click Moving"), "OneClick", OneClickProc},
740 {N_("Periodic Updates"), "Periodic Updates", PeriodicUpdatesProc},
741 {N_("Ponder Next Move Ctrl+Shift+P"), "Ponder Next Move", PonderNextMoveProc},
742 {N_("Popup Exit Message"), "Popup Exit Message", PopupExitMessageProc},
743 {N_("Popup Move Errors"), "Popup Move Errors", PopupMoveErrorsProc},
744 // {N_("Premove"), "Premove", PremoveProc},
745 {N_("Show Coords"), "Show Coords", ShowCoordsProc},
746 {N_("Hide Thinking Ctrl+Shift+H"), "Hide Thinking", HideThinkingProc},
747 {N_("Test Legality Ctrl+Shift+L"), "Test Legality", TestLegalityProc},
748 {"----", NULL, NothingProc},
750 {N_("Save Settings Now"), "Save Settings Now", SaveSettingsProc},
751 {N_("Save Settings on Exit"), "Save Settings on Exit", SaveOnExitProc},
755 MenuItem helpMenu[] = {
756 {N_("Info XBoard"), "Info XBoard", InfoProc},
757 {N_("Man XBoard F1"), "Man XBoard", ManProc},
758 {"----", NULL, NothingProc},
759 {N_("About XBoard"), "About XBoard", AboutProc},
764 {N_("File"), "File", fileMenu},
765 {N_("Edit"), "Edit", editMenu},
766 {N_("View"), "View", viewMenu},
767 {N_("Mode"), "Mode", modeMenu},
768 {N_("Action"), "Action", actionMenu},
769 {N_("Engine"), "Engine", engineMenu},
770 {N_("Options"), "Options", optionsMenu},
771 {N_("Help"), "Help", helpMenu},
775 #define PAUSE_BUTTON "P"
776 MenuItem buttonBar[] = {
777 {"<<", "<<", ToStartProc},
778 {"<", "<", BackwardProc},
779 {PAUSE_BUTTON, PAUSE_BUTTON, PauseProc},
780 {">", ">", ForwardProc},
781 {">>", ">>", ToEndProc},
785 #define PIECE_MENU_SIZE 18
786 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
787 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
788 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
789 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
790 N_("Empty square"), N_("Clear board") },
791 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
792 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
793 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
794 N_("Empty square"), N_("Clear board") }
796 /* must be in same order as PieceMenuStrings! */
797 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
798 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
799 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
800 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
801 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
802 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
803 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
804 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
805 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
808 #define DROP_MENU_SIZE 6
809 String dropMenuStrings[DROP_MENU_SIZE] = {
810 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
812 /* must be in same order as PieceMenuStrings! */
813 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
814 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
815 WhiteRook, WhiteQueen
823 DropMenuEnables dmEnables[] = {
841 { XtNborderWidth, 0 },
842 { XtNdefaultDistance, 0 },
846 { XtNborderWidth, 0 },
847 { XtNresizable, (XtArgVal) True },
851 { XtNborderWidth, 0 },
857 { XtNjustify, (XtArgVal) XtJustifyRight },
858 { XtNlabel, (XtArgVal) "..." },
859 { XtNresizable, (XtArgVal) True },
860 { XtNresize, (XtArgVal) False }
863 Arg messageArgs[] = {
864 { XtNjustify, (XtArgVal) XtJustifyLeft },
865 { XtNlabel, (XtArgVal) "..." },
866 { XtNresizable, (XtArgVal) True },
867 { XtNresize, (XtArgVal) False }
871 { XtNborderWidth, 0 },
872 { XtNjustify, (XtArgVal) XtJustifyLeft }
875 XtResource clientResources[] = {
876 { "flashCount", "flashCount", XtRInt, sizeof(int),
877 XtOffset(AppDataPtr, flashCount), XtRImmediate,
878 (XtPointer) FLASH_COUNT },
881 XrmOptionDescRec shellOptions[] = {
882 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
883 { "-flash", "flashCount", XrmoptionNoArg, "3" },
884 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
887 XtActionsRec boardActions[] = {
888 { "DrawPosition", DrawPositionProc },
889 { "HandleUserMove", HandleUserMove },
890 { "AnimateUserMove", AnimateUserMove },
891 { "HandlePV", HandlePV },
892 { "SelectPV", SelectPV },
893 { "StopPV", StopPV },
894 { "FileNameAction", FileNameAction },
895 { "AskQuestionProc", AskQuestionProc },
896 { "AskQuestionReplyAction", AskQuestionReplyAction },
897 { "PieceMenuPopup", PieceMenuPopup },
898 { "WhiteClock", WhiteClock },
899 { "BlackClock", BlackClock },
900 { "Iconify", Iconify },
901 { "ResetProc", ResetProc },
902 { "NewVariantProc", NewVariantProc },
903 { "LoadGameProc", LoadGameProc },
904 { "LoadNextGameProc", LoadNextGameProc },
905 { "LoadPrevGameProc", LoadPrevGameProc },
906 { "LoadSelectedProc", LoadSelectedProc },
907 { "SetFilterProc", SetFilterProc },
908 { "ReloadGameProc", ReloadGameProc },
909 { "LoadPositionProc", LoadPositionProc },
910 { "LoadNextPositionProc", LoadNextPositionProc },
911 { "LoadPrevPositionProc", LoadPrevPositionProc },
912 { "ReloadPositionProc", ReloadPositionProc },
913 { "CopyPositionProc", CopyPositionProc },
914 { "PastePositionProc", PastePositionProc },
915 { "CopyGameProc", CopyGameProc },
916 { "PasteGameProc", PasteGameProc },
917 { "SaveGameProc", SaveGameProc },
918 { "SavePositionProc", SavePositionProc },
919 { "MailMoveProc", MailMoveProc },
920 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
921 { "QuitProc", QuitProc },
922 { "MachineWhiteProc", MachineWhiteProc },
923 { "MachineBlackProc", MachineBlackProc },
924 { "AnalysisModeProc", AnalyzeModeProc },
925 { "AnalyzeFileProc", AnalyzeFileProc },
926 { "TwoMachinesProc", TwoMachinesProc },
927 { "IcsClientProc", IcsClientProc },
928 { "EditGameProc", EditGameProc },
929 { "EditPositionProc", EditPositionProc },
930 { "TrainingProc", EditPositionProc },
931 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
932 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
933 { "ShowGameListProc", ShowGameListProc },
934 { "ShowMoveListProc", HistoryShowProc},
935 { "EditTagsProc", EditCommentProc },
936 { "EditCommentProc", EditCommentProc },
937 { "IcsInputBoxProc", IcsInputBoxProc },
938 { "PauseProc", PauseProc },
939 { "AcceptProc", AcceptProc },
940 { "DeclineProc", DeclineProc },
941 { "RematchProc", RematchProc },
942 { "CallFlagProc", CallFlagProc },
943 { "DrawProc", DrawProc },
944 { "AdjournProc", AdjournProc },
945 { "AbortProc", AbortProc },
946 { "ResignProc", ResignProc },
947 { "AdjuWhiteProc", AdjuWhiteProc },
948 { "AdjuBlackProc", AdjuBlackProc },
949 { "AdjuDrawProc", AdjuDrawProc },
950 { "EnterKeyProc", EnterKeyProc },
951 { "UpKeyProc", UpKeyProc },
952 { "DownKeyProc", DownKeyProc },
953 { "StopObservingProc", StopObservingProc },
954 { "StopExaminingProc", StopExaminingProc },
955 { "UploadProc", UploadProc },
956 { "BackwardProc", BackwardProc },
957 { "ForwardProc", ForwardProc },
958 { "ToStartProc", ToStartProc },
959 { "ToEndProc", ToEndProc },
960 { "RevertProc", RevertProc },
961 { "AnnotateProc", AnnotateProc },
962 { "TruncateGameProc", TruncateGameProc },
963 { "MoveNowProc", MoveNowProc },
964 { "RetractMoveProc", RetractMoveProc },
965 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
966 { "UciMenuProc", (XtActionProc) UciMenuProc },
967 { "TimeControlProc", (XtActionProc) TimeControlProc },
968 { "FlipViewProc", FlipViewProc },
969 { "PonderNextMoveProc", PonderNextMoveProc },
970 #ifndef OPTIONSDIALOG
971 { "AlwaysQueenProc", AlwaysQueenProc },
972 { "AnimateDraggingProc", AnimateDraggingProc },
973 { "AnimateMovingProc", AnimateMovingProc },
974 { "AutoflagProc", AutoflagProc },
975 { "AutoflipProc", AutoflipProc },
976 { "BlindfoldProc", BlindfoldProc },
977 { "FlashMovesProc", FlashMovesProc },
979 { "HighlightDraggingProc", HighlightDraggingProc },
981 { "HighlightLastMoveProc", HighlightLastMoveProc },
982 // { "IcsAlarmProc", IcsAlarmProc },
983 { "MoveSoundProc", MoveSoundProc },
984 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
985 { "PopupExitMessageProc", PopupExitMessageProc },
986 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
987 // { "PremoveProc", PremoveProc },
988 { "ShowCoordsProc", ShowCoordsProc },
989 { "ShowThinkingProc", ShowThinkingProc },
990 { "HideThinkingProc", HideThinkingProc },
991 { "TestLegalityProc", TestLegalityProc },
993 { "SaveSettingsProc", SaveSettingsProc },
994 { "SaveOnExitProc", SaveOnExitProc },
995 { "InfoProc", InfoProc },
996 { "ManProc", ManProc },
997 { "HintProc", HintProc },
998 { "BookProc", BookProc },
999 { "AboutGameProc", AboutGameProc },
1000 { "AboutProc", AboutProc },
1001 { "DebugProc", DebugProc },
1002 { "NothingProc", NothingProc },
1003 { "CommentClick", (XtActionProc) CommentClick },
1004 { "CommentPopDown", (XtActionProc) CommentPopDown },
1005 { "TagsPopDown", (XtActionProc) TagsPopDown },
1006 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
1007 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
1008 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
1009 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
1010 { "GameListPopDown", (XtActionProc) GameListPopDown },
1011 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
1012 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1013 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
1014 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1015 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1016 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
1017 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
1018 { "GenericPopDown", (XtActionProc) GenericPopDown },
1019 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1022 char globalTranslations[] =
1023 ":<Key>F9: ResignProc() \n \
1024 :Ctrl<Key>n: ResetProc() \n \
1025 :Meta<Key>V: NewVariantProc() \n \
1026 :Ctrl<Key>o: LoadGameProc() \n \
1027 :Meta<Key>Next: LoadNextGameProc() \n \
1028 :Meta<Key>Prior: LoadPrevGameProc() \n \
1029 :Ctrl<Key>s: SaveGameProc() \n \
1030 :Ctrl<Key>c: CopyGameProc() \n \
1031 :Ctrl<Key>v: PasteGameProc() \n \
1032 :Ctrl<Key>O: LoadPositionProc() \n \
1033 :Shift<Key>Next: LoadNextPositionProc() \n \
1034 :Shift<Key>Prior: LoadPrevPositionProc() \n \
1035 :Ctrl<Key>S: SavePositionProc() \n \
1036 :Ctrl<Key>C: CopyPositionProc() \n \
1037 :Ctrl<Key>V: PastePositionProc() \n \
1038 :Ctrl<Key>q: QuitProc() \n \
1039 :Ctrl<Key>w: MachineWhiteProc() \n \
1040 :Ctrl<Key>b: MachineBlackProc() \n \
1041 :Ctrl<Key>t: TwoMachinesProc() \n \
1042 :Ctrl<Key>a: AnalysisModeProc() \n \
1043 :Ctrl<Key>f: AnalyzeFileProc() \n \
1044 :Ctrl<Key>e: EditGameProc() \n \
1045 :Ctrl<Key>E: EditPositionProc() \n \
1046 :Meta<Key>O: EngineOutputProc() \n \
1047 :Meta<Key>E: EvalGraphProc() \n \
1048 :Meta<Key>G: ShowGameListProc() \n \
1049 :Meta<Key>H: ShowMoveListProc() \n \
1050 :<Key>Pause: PauseProc() \n \
1051 :<Key>F3: AcceptProc() \n \
1052 :<Key>F4: DeclineProc() \n \
1053 :<Key>F12: RematchProc() \n \
1054 :<Key>F5: CallFlagProc() \n \
1055 :<Key>F6: DrawProc() \n \
1056 :<Key>F7: AdjournProc() \n \
1057 :<Key>F8: AbortProc() \n \
1058 :<Key>F10: StopObservingProc() \n \
1059 :<Key>F11: StopExaminingProc() \n \
1060 :Meta Ctrl<Key>F12: DebugProc() \n \
1061 :Meta<Key>End: ToEndProc() \n \
1062 :Meta<Key>Right: ForwardProc() \n \
1063 :Meta<Key>Home: ToStartProc() \n \
1064 :Meta<Key>Left: BackwardProc() \n \
1065 :<Key>Home: RevertProc() \n \
1066 :<Key>End: TruncateGameProc() \n \
1067 :Ctrl<Key>m: MoveNowProc() \n \
1068 :Ctrl<Key>x: RetractMoveProc() \n \
1069 :Meta<Key>J: EngineMenuProc() \n \
1070 :Meta<Key>U: UciMenuProc() \n \
1071 :Meta<Key>T: TimeControlProc() \n \
1072 :Ctrl<Key>P: PonderNextMoveProc() \n "
1073 #ifndef OPTIONSDIALOG
1075 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1076 :Ctrl<Key>F: AutoflagProc() \n \
1077 :Ctrl<Key>A: AnimateMovingProc() \n \
1078 :Ctrl<Key>L: TestLegalityProc() \n \
1079 :Ctrl<Key>H: HideThinkingProc() \n "
1082 :<Key>-: Iconify() \n \
1083 :<Key>F1: ManProc() \n \
1084 :<Key>F2: FlipViewProc() \n \
1085 <KeyDown>.: BackwardProc() \n \
1086 <KeyUp>.: ForwardProc() \n \
1087 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1088 \"Send to chess program:\",,1) \n \
1089 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1090 \"Send to second chess program:\",,2) \n";
1092 char boardTranslations[] =
1093 "<Btn1Down>: HandleUserMove(0) \n \
1094 Shift<Btn1Up>: HandleUserMove(1) \n \
1095 <Btn1Up>: HandleUserMove(0) \n \
1096 <Btn1Motion>: AnimateUserMove() \n \
1097 <Btn3Motion>: HandlePV() \n \
1098 <Btn3Up>: PieceMenuPopup(menuB) \n \
1099 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1100 PieceMenuPopup(menuB) \n \
1101 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1102 PieceMenuPopup(menuW) \n \
1103 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1104 PieceMenuPopup(menuW) \n \
1105 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1106 PieceMenuPopup(menuB) \n";
1108 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1109 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1111 char ICSInputTranslations[] =
1112 "<Key>Up: UpKeyProc() \n "
1113 "<Key>Down: DownKeyProc() \n "
1114 "<Key>Return: EnterKeyProc() \n";
1116 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1117 // as the widget is destroyed before the up-click can call extend-end
1118 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1120 String xboardResources[] = {
1121 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1122 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1123 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1128 /* Max possible square size */
1129 #define MAXSQSIZE 256
1131 static int xpm_avail[MAXSQSIZE];
1133 #ifdef HAVE_DIR_STRUCT
1135 /* Extract piece size from filename */
1137 xpm_getsize(name, len, ext)
1148 if ((p=strchr(name, '.')) == NULL ||
1149 StrCaseCmp(p+1, ext) != 0)
1155 while (*p && isdigit(*p))
1162 /* Setup xpm_avail */
1164 xpm_getavail(dirname, ext)
1172 for (i=0; i<MAXSQSIZE; ++i)
1175 if (appData.debugMode)
1176 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1178 dir = opendir(dirname);
1181 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1182 programName, dirname);
1186 while ((ent=readdir(dir)) != NULL) {
1187 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1188 if (i > 0 && i < MAXSQSIZE)
1198 xpm_print_avail(fp, ext)
1204 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1205 for (i=1; i<MAXSQSIZE; ++i) {
1211 /* Return XPM piecesize closest to size */
1213 xpm_closest_to(dirname, size, ext)
1219 int sm_diff = MAXSQSIZE;
1223 xpm_getavail(dirname, ext);
1225 if (appData.debugMode)
1226 xpm_print_avail(stderr, ext);
1228 for (i=1; i<MAXSQSIZE; ++i) {
1231 diff = (diff<0) ? -diff : diff;
1232 if (diff < sm_diff) {
1240 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1246 #else /* !HAVE_DIR_STRUCT */
1247 /* If we are on a system without a DIR struct, we can't
1248 read the directory, so we can't collect a list of
1249 filenames, etc., so we can't do any size-fitting. */
1251 xpm_closest_to(dirname, size, ext)
1256 fprintf(stderr, _("\
1257 Warning: No DIR structure found on this system --\n\
1258 Unable to autosize for XPM/XIM pieces.\n\
1259 Please report this error to frankm@hiwaay.net.\n\
1260 Include system type & operating system in message.\n"));
1263 #endif /* HAVE_DIR_STRUCT */
1265 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1266 "magenta", "cyan", "white" };
1270 TextColors textColors[(int)NColorClasses];
1272 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1274 parse_color(str, which)
1278 char *p, buf[100], *d;
1281 if (strlen(str) > 99) /* watch bounds on buf */
1286 for (i=0; i<which; ++i) {
1293 /* Could be looking at something like:
1295 .. in which case we want to stop on a comma also */
1296 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1300 return -1; /* Use default for empty field */
1303 if (which == 2 || isdigit(*p))
1306 while (*p && isalpha(*p))
1311 for (i=0; i<8; ++i) {
1312 if (!StrCaseCmp(buf, cnames[i]))
1313 return which? (i+40) : (i+30);
1315 if (!StrCaseCmp(buf, "default")) return -1;
1317 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1322 parse_cpair(cc, str)
1326 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1327 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1332 /* bg and attr are optional */
1333 textColors[(int)cc].bg = parse_color(str, 1);
1334 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1335 textColors[(int)cc].attr = 0;
1341 /* Arrange to catch delete-window events */
1342 Atom wm_delete_window;
1344 CatchDeleteWindow(Widget w, String procname)
1347 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1348 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1349 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1356 XtSetArg(args[0], XtNiconic, False);
1357 XtSetValues(shellWidget, args, 1);
1359 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1362 //---------------------------------------------------------------------------------------------------------
1363 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1366 #define CW_USEDEFAULT (1<<31)
1367 #define ICS_TEXT_MENU_SIZE 90
1368 #define DEBUG_FILE "xboard.debug"
1369 #define SetCurrentDirectory chdir
1370 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1374 // these two must some day move to frontend.h, when they are implemented
1375 Boolean GameListIsUp();
1377 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1380 // front-end part of option handling
1382 // [HGM] This platform-dependent table provides the location for storing the color info
1383 extern char *crWhite, * crBlack;
1387 &appData.whitePieceColor,
1388 &appData.blackPieceColor,
1389 &appData.lightSquareColor,
1390 &appData.darkSquareColor,
1391 &appData.highlightSquareColor,
1392 &appData.premoveHighlightColor,
1393 &appData.lowTimeWarningColor,
1404 // [HGM] font: keep a font for each square size, even non-stndard ones
1405 #define NUM_SIZES 18
1406 #define MAX_SIZE 130
1407 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1408 char *fontTable[NUM_FONTS][MAX_SIZE];
1411 ParseFont(char *name, int number)
1412 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1414 if(sscanf(name, "size%d:", &size)) {
1415 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1416 // defer processing it until we know if it matches our board size
1417 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1418 fontTable[number][size] = strdup(strchr(name, ':')+1);
1419 fontValid[number][size] = True;
1424 case 0: // CLOCK_FONT
1425 appData.clockFont = strdup(name);
1427 case 1: // MESSAGE_FONT
1428 appData.font = strdup(name);
1430 case 2: // COORD_FONT
1431 appData.coordFont = strdup(name);
1436 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1441 { // only 2 fonts currently
1442 appData.clockFont = CLOCK_FONT_NAME;
1443 appData.coordFont = COORD_FONT_NAME;
1444 appData.font = DEFAULT_FONT_NAME;
1449 { // no-op, until we identify the code for this already in XBoard and move it here
1453 ParseColor(int n, char *name)
1454 { // in XBoard, just copy the color-name string
1455 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1459 ParseTextAttribs(ColorClass cc, char *s)
1461 (&appData.colorShout)[cc] = strdup(s);
1465 ParseBoardSize(void *addr, char *name)
1467 appData.boardSize = strdup(name);
1472 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1476 SetCommPortDefaults()
1477 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1480 // [HGM] args: these three cases taken out to stay in front-end
1482 SaveFontArg(FILE *f, ArgDescriptor *ad)
1485 int i, n = (int)(intptr_t)ad->argLoc;
1487 case 0: // CLOCK_FONT
1488 name = appData.clockFont;
1490 case 1: // MESSAGE_FONT
1491 name = appData.font;
1493 case 2: // COORD_FONT
1494 name = appData.coordFont;
1499 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1500 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1501 fontTable[n][squareSize] = strdup(name);
1502 fontValid[n][squareSize] = True;
1505 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1506 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1511 { // nothing to do, as the sounds are at all times represented by their text-string names already
1515 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1516 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1517 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
1521 SaveColor(FILE *f, ArgDescriptor *ad)
1522 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1523 if(colorVariable[(int)(intptr_t)ad->argLoc])
1524 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
1528 SaveBoardSize(FILE *f, char *name, void *addr)
1529 { // wrapper to shield back-end from BoardSize & sizeInfo
1530 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1534 ParseCommPortSettings(char *s)
1535 { // no such option in XBoard (yet)
1538 extern Widget engineOutputShell;
1541 GetActualPlacement(Widget wg, WindowPlacement *wp)
1551 XtSetArg(args[i], XtNx, &x); i++;
1552 XtSetArg(args[i], XtNy, &y); i++;
1553 XtSetArg(args[i], XtNwidth, &w); i++;
1554 XtSetArg(args[i], XtNheight, &h); i++;
1555 XtGetValues(wg, args, i);
1564 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1565 // In XBoard this will have to wait until awareness of window parameters is implemented
1566 GetActualPlacement(shellWidget, &wpMain);
1567 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1568 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1569 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1570 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1571 if(shellUp[1]) GetActualPlacement(shells[1], &wpComment);
1572 if(shellUp[2]) GetActualPlacement(shells[2], &wpTags);
1576 PrintCommPortSettings(FILE *f, char *name)
1577 { // This option does not exist in XBoard
1581 MySearchPath(char *installDir, char *name, char *fullname)
1582 { // just append installDir and name. Perhaps ExpandPath should be used here?
1583 name = ExpandPathName(name);
1584 if(name && name[0] == '/')
1585 safeStrCpy(fullname, name, MSG_SIZ );
1587 sprintf(fullname, "%s%c%s", installDir, '/', name);
1593 MyGetFullPathName(char *name, char *fullname)
1594 { // should use ExpandPath?
1595 name = ExpandPathName(name);
1596 safeStrCpy(fullname, name, MSG_SIZ );
1601 EnsureOnScreen(int *x, int *y, int minX, int minY)
1608 { // [HGM] args: allows testing if main window is realized from back-end
1609 return xBoardWindow != 0;
1613 PopUpStartupDialog()
1614 { // start menu not implemented in XBoard
1618 ConvertToLine(int argc, char **argv)
1620 static char line[128*1024], buf[1024];
1624 for(i=1; i<argc; i++)
1626 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1627 && argv[i][0] != '{' )
1628 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1630 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1631 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1634 line[strlen(line)-1] = NULLCHAR;
1638 //--------------------------------------------------------------------------------------------
1640 extern Boolean twoBoards, partnerUp;
1643 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1645 #define BoardSize int
1646 void InitDrawingSizes(BoardSize boardSize, int flags)
1647 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1648 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1650 XtGeometryResult gres;
1653 if(!formWidget) return;
1656 * Enable shell resizing.
1658 shellArgs[0].value = (XtArgVal) &w;
1659 shellArgs[1].value = (XtArgVal) &h;
1660 XtGetValues(shellWidget, shellArgs, 2);
1662 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1663 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1664 XtSetValues(shellWidget, &shellArgs[2], 4);
1666 XtSetArg(args[0], XtNdefaultDistance, &sep);
1667 XtGetValues(formWidget, args, 1);
1669 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1670 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1671 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1673 hOffset = boardWidth + 10;
1674 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1675 secondSegments[i] = gridSegments[i];
1676 secondSegments[i].x1 += hOffset;
1677 secondSegments[i].x2 += hOffset;
1680 XtSetArg(args[0], XtNwidth, boardWidth);
1681 XtSetArg(args[1], XtNheight, boardHeight);
1682 XtSetValues(boardWidget, args, 2);
1684 timerWidth = (boardWidth - sep) / 2;
1685 XtSetArg(args[0], XtNwidth, timerWidth);
1686 XtSetValues(whiteTimerWidget, args, 1);
1687 XtSetValues(blackTimerWidget, args, 1);
1689 XawFormDoLayout(formWidget, False);
1691 if (appData.titleInWindow) {
1693 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1694 XtSetArg(args[i], XtNheight, &h); i++;
1695 XtGetValues(titleWidget, args, i);
1697 w = boardWidth - 2*bor;
1699 XtSetArg(args[0], XtNwidth, &w);
1700 XtGetValues(menuBarWidget, args, 1);
1701 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1704 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1705 if (gres != XtGeometryYes && appData.debugMode) {
1707 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1708 programName, gres, w, h, wr, hr);
1712 XawFormDoLayout(formWidget, True);
1715 * Inhibit shell resizing.
1717 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1718 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1719 shellArgs[4].value = shellArgs[2].value = w;
1720 shellArgs[5].value = shellArgs[3].value = h;
1721 XtSetValues(shellWidget, &shellArgs[0], 6);
1723 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1726 for(i=0; i<4; i++) {
1728 for(p=0; p<=(int)WhiteKing; p++)
1729 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1730 if(gameInfo.variant == VariantShogi) {
1731 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1732 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1733 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1734 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1735 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1738 if(gameInfo.variant == VariantGothic) {
1739 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1742 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1743 xpmPieceBitmap[i][(int)WhiteAngel] = xpmPieceBitmap2[i][(int)WhiteFalcon];
1744 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1747 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1748 for(p=0; p<=(int)WhiteKing; p++)
1749 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1750 if(gameInfo.variant == VariantShogi) {
1751 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1752 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1753 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1754 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1755 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1758 if(gameInfo.variant == VariantGothic) {
1759 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1762 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1763 ximMaskPm[(int)WhiteAngel] = ximMaskPm2[(int)WhiteFalcon];
1764 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1769 for(i=0; i<2; i++) {
1771 for(p=0; p<=(int)WhiteKing; p++)
1772 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1773 if(gameInfo.variant == VariantShogi) {
1774 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1775 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1776 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1777 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1778 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1781 if(gameInfo.variant == VariantGothic) {
1782 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1785 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1786 pieceBitmap[i][(int)WhiteAngel] = pieceBitmap2[i][(int)WhiteFalcon];
1787 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1797 void ParseIcsTextColors()
1798 { // [HGM] tken out of main(), so it can be called from ICS-Options dialog
1799 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1800 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1801 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1802 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1803 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1804 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1805 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1806 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1807 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1808 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1810 if (appData.colorize) {
1812 _("%s: can't parse color names; disabling colorization\n"),
1815 appData.colorize = FALSE;
1820 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
1821 XrmValue vFrom, vTo;
1822 int forceMono = False;
1824 if (!appData.monoMode) {
1825 vFrom.addr = (caddr_t) appData.lightSquareColor;
1826 vFrom.size = strlen(appData.lightSquareColor);
1827 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1828 if (vTo.addr == NULL) {
1829 appData.monoMode = True;
1832 lightSquareColor = *(Pixel *) vTo.addr;
1835 if (!appData.monoMode) {
1836 vFrom.addr = (caddr_t) appData.darkSquareColor;
1837 vFrom.size = strlen(appData.darkSquareColor);
1838 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1839 if (vTo.addr == NULL) {
1840 appData.monoMode = True;
1843 darkSquareColor = *(Pixel *) vTo.addr;
1846 if (!appData.monoMode) {
1847 vFrom.addr = (caddr_t) appData.whitePieceColor;
1848 vFrom.size = strlen(appData.whitePieceColor);
1849 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1850 if (vTo.addr == NULL) {
1851 appData.monoMode = True;
1854 whitePieceColor = *(Pixel *) vTo.addr;
1857 if (!appData.monoMode) {
1858 vFrom.addr = (caddr_t) appData.blackPieceColor;
1859 vFrom.size = strlen(appData.blackPieceColor);
1860 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1861 if (vTo.addr == NULL) {
1862 appData.monoMode = True;
1865 blackPieceColor = *(Pixel *) vTo.addr;
1869 if (!appData.monoMode) {
1870 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1871 vFrom.size = strlen(appData.highlightSquareColor);
1872 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1873 if (vTo.addr == NULL) {
1874 appData.monoMode = True;
1877 highlightSquareColor = *(Pixel *) vTo.addr;
1881 if (!appData.monoMode) {
1882 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1883 vFrom.size = strlen(appData.premoveHighlightColor);
1884 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1885 if (vTo.addr == NULL) {
1886 appData.monoMode = True;
1889 premoveHighlightColor = *(Pixel *) vTo.addr;
1900 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1901 XSetWindowAttributes window_attributes;
1903 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1904 XrmValue vFrom, vTo;
1905 XtGeometryResult gres;
1908 int forceMono = False;
1910 srandom(time(0)); // [HGM] book: make random truly random
1912 setbuf(stdout, NULL);
1913 setbuf(stderr, NULL);
1916 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1917 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1921 programName = strrchr(argv[0], '/');
1922 if (programName == NULL)
1923 programName = argv[0];
1928 XtSetLanguageProc(NULL, NULL, NULL);
1929 bindtextdomain(PACKAGE, LOCALEDIR);
1930 textdomain(PACKAGE);
1934 XtAppInitialize(&appContext, "XBoard", shellOptions,
1935 XtNumber(shellOptions),
1936 &argc, argv, xboardResources, NULL, 0);
1937 appData.boardSize = "";
1938 InitAppData(ConvertToLine(argc, argv));
1940 if (p == NULL) p = "/tmp";
1941 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1942 gameCopyFilename = (char*) malloc(i);
1943 gamePasteFilename = (char*) malloc(i);
1944 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1945 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1947 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1948 clientResources, XtNumber(clientResources),
1951 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1952 static char buf[MSG_SIZ];
1953 EscapeExpand(buf, appData.initString);
1954 appData.initString = strdup(buf);
1955 EscapeExpand(buf, appData.secondInitString);
1956 appData.secondInitString = strdup(buf);
1957 EscapeExpand(buf, appData.firstComputerString);
1958 appData.firstComputerString = strdup(buf);
1959 EscapeExpand(buf, appData.secondComputerString);
1960 appData.secondComputerString = strdup(buf);
1963 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1966 if (chdir(chessDir) != 0) {
1967 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1973 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1974 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1975 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1976 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1979 setbuf(debugFP, NULL);
1982 /* [HGM,HR] make sure board size is acceptable */
1983 if(appData.NrFiles > BOARD_FILES ||
1984 appData.NrRanks > BOARD_RANKS )
1985 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1988 /* This feature does not work; animation needs a rewrite */
1989 appData.highlightDragging = FALSE;
1993 xDisplay = XtDisplay(shellWidget);
1994 xScreen = DefaultScreen(xDisplay);
1995 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1997 gameInfo.variant = StringToVariant(appData.variant);
1998 InitPosition(FALSE);
2001 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
2003 if (isdigit(appData.boardSize[0])) {
2004 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
2005 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
2006 &fontPxlSize, &smallLayout, &tinyLayout);
2008 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
2009 programName, appData.boardSize);
2013 /* Find some defaults; use the nearest known size */
2014 SizeDefaults *szd, *nearest;
2015 int distance = 99999;
2016 nearest = szd = sizeDefaults;
2017 while (szd->name != NULL) {
2018 if (abs(szd->squareSize - squareSize) < distance) {
2020 distance = abs(szd->squareSize - squareSize);
2021 if (distance == 0) break;
2025 if (i < 2) lineGap = nearest->lineGap;
2026 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
2027 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
2028 if (i < 5) fontPxlSize = nearest->fontPxlSize;
2029 if (i < 6) smallLayout = nearest->smallLayout;
2030 if (i < 7) tinyLayout = nearest->tinyLayout;
2033 SizeDefaults *szd = sizeDefaults;
2034 if (*appData.boardSize == NULLCHAR) {
2035 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
2036 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
2039 if (szd->name == NULL) szd--;
2040 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
2042 while (szd->name != NULL &&
2043 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
2044 if (szd->name == NULL) {
2045 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
2046 programName, appData.boardSize);
2050 squareSize = szd->squareSize;
2051 lineGap = szd->lineGap;
2052 clockFontPxlSize = szd->clockFontPxlSize;
2053 coordFontPxlSize = szd->coordFontPxlSize;
2054 fontPxlSize = szd->fontPxlSize;
2055 smallLayout = szd->smallLayout;
2056 tinyLayout = szd->tinyLayout;
2057 // [HGM] font: use defaults from settings file if available and not overruled
2059 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
2060 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
2061 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
2062 appData.font = fontTable[MESSAGE_FONT][squareSize];
2063 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
2064 appData.coordFont = fontTable[COORD_FONT][squareSize];
2066 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
2067 if (strlen(appData.pixmapDirectory) > 0) {
2068 p = ExpandPathName(appData.pixmapDirectory);
2070 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
2071 appData.pixmapDirectory);
2074 if (appData.debugMode) {
2075 fprintf(stderr, _("\
2076 XBoard square size (hint): %d\n\
2077 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
2079 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
2080 if (appData.debugMode) {
2081 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
2084 defaultLineGap = lineGap;
2085 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
2087 /* [HR] height treated separately (hacked) */
2088 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
2089 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
2090 if (appData.showJail == 1) {
2091 /* Jail on top and bottom */
2092 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2093 XtSetArg(boardArgs[2], XtNheight,
2094 boardHeight + 2*(lineGap + squareSize));
2095 } else if (appData.showJail == 2) {
2097 XtSetArg(boardArgs[1], XtNwidth,
2098 boardWidth + 2*(lineGap + squareSize));
2099 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2102 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2103 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2107 * Determine what fonts to use.
2109 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2110 clockFontID = XLoadFont(xDisplay, appData.clockFont);
2111 clockFontStruct = XQueryFont(xDisplay, clockFontID);
2112 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2113 coordFontID = XLoadFont(xDisplay, appData.coordFont);
2114 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2115 appData.font = FindFont(appData.font, fontPxlSize);
2116 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
2117 countFontStruct = XQueryFont(xDisplay, countFontID);
2118 // appData.font = FindFont(appData.font, fontPxlSize);
2120 xdb = XtDatabase(xDisplay);
2121 XrmPutStringResource(&xdb, "*font", appData.font);
2124 * Detect if there are not enough colors available and adapt.
2126 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2127 appData.monoMode = True;
2130 forceMono = MakeColors();
2133 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2136 if (appData.bitmapDirectory == NULL ||
2137 appData.bitmapDirectory[0] == NULLCHAR)
2138 appData.bitmapDirectory = DEF_BITMAP_DIR;
2141 if (appData.lowTimeWarning && !appData.monoMode) {
2142 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2143 vFrom.size = strlen(appData.lowTimeWarningColor);
2144 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2145 if (vTo.addr == NULL)
2146 appData.monoMode = True;
2148 lowTimeWarningColor = *(Pixel *) vTo.addr;
2151 if (appData.monoMode && appData.debugMode) {
2152 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2153 (unsigned long) XWhitePixel(xDisplay, xScreen),
2154 (unsigned long) XBlackPixel(xDisplay, xScreen));
2157 ParseIcsTextColors();
2158 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2159 textColors[ColorNone].attr = 0;
2161 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2167 layoutName = "tinyLayout";
2168 } else if (smallLayout) {
2169 layoutName = "smallLayout";
2171 layoutName = "normalLayout";
2173 /* Outer layoutWidget is there only to provide a name for use in
2174 resources that depend on the layout style */
2176 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2177 layoutArgs, XtNumber(layoutArgs));
2179 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2180 formArgs, XtNumber(formArgs));
2181 XtSetArg(args[0], XtNdefaultDistance, &sep);
2182 XtGetValues(formWidget, args, 1);
2185 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2186 XtSetArg(args[0], XtNtop, XtChainTop);
2187 XtSetArg(args[1], XtNbottom, XtChainTop);
2188 XtSetArg(args[2], XtNright, XtChainLeft);
2189 XtSetValues(menuBarWidget, args, 3);
2191 widgetList[j++] = whiteTimerWidget =
2192 XtCreateWidget("whiteTime", labelWidgetClass,
2193 formWidget, timerArgs, XtNumber(timerArgs));
2194 XtSetArg(args[0], XtNfont, clockFontStruct);
2195 XtSetArg(args[1], XtNtop, XtChainTop);
2196 XtSetArg(args[2], XtNbottom, XtChainTop);
2197 XtSetValues(whiteTimerWidget, args, 3);
2199 widgetList[j++] = blackTimerWidget =
2200 XtCreateWidget("blackTime", labelWidgetClass,
2201 formWidget, timerArgs, XtNumber(timerArgs));
2202 XtSetArg(args[0], XtNfont, clockFontStruct);
2203 XtSetArg(args[1], XtNtop, XtChainTop);
2204 XtSetArg(args[2], XtNbottom, XtChainTop);
2205 XtSetValues(blackTimerWidget, args, 3);
2207 if (appData.titleInWindow) {
2208 widgetList[j++] = titleWidget =
2209 XtCreateWidget("title", labelWidgetClass, formWidget,
2210 titleArgs, XtNumber(titleArgs));
2211 XtSetArg(args[0], XtNtop, XtChainTop);
2212 XtSetArg(args[1], XtNbottom, XtChainTop);
2213 XtSetValues(titleWidget, args, 2);
2216 if (appData.showButtonBar) {
2217 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2218 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2219 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2220 XtSetArg(args[2], XtNtop, XtChainTop);
2221 XtSetArg(args[3], XtNbottom, XtChainTop);
2222 XtSetValues(buttonBarWidget, args, 4);
2225 widgetList[j++] = messageWidget =
2226 XtCreateWidget("message", labelWidgetClass, formWidget,
2227 messageArgs, XtNumber(messageArgs));
2228 XtSetArg(args[0], XtNtop, XtChainTop);
2229 XtSetArg(args[1], XtNbottom, XtChainTop);
2230 XtSetValues(messageWidget, args, 2);
2232 widgetList[j++] = boardWidget =
2233 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2234 XtNumber(boardArgs));
2236 XtManageChildren(widgetList, j);
2238 timerWidth = (boardWidth - sep) / 2;
2239 XtSetArg(args[0], XtNwidth, timerWidth);
2240 XtSetValues(whiteTimerWidget, args, 1);
2241 XtSetValues(blackTimerWidget, args, 1);
2243 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2244 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2245 XtGetValues(whiteTimerWidget, args, 2);
2247 if (appData.showButtonBar) {
2248 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2249 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2250 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2254 * formWidget uses these constraints but they are stored
2258 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2259 XtSetValues(menuBarWidget, args, i);
2260 if (appData.titleInWindow) {
2263 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2264 XtSetValues(whiteTimerWidget, args, i);
2266 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2267 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2268 XtSetValues(blackTimerWidget, args, i);
2270 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2271 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2272 XtSetValues(titleWidget, args, i);
2274 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2275 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2276 XtSetValues(messageWidget, args, i);
2277 if (appData.showButtonBar) {
2279 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2280 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2281 XtSetValues(buttonBarWidget, args, i);
2285 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2286 XtSetValues(whiteTimerWidget, args, i);
2288 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2289 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2290 XtSetValues(blackTimerWidget, args, i);
2292 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2293 XtSetValues(titleWidget, args, i);
2295 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2296 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2297 XtSetValues(messageWidget, args, i);
2298 if (appData.showButtonBar) {
2300 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2301 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2302 XtSetValues(buttonBarWidget, args, i);
2307 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2308 XtSetValues(whiteTimerWidget, args, i);
2310 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2311 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2312 XtSetValues(blackTimerWidget, args, i);
2314 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2315 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2316 XtSetValues(messageWidget, args, i);
2317 if (appData.showButtonBar) {
2319 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2320 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2321 XtSetValues(buttonBarWidget, args, i);
2325 XtSetArg(args[0], XtNfromVert, messageWidget);
2326 XtSetArg(args[1], XtNtop, XtChainTop);
2327 XtSetArg(args[2], XtNbottom, XtChainBottom);
2328 XtSetArg(args[3], XtNleft, XtChainLeft);
2329 XtSetArg(args[4], XtNright, XtChainRight);
2330 XtSetValues(boardWidget, args, 5);
2332 XtRealizeWidget(shellWidget);
2335 XtSetArg(args[0], XtNx, wpMain.x);
2336 XtSetArg(args[1], XtNy, wpMain.y);
2337 XtSetValues(shellWidget, args, 2);
2341 * Correct the width of the message and title widgets.
2342 * It is not known why some systems need the extra fudge term.
2343 * The value "2" is probably larger than needed.
2345 XawFormDoLayout(formWidget, False);
2347 #define WIDTH_FUDGE 2
2349 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2350 XtSetArg(args[i], XtNheight, &h); i++;
2351 XtGetValues(messageWidget, args, i);
2352 if (appData.showButtonBar) {
2354 XtSetArg(args[i], XtNwidth, &w); i++;
2355 XtGetValues(buttonBarWidget, args, i);
2356 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2358 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2361 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2362 if (gres != XtGeometryYes && appData.debugMode) {
2363 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2364 programName, gres, w, h, wr, hr);
2367 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2368 /* The size used for the child widget in layout lags one resize behind
2369 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2371 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2372 if (gres != XtGeometryYes && appData.debugMode) {
2373 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2374 programName, gres, w, h, wr, hr);
2377 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2378 XtSetArg(args[1], XtNright, XtChainRight);
2379 XtSetValues(messageWidget, args, 2);
2381 if (appData.titleInWindow) {
2383 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2384 XtSetArg(args[i], XtNheight, &h); i++;
2385 XtGetValues(titleWidget, args, i);
2387 w = boardWidth - 2*bor;
2389 XtSetArg(args[0], XtNwidth, &w);
2390 XtGetValues(menuBarWidget, args, 1);
2391 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2394 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2395 if (gres != XtGeometryYes && appData.debugMode) {
2397 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2398 programName, gres, w, h, wr, hr);
2401 XawFormDoLayout(formWidget, True);
2403 xBoardWindow = XtWindow(boardWidget);
2405 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2406 // not need to go into InitDrawingSizes().
2410 * Create X checkmark bitmap and initialize option menu checks.
2412 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2413 checkmark_bits, checkmark_width, checkmark_height);
2414 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2415 #ifndef OPTIONSDIALOG
2416 if (appData.alwaysPromoteToQueen) {
2417 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2420 if (appData.animateDragging) {
2421 XtSetValues(XtNameToWidget(menuBarWidget,
2422 "menuOptions.Animate Dragging"),
2425 if (appData.animate) {
2426 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2429 if (appData.autoCallFlag) {
2430 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2433 if (appData.autoFlipView) {
2434 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2437 if (appData.blindfold) {
2438 XtSetValues(XtNameToWidget(menuBarWidget,
2439 "menuOptions.Blindfold"), args, 1);
2441 if (appData.flashCount > 0) {
2442 XtSetValues(XtNameToWidget(menuBarWidget,
2443 "menuOptions.Flash Moves"),
2447 if (appData.highlightDragging) {
2448 XtSetValues(XtNameToWidget(menuBarWidget,
2449 "menuOptions.Highlight Dragging"),
2453 if (appData.highlightLastMove) {
2454 XtSetValues(XtNameToWidget(menuBarWidget,
2455 "menuOptions.Highlight Last Move"),
2458 if (appData.highlightMoveWithArrow) {
2459 XtSetValues(XtNameToWidget(menuBarWidget,
2460 "menuOptions.Arrow"),
2463 // if (appData.icsAlarm) {
2464 // XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2467 if (appData.ringBellAfterMoves) {
2468 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2471 if (appData.oneClick) {
2472 XtSetValues(XtNameToWidget(menuBarWidget,
2473 "menuOptions.OneClick"), args, 1);
2475 if (appData.periodicUpdates) {
2476 XtSetValues(XtNameToWidget(menuBarWidget,
2477 "menuOptions.Periodic Updates"), args, 1);
2479 if (appData.ponderNextMove) {
2480 XtSetValues(XtNameToWidget(menuBarWidget,
2481 "menuOptions.Ponder Next Move"), args, 1);
2483 if (appData.popupExitMessage) {
2484 XtSetValues(XtNameToWidget(menuBarWidget,
2485 "menuOptions.Popup Exit Message"), args, 1);
2487 if (appData.popupMoveErrors) {
2488 XtSetValues(XtNameToWidget(menuBarWidget,
2489 "menuOptions.Popup Move Errors"), args, 1);
2491 // if (appData.premove) {
2492 // XtSetValues(XtNameToWidget(menuBarWidget,
2493 // "menuOptions.Premove"), args, 1);
2495 if (appData.showCoords) {
2496 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2499 if (appData.hideThinkingFromHuman) {
2500 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2503 if (appData.testLegality) {
2504 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2508 if (saveSettingsOnExit) {
2509 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2516 ReadBitmap(&wIconPixmap, "icon_white.bm",
2517 icon_white_bits, icon_white_width, icon_white_height);
2518 ReadBitmap(&bIconPixmap, "icon_black.bm",
2519 icon_black_bits, icon_black_width, icon_black_height);
2520 iconPixmap = wIconPixmap;
2522 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2523 XtSetValues(shellWidget, args, i);
2526 * Create a cursor for the board widget.
2528 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2529 XChangeWindowAttributes(xDisplay, xBoardWindow,
2530 CWCursor, &window_attributes);
2533 * Inhibit shell resizing.
2535 shellArgs[0].value = (XtArgVal) &w;
2536 shellArgs[1].value = (XtArgVal) &h;
2537 XtGetValues(shellWidget, shellArgs, 2);
2538 shellArgs[4].value = shellArgs[2].value = w;
2539 shellArgs[5].value = shellArgs[3].value = h;
2540 XtSetValues(shellWidget, &shellArgs[2], 4);
2541 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2542 marginH = h - boardHeight;
2544 CatchDeleteWindow(shellWidget, "QuitProc");
2549 if (appData.bitmapDirectory[0] != NULLCHAR) {
2553 CreateXPMBoard(appData.liteBackTextureFile, 1);
2554 CreateXPMBoard(appData.darkBackTextureFile, 0);
2558 /* Create regular pieces */
2559 if (!useImages) CreatePieces();
2564 if (appData.animate || appData.animateDragging)
2567 XtAugmentTranslations(formWidget,
2568 XtParseTranslationTable(globalTranslations));
2569 XtAugmentTranslations(boardWidget,
2570 XtParseTranslationTable(boardTranslations));
2571 XtAugmentTranslations(whiteTimerWidget,
2572 XtParseTranslationTable(whiteTranslations));
2573 XtAugmentTranslations(blackTimerWidget,
2574 XtParseTranslationTable(blackTranslations));
2576 /* Why is the following needed on some versions of X instead
2577 * of a translation? */
2578 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2579 (XtEventHandler) EventProc, NULL);
2582 /* [AS] Restore layout */
2583 if( wpMoveHistory.visible ) {
2587 if( wpEvalGraph.visible )
2592 if( wpEngineOutput.visible ) {
2593 EngineOutputPopUp();
2598 if (errorExitStatus == -1) {
2599 if (appData.icsActive) {
2600 /* We now wait until we see "login:" from the ICS before
2601 sending the logon script (problems with timestamp otherwise) */
2602 /*ICSInitScript();*/
2603 if (appData.icsInputBox) ICSInputBoxPopUp();
2607 signal(SIGWINCH, TermSizeSigHandler);
2609 signal(SIGINT, IntSigHandler);
2610 signal(SIGTERM, IntSigHandler);
2611 if (*appData.cmailGameName != NULLCHAR) {
2612 signal(SIGUSR1, CmailSigHandler);
2615 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2617 XtSetKeyboardFocus(shellWidget, formWidget);
2619 XtAppMainLoop(appContext);
2620 if (appData.debugMode) fclose(debugFP); // [DM] debug
2627 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2628 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2630 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2631 unlink(gameCopyFilename);
2632 unlink(gamePasteFilename);
2635 RETSIGTYPE TermSizeSigHandler(int sig)
2648 CmailSigHandler(sig)
2654 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2656 /* Activate call-back function CmailSigHandlerCallBack() */
2657 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2659 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2663 CmailSigHandlerCallBack(isr, closure, message, count, error)
2671 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2673 /**** end signal code ****/
2679 /* try to open the icsLogon script, either in the location given
2680 * or in the users HOME directory
2687 f = fopen(appData.icsLogon, "r");
2690 homedir = getenv("HOME");
2691 if (homedir != NULL)
2693 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2694 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2695 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2696 f = fopen(buf, "r");
2701 ProcessICSInitScript(f);
2703 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2726 if (!menuBarWidget) return;
2727 w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2729 DisplayError("menuEdit.Revert", 0);
2731 XtSetSensitive(w, !grey);
2733 w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2735 DisplayError("menuEdit.Annotate", 0);
2737 XtSetSensitive(w, !grey);
2742 SetMenuEnables(enab)
2746 if (!menuBarWidget) return;
2747 while (enab->name != NULL) {
2748 w = XtNameToWidget(menuBarWidget, enab->name);
2750 DisplayError(enab->name, 0);
2752 XtSetSensitive(w, enab->value);
2758 Enables icsEnables[] = {
2759 { "menuFile.Mail Move", False },
2760 { "menuFile.Reload CMail Message", False },
2761 { "menuMode.Machine Black", False },
2762 { "menuMode.Machine White", False },
2763 { "menuMode.Analysis Mode", False },
2764 { "menuMode.Analyze File", False },
2765 { "menuMode.Two Machines", False },
2766 { "menuMode.Machine Match", False },
2768 { "menuEngine.Hint", False },
2769 { "menuEngine.Book", False },
2770 { "menuEngine.Move Now", False },
2771 #ifndef OPTIONSDIALOG
2772 { "menuOptions.Periodic Updates", False },
2773 { "menuOptions.Hide Thinking", False },
2774 { "menuOptions.Ponder Next Move", False },
2776 { "menuEngine.Engine #1 Settings", False },
2778 { "menuEngine.Engine #2 Settings", False },
2779 { "menuEdit.Annotate", False },
2783 Enables ncpEnables[] = {
2784 { "menuFile.Mail Move", False },
2785 { "menuFile.Reload CMail Message", False },
2786 { "menuMode.Machine White", False },
2787 { "menuMode.Machine Black", False },
2788 { "menuMode.Analysis Mode", False },
2789 { "menuMode.Analyze File", False },
2790 { "menuMode.Two Machines", False },
2791 { "menuMode.Machine Match", False },
2792 { "menuMode.ICS Client", False },
2793 { "menuView.ICStex", False },
2794 { "menuView.ICS Input Box", False },
2795 { "Action", False },
2796 { "menuEdit.Revert", False },
2797 { "menuEdit.Annotate", False },
2798 { "menuEngine.Engine #1 Settings", False },
2799 { "menuEngine.Engine #2 Settings", False },
2800 { "menuEngine.Move Now", False },
2801 { "menuEngine.Retract Move", False },
2802 { "menuOptions.ICS", False },
2803 #ifndef OPTIONSDIALOG
2804 { "menuOptions.Auto Flag", False },
2805 { "menuOptions.Auto Flip View", False },
2806 // { "menuOptions.ICS Alarm", False },
2807 { "menuOptions.Move Sound", False },
2808 { "menuOptions.Hide Thinking", False },
2809 { "menuOptions.Periodic Updates", False },
2810 { "menuOptions.Ponder Next Move", False },
2812 { "menuEngine.Hint", False },
2813 { "menuEngine.Book", False },
2817 Enables gnuEnables[] = {
2818 { "menuMode.ICS Client", False },
2819 { "menuView.ICStex", False },
2820 { "menuView.ICS Input Box", False },
2821 { "menuAction.Accept", False },
2822 { "menuAction.Decline", False },
2823 { "menuAction.Rematch", False },
2824 { "menuAction.Adjourn", False },
2825 { "menuAction.Stop Examining", False },
2826 { "menuAction.Stop Observing", False },
2827 { "menuAction.Upload to Examine", False },
2828 { "menuEdit.Revert", False },
2829 { "menuEdit.Annotate", False },
2830 { "menuOptions.ICS", False },
2832 /* The next two options rely on SetCmailMode being called *after* */
2833 /* SetGNUMode so that when GNU is being used to give hints these */
2834 /* menu options are still available */
2836 { "menuFile.Mail Move", False },
2837 { "menuFile.Reload CMail Message", False },
2841 Enables cmailEnables[] = {
2843 { "menuAction.Call Flag", False },
2844 { "menuAction.Draw", True },
2845 { "menuAction.Adjourn", False },
2846 { "menuAction.Abort", False },
2847 { "menuAction.Stop Observing", False },
2848 { "menuAction.Stop Examining", False },
2849 { "menuFile.Mail Move", True },
2850 { "menuFile.Reload CMail Message", True },
2854 Enables trainingOnEnables[] = {
2855 { "menuMode.Edit Comment", False },
2856 { "menuMode.Pause", False },
2857 { "menuEdit.Forward", False },
2858 { "menuEdit.Backward", False },
2859 { "menuEdit.Forward to End", False },
2860 { "menuEdit.Back to Start", False },
2861 { "menuEngine.Move Now", False },
2862 { "menuEdit.Truncate Game", False },
2866 Enables trainingOffEnables[] = {
2867 { "menuMode.Edit Comment", True },
2868 { "menuMode.Pause", True },
2869 { "menuEdit.Forward", True },
2870 { "menuEdit.Backward", True },
2871 { "menuEdit.Forward to End", True },
2872 { "menuEdit.Back to Start", True },
2873 { "menuEngine.Move Now", True },
2874 { "menuEdit.Truncate Game", True },
2878 Enables machineThinkingEnables[] = {
2879 { "menuFile.Load Game", False },
2880 // { "menuFile.Load Next Game", False },
2881 // { "menuFile.Load Previous Game", False },
2882 // { "menuFile.Reload Same Game", False },
2883 { "menuEdit.Paste Game", False },
2884 { "menuFile.Load Position", False },
2885 // { "menuFile.Load Next Position", False },
2886 // { "menuFile.Load Previous Position", False },
2887 // { "menuFile.Reload Same Position", False },
2888 { "menuEdit.Paste Position", False },
2889 { "menuMode.Machine White", False },
2890 { "menuMode.Machine Black", False },
2891 { "menuMode.Two Machines", False },
2892 { "menuMode.Machine Match", False },
2893 { "menuEngine.Retract Move", False },
2897 Enables userThinkingEnables[] = {
2898 { "menuFile.Load Game", True },
2899 // { "menuFile.Load Next Game", True },
2900 // { "menuFile.Load Previous Game", True },
2901 // { "menuFile.Reload Same Game", True },
2902 { "menuEdit.Paste Game", True },
2903 { "menuFile.Load Position", True },
2904 // { "menuFile.Load Next Position", True },
2905 // { "menuFile.Load Previous Position", True },
2906 // { "menuFile.Reload Same Position", True },
2907 { "menuEdit.Paste Position", True },
2908 { "menuMode.Machine White", True },
2909 { "menuMode.Machine Black", True },
2910 { "menuMode.Two Machines", True },
2911 { "menuMode.Machine Match", True },
2912 { "menuEngine.Retract Move", True },
2918 SetMenuEnables(icsEnables);
2921 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2922 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2929 SetMenuEnables(ncpEnables);
2935 SetMenuEnables(gnuEnables);
2941 SetMenuEnables(cmailEnables);
2947 SetMenuEnables(trainingOnEnables);
2948 if (appData.showButtonBar) {
2949 XtSetSensitive(buttonBarWidget, False);
2955 SetTrainingModeOff()
2957 SetMenuEnables(trainingOffEnables);
2958 if (appData.showButtonBar) {
2959 XtSetSensitive(buttonBarWidget, True);
2964 SetUserThinkingEnables()
2966 if (appData.noChessProgram) return;
2967 SetMenuEnables(userThinkingEnables);
2971 SetMachineThinkingEnables()
2973 if (appData.noChessProgram) return;
2974 SetMenuEnables(machineThinkingEnables);
2976 case MachinePlaysBlack:
2977 case MachinePlaysWhite:
2978 case TwoMachinesPlay:
2979 XtSetSensitive(XtNameToWidget(menuBarWidget,
2980 ModeToWidgetName(gameMode)), True);
2987 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2988 #define HISTORY_SIZE 64
2989 static char *history[HISTORY_SIZE];
2990 int histIn = 0, histP = 0;
2993 SaveInHistory(char *cmd)
2995 if (history[histIn] != NULL) {
2996 free(history[histIn]);
2997 history[histIn] = NULL;
2999 if (*cmd == NULLCHAR) return;
3000 history[histIn] = StrSave(cmd);
3001 histIn = (histIn + 1) % HISTORY_SIZE;
3002 if (history[histIn] != NULL) {
3003 free(history[histIn]);
3004 history[histIn] = NULL;
3010 PrevInHistory(char *cmd)
3013 if (histP == histIn) {
3014 if (history[histIn] != NULL) free(history[histIn]);
3015 history[histIn] = StrSave(cmd);
3017 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
3018 if (newhp == histIn || history[newhp] == NULL) return NULL;
3020 return history[histP];
3026 if (histP == histIn) return NULL;
3027 histP = (histP + 1) % HISTORY_SIZE;
3028 return history[histP];
3030 // end of borrowed code
3032 #define Abs(n) ((n)<0 ? -(n) : (n))
3035 * Find a font that matches "pattern" that is as close as
3036 * possible to the targetPxlSize. Prefer fonts that are k
3037 * pixels smaller to fonts that are k pixels larger. The
3038 * pattern must be in the X Consortium standard format,
3039 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3040 * The return value should be freed with XtFree when no
3044 FindFont(pattern, targetPxlSize)
3048 char **fonts, *p, *best, *scalable, *scalableTail;
3049 int i, j, nfonts, minerr, err, pxlSize;
3052 char **missing_list;
3054 char *def_string, *base_fnt_lst, strInt[3];
3056 XFontStruct **fnt_list;
3058 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3059 snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize);
3060 p = strstr(pattern, "--");
3061 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3062 strcat(base_fnt_lst, strInt);
3063 strcat(base_fnt_lst, strchr(p + 2, '-'));
3065 if ((fntSet = XCreateFontSet(xDisplay,
3069 &def_string)) == NULL) {
3071 fprintf(stderr, _("Unable to create font set.\n"));
3075 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3077 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3079 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3080 programName, pattern);
3088 for (i=0; i<nfonts; i++) {
3091 if (*p != '-') continue;
3093 if (*p == NULLCHAR) break;
3094 if (*p++ == '-') j++;
3096 if (j < 7) continue;
3099 scalable = fonts[i];
3102 err = pxlSize - targetPxlSize;
3103 if (Abs(err) < Abs(minerr) ||
3104 (minerr > 0 && err < 0 && -err == minerr)) {
3110 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3111 /* If the error is too big and there is a scalable font,
3112 use the scalable font. */
3113 int headlen = scalableTail - scalable;
3114 p = (char *) XtMalloc(strlen(scalable) + 10);
3115 while (isdigit(*scalableTail)) scalableTail++;
3116 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3118 p = (char *) XtMalloc(strlen(best) + 2);
3119 safeStrCpy(p, best, strlen(best)+1 );
3121 if (appData.debugMode) {
3122 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3123 pattern, targetPxlSize, p);
3126 if (missing_count > 0)
3127 XFreeStringList(missing_list);
3128 XFreeFontSet(xDisplay, fntSet);
3130 XFreeFontNames(fonts);
3136 { // [HGM] deletes GCs that are to be remade, to prevent resource leak;
3137 // must be called before all non-first callse to CreateGCs()
3138 XtReleaseGC(shellWidget, highlineGC);
3139 XtReleaseGC(shellWidget, lightSquareGC);
3140 XtReleaseGC(shellWidget, darkSquareGC);
3141 XtReleaseGC(shellWidget, lineGC);
3142 if (appData.monoMode) {
3143 if (DefaultDepth(xDisplay, xScreen) == 1) {
3144 XtReleaseGC(shellWidget, wbPieceGC);
3146 XtReleaseGC(shellWidget, bwPieceGC);
3149 XtReleaseGC(shellWidget, prelineGC);
3150 XtReleaseGC(shellWidget, jailSquareGC);
3151 XtReleaseGC(shellWidget, wdPieceGC);
3152 XtReleaseGC(shellWidget, wlPieceGC);
3153 XtReleaseGC(shellWidget, wjPieceGC);
3154 XtReleaseGC(shellWidget, bdPieceGC);
3155 XtReleaseGC(shellWidget, blPieceGC);
3156 XtReleaseGC(shellWidget, bjPieceGC);
3160 void CreateGCs(int redo)
3162 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3163 | GCBackground | GCFunction | GCPlaneMask;
3164 XGCValues gc_values;
3167 gc_values.plane_mask = AllPlanes;
3168 gc_values.line_width = lineGap;
3169 gc_values.line_style = LineSolid;
3170 gc_values.function = GXcopy;
3173 DeleteGCs(); // called a second time; clean up old GCs first
3174 } else { // [HGM] grid and font GCs created on first call only
3175 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3176 gc_values.background = XWhitePixel(xDisplay, xScreen);
3177 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3178 XSetFont(xDisplay, coordGC, coordFontID);
3180 // [HGM] make font for holdings counts (white on black)
3181 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3182 gc_values.background = XBlackPixel(xDisplay, xScreen);
3183 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3184 XSetFont(xDisplay, countGC, countFontID);
3186 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3187 gc_values.background = XBlackPixel(xDisplay, xScreen);
3188 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3190 if (appData.monoMode) {
3191 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3192 gc_values.background = XWhitePixel(xDisplay, xScreen);
3193 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3195 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3196 gc_values.background = XBlackPixel(xDisplay, xScreen);
3197 lightSquareGC = wbPieceGC
3198 = XtGetGC(shellWidget, value_mask, &gc_values);
3200 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3201 gc_values.background = XWhitePixel(xDisplay, xScreen);
3202 darkSquareGC = bwPieceGC
3203 = XtGetGC(shellWidget, value_mask, &gc_values);
3205 if (DefaultDepth(xDisplay, xScreen) == 1) {
3206 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3207 gc_values.function = GXcopyInverted;
3208 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3209 gc_values.function = GXcopy;
3210 if (XBlackPixel(xDisplay, xScreen) == 1) {
3211 bwPieceGC = darkSquareGC;
3212 wbPieceGC = copyInvertedGC;
3214 bwPieceGC = copyInvertedGC;
3215 wbPieceGC = lightSquareGC;
3219 gc_values.foreground = highlightSquareColor;
3220 gc_values.background = highlightSquareColor;
3221 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3223 gc_values.foreground = premoveHighlightColor;
3224 gc_values.background = premoveHighlightColor;
3225 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3227 gc_values.foreground = lightSquareColor;
3228 gc_values.background = darkSquareColor;
3229 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3231 gc_values.foreground = darkSquareColor;
3232 gc_values.background = lightSquareColor;
3233 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3235 gc_values.foreground = jailSquareColor;
3236 gc_values.background = jailSquareColor;
3237 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3239 gc_values.foreground = whitePieceColor;
3240 gc_values.background = darkSquareColor;
3241 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3243 gc_values.foreground = whitePieceColor;
3244 gc_values.background = lightSquareColor;
3245 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3247 gc_values.foreground = whitePieceColor;
3248 gc_values.background = jailSquareColor;
3249 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3251 gc_values.foreground = blackPieceColor;
3252 gc_values.background = darkSquareColor;
3253 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3255 gc_values.foreground = blackPieceColor;
3256 gc_values.background = lightSquareColor;
3257 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3259 gc_values.foreground = blackPieceColor;
3260 gc_values.background = jailSquareColor;
3261 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3265 void loadXIM(xim, xmask, filename, dest, mask)
3278 fp = fopen(filename, "rb");
3280 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3287 for (y=0; y<h; ++y) {
3288 for (x=0; x<h; ++x) {
3293 XPutPixel(xim, x, y, blackPieceColor);
3295 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3298 XPutPixel(xim, x, y, darkSquareColor);
3300 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3303 XPutPixel(xim, x, y, whitePieceColor);
3305 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3308 XPutPixel(xim, x, y, lightSquareColor);
3310 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3318 /* create Pixmap of piece */
3319 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3321 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3324 /* create Pixmap of clipmask
3325 Note: We assume the white/black pieces have the same
3326 outline, so we make only 6 masks. This is okay
3327 since the XPM clipmask routines do the same. */
3329 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3331 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3334 /* now create the 1-bit version */
3335 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3338 values.foreground = 1;
3339 values.background = 0;
3341 /* Don't use XtGetGC, not read only */
3342 maskGC = XCreateGC(xDisplay, *mask,
3343 GCForeground | GCBackground, &values);
3344 XCopyPlane(xDisplay, temp, *mask, maskGC,
3345 0, 0, squareSize, squareSize, 0, 0, 1);
3346 XFreePixmap(xDisplay, temp);
3351 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3353 void CreateXIMPieces()
3358 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3363 /* The XSynchronize calls were copied from CreatePieces.
3364 Not sure if needed, but can't hurt */
3365 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3368 /* temp needed by loadXIM() */
3369 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3370 0, 0, ss, ss, AllPlanes, XYPixmap);
3372 if (strlen(appData.pixmapDirectory) == 0) {
3376 if (appData.monoMode) {
3377 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3381 fprintf(stderr, _("\nLoading XIMs...\n"));
3383 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3384 fprintf(stderr, "%d", piece+1);
3385 for (kind=0; kind<4; kind++) {
3386 fprintf(stderr, ".");
3387 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3388 ExpandPathName(appData.pixmapDirectory),
3389 piece <= (int) WhiteKing ? "" : "w",
3390 pieceBitmapNames[piece],
3392 ximPieceBitmap[kind][piece] =
3393 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3394 0, 0, ss, ss, AllPlanes, XYPixmap);
3395 if (appData.debugMode)
3396 fprintf(stderr, _("(File:%s:) "), buf);
3397 loadXIM(ximPieceBitmap[kind][piece],
3399 &(xpmPieceBitmap2[kind][piece]),
3400 &(ximMaskPm2[piece]));
3401 if(piece <= (int)WhiteKing)
3402 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3404 fprintf(stderr," ");
3406 /* Load light and dark squares */
3407 /* If the LSQ and DSQ pieces don't exist, we will
3408 draw them with solid squares. */
3409 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3410 if (access(buf, 0) != 0) {
3414 fprintf(stderr, _("light square "));
3416 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3417 0, 0, ss, ss, AllPlanes, XYPixmap);
3418 if (appData.debugMode)
3419 fprintf(stderr, _("(File:%s:) "), buf);
3421 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3422 fprintf(stderr, _("dark square "));
3423 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3424 ExpandPathName(appData.pixmapDirectory), ss);
3425 if (appData.debugMode)
3426 fprintf(stderr, _("(File:%s:) "), buf);
3428 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3429 0, 0, ss, ss, AllPlanes, XYPixmap);
3430 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3431 xpmJailSquare = xpmLightSquare;
3433 fprintf(stderr, _("Done.\n"));
3435 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3438 static VariantClass oldVariant = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
3441 void CreateXPMBoard(char *s, int kind)
3445 if(s == NULL || *s == 0 || *s == '*') { useTexture &= ~(kind+1); return; }
3446 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3447 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3451 void FreeXPMPieces()
3452 { // [HGM] to prevent resoucre leak on calling CreaeXPMPieces() a second time,
3453 // thisroutine has to be called t free the old piece pixmaps
3455 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++)
3456 for (kind=0; kind<4; kind++) XFreePixmap(xDisplay, xpmPieceBitmap2[kind][piece]);
3458 XFreePixmap(xDisplay, xpmLightSquare);
3459 XFreePixmap(xDisplay, xpmDarkSquare);
3463 void CreateXPMPieces()
3467 u_int ss = squareSize;
3469 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3470 XpmColorSymbol symbols[4];
3471 static int redo = False;
3473 if(redo) FreeXPMPieces(); else redo = 1;
3475 /* The XSynchronize calls were copied from CreatePieces.
3476 Not sure if needed, but can't hurt */
3477 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3479 /* Setup translations so piece colors match square colors */
3480 symbols[0].name = "light_piece";
3481 symbols[0].value = appData.whitePieceColor;
3482 symbols[1].name = "dark_piece";
3483 symbols[1].value = appData.blackPieceColor;
3484 symbols[2].name = "light_square";
3485 symbols[2].value = appData.lightSquareColor;
3486 symbols[3].name = "dark_square";
3487 symbols[3].value = appData.darkSquareColor;
3489 attr.valuemask = XpmColorSymbols;
3490 attr.colorsymbols = symbols;
3491 attr.numsymbols = 4;
3493 if (appData.monoMode) {
3494 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3498 if (strlen(appData.pixmapDirectory) == 0) {
3499 XpmPieces* pieces = builtInXpms;
3502 while (pieces->size != squareSize && pieces->size) pieces++;
3503 if (!pieces->size) {
3504 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3507 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3508 for (kind=0; kind<4; kind++) {
3510 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3511 pieces->xpm[piece][kind],
3512 &(xpmPieceBitmap2[kind][piece]),
3513 NULL, &attr)) != 0) {
3514 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3518 if(piece <= (int) WhiteKing)
3519 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3523 xpmJailSquare = xpmLightSquare;
3527 fprintf(stderr, _("\nLoading XPMs...\n"));
3530 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3531 fprintf(stderr, "%d ", piece+1);
3532 for (kind=0; kind<4; kind++) {
3533 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3534 ExpandPathName(appData.pixmapDirectory),
3535 piece > (int) WhiteKing ? "w" : "",
3536 pieceBitmapNames[piece],
3538 if (appData.debugMode) {
3539 fprintf(stderr, _("(File:%s:) "), buf);
3541 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3542 &(xpmPieceBitmap2[kind][piece]),
3543 NULL, &attr)) != 0) {
3544 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3545 // [HGM] missing: read of unorthodox piece failed; substitute King.
3546 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3547 ExpandPathName(appData.pixmapDirectory),
3549 if (appData.debugMode) {
3550 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3552 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3553 &(xpmPieceBitmap2[kind][piece]),
3557 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3562 if(piece <= (int) WhiteKing)
3563 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3566 /* Load light and dark squares */
3567 /* If the LSQ and DSQ pieces don't exist, we will
3568 draw them with solid squares. */
3569 fprintf(stderr, _("light square "));
3570 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3571 if (access(buf, 0) != 0) {
3575 if (appData.debugMode)
3576 fprintf(stderr, _("(File:%s:) "), buf);
3578 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3579 &xpmLightSquare, NULL, &attr)) != 0) {
3580 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3583 fprintf(stderr, _("dark square "));
3584 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3585 ExpandPathName(appData.pixmapDirectory), ss);
3586 if (appData.debugMode) {
3587 fprintf(stderr, _("(File:%s:) "), buf);
3589 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3590 &xpmDarkSquare, NULL, &attr)) != 0) {
3591 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3595 xpmJailSquare = xpmLightSquare;
3596 fprintf(stderr, _("Done.\n"));
3598 oldVariant = -1; // kludge to force re-makig of animation masks
3599 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3602 #endif /* HAVE_LIBXPM */
3605 /* No built-in bitmaps */
3610 u_int ss = squareSize;
3612 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3615 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3616 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3617 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3618 pieceBitmapNames[piece],
3619 ss, kind == SOLID ? 's' : 'o');
3620 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3621 if(piece <= (int)WhiteKing)
3622 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3626 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3630 /* With built-in bitmaps */
3633 BuiltInBits* bib = builtInBits;
3636 u_int ss = squareSize;
3638 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3641 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3643 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3644 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3645 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3646 pieceBitmapNames[piece],
3647 ss, kind == SOLID ? 's' : 'o');
3648 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3649 bib->bits[kind][piece], ss, ss);
3650 if(piece <= (int)WhiteKing)
3651 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3655 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3660 void ReadBitmap(pm, name, bits, wreq, hreq)
3663 unsigned char bits[];
3669 char msg[MSG_SIZ], fullname[MSG_SIZ];
3671 if (*appData.bitmapDirectory != NULLCHAR) {
3672 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3673 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3674 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3675 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3676 &w, &h, pm, &x_hot, &y_hot);
3677 fprintf(stderr, "load %s\n", name);
3678 if (errcode != BitmapSuccess) {
3680 case BitmapOpenFailed:
3681 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3683 case BitmapFileInvalid:
3684 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3686 case BitmapNoMemory:
3687 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3691 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3695 fprintf(stderr, _("%s: %s...using built-in\n"),
3697 } else if (w != wreq || h != hreq) {
3699 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3700 programName, fullname, w, h, wreq, hreq);
3706 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3715 if (lineGap == 0) return;
3717 /* [HR] Split this into 2 loops for non-square boards. */
3719 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3720 gridSegments[i].x1 = 0;
3721 gridSegments[i].x2 =
3722 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3723 gridSegments[i].y1 = gridSegments[i].y2
3724 = lineGap / 2 + (i * (squareSize + lineGap));
3727 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3728 gridSegments[j + i].y1 = 0;
3729 gridSegments[j + i].y2 =
3730 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3731 gridSegments[j + i].x1 = gridSegments[j + i].x2
3732 = lineGap / 2 + (j * (squareSize + lineGap));
3736 static void MenuBarSelect(w, addr, index)
3741 XtActionProc proc = (XtActionProc) addr;
3743 (proc)(NULL, NULL, NULL, NULL);
3746 void CreateMenuBarPopup(parent, name, mb)
3756 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3759 XtSetArg(args[j], XtNleftMargin, 20); j++;
3760 XtSetArg(args[j], XtNrightMargin, 20); j++;
3762 while (mi->string != NULL) {
3763 if (strcmp(mi->string, "----") == 0) {
3764 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3767 XtSetArg(args[j], XtNlabel, XtNewString(mi->string));
3768 entry = XtCreateManagedWidget(mi->ref, smeBSBObjectClass,
3770 XtAddCallback(entry, XtNcallback,
3771 (XtCallbackProc) MenuBarSelect,
3772 (caddr_t) mi->proc);
3778 Widget CreateMenuBar(mb)
3782 Widget anchor, menuBar;
3784 char menuName[MSG_SIZ];
3787 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3788 XtSetArg(args[j], XtNvSpace, 0); j++;
3789 XtSetArg(args[j], XtNborderWidth, 0); j++;
3790 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3791 formWidget, args, j);
3793 while (mb->name != NULL) {
3794 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3795 strncat(menuName, mb->ref, MSG_SIZ - strlen(menuName) - 1);
3797 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3800 shortName[0] = mb->name[0];
3801 shortName[1] = NULLCHAR;
3802 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3805 XtSetArg(args[j], XtNlabel, XtNewString(mb->name)); j++;
3808 XtSetArg(args[j], XtNborderWidth, 0); j++;
3809 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3811 CreateMenuBarPopup(menuBar, menuName, mb);
3817 Widget CreateButtonBar(mi)
3821 Widget button, buttonBar;
3825 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3827 XtSetArg(args[j], XtNhSpace, 0); j++;
3829 XtSetArg(args[j], XtNborderWidth, 0); j++;
3830 XtSetArg(args[j], XtNvSpace, 0); j++;
3831 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3832 formWidget, args, j);
3834 while (mi->string != NULL) {
3837 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3838 XtSetArg(args[j], XtNborderWidth, 0); j++;
3840 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3841 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3842 buttonBar, args, j);
3843 XtAddCallback(button, XtNcallback,
3844 (XtCallbackProc) MenuBarSelect,
3845 (caddr_t) mi->proc);
3852 CreatePieceMenu(name, color)
3859 ChessSquare selection;
3861 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3862 boardWidget, args, 0);
3864 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3865 String item = pieceMenuStrings[color][i];
3867 if (strcmp(item, "----") == 0) {
3868 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3871 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3872 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3874 selection = pieceMenuTranslation[color][i];
3875 XtAddCallback(entry, XtNcallback,
3876 (XtCallbackProc) PieceMenuSelect,
3877 (caddr_t) selection);
3878 if (selection == WhitePawn || selection == BlackPawn) {
3879 XtSetArg(args[0], XtNpopupOnEntry, entry);
3880 XtSetValues(menu, args, 1);
3893 ChessSquare selection;
3895 whitePieceMenu = CreatePieceMenu("menuW", 0);
3896 blackPieceMenu = CreatePieceMenu("menuB", 1);
3898 XtRegisterGrabAction(PieceMenuPopup, True,
3899 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3900 GrabModeAsync, GrabModeAsync);
3902 XtSetArg(args[0], XtNlabel, _("Drop"));
3903 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3904 boardWidget, args, 1);
3905 for (i = 0; i < DROP_MENU_SIZE; i++) {
3906 String item = dropMenuStrings[i];
3908 if (strcmp(item, "----") == 0) {
3909 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3912 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3913 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3915 selection = dropMenuTranslation[i];
3916 XtAddCallback(entry, XtNcallback,
3917 (XtCallbackProc) DropMenuSelect,
3918 (caddr_t) selection);
3923 void SetupDropMenu()
3931 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3932 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3933 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3934 dmEnables[i].piece);
3935 XtSetSensitive(entry, p != NULL || !appData.testLegality
3936 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3937 && !appData.icsActive));
3939 while (p && *p++ == dmEnables[i].piece) count++;
3940 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3942 XtSetArg(args[j], XtNlabel, label); j++;
3943 XtSetValues(entry, args, j);
3947 void PieceMenuPopup(w, event, params, num_params)
3951 Cardinal *num_params;
3953 String whichMenu; int menuNr;
3954 shiftKey = strcmp(params[0], "menuW"); // used to indicate black
3955 if (event->type == ButtonRelease)
3956 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3957 else if (event->type == ButtonPress)
3958 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3960 case 0: whichMenu = params[0]; break;
3961 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3963 case -1: if (errorUp) ErrorPopDown();
3966 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3969 static void PieceMenuSelect(w, piece, junk)
3974 if (pmFromX < 0 || pmFromY < 0) return;
3975 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3978 static void DropMenuSelect(w, piece, junk)
3983 if (pmFromX < 0 || pmFromY < 0) return;
3984 DropMenuEvent(piece, pmFromX, pmFromY);
3987 void WhiteClock(w, event, prms, nprms)
3996 void BlackClock(w, event, prms, nprms)
4007 * If the user selects on a border boundary, return -1; if off the board,
4008 * return -2. Otherwise map the event coordinate to the square.
4010 int EventToSquare(x, limit)
4018 if ((x % (squareSize + lineGap)) >= squareSize)
4020 x /= (squareSize + lineGap);
4026 static void do_flash_delay(msec)
4032 static void drawHighlight(file, rank, gc)
4038 if (lineGap == 0) return;
4041 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
4042 (squareSize + lineGap);
4043 y = lineGap/2 + rank * (squareSize + lineGap);
4045 x = lineGap/2 + file * (squareSize + lineGap);
4046 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
4047 (squareSize + lineGap);
4050 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
4051 squareSize+lineGap, squareSize+lineGap);
4054 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
4055 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4058 SetHighlights(fromX, fromY, toX, toY)
4059 int fromX, fromY, toX, toY;
4061 if (hi1X != fromX || hi1Y != fromY) {
4062 if (hi1X >= 0 && hi1Y >= 0) {
4063 drawHighlight(hi1X, hi1Y, lineGC);
4065 } // [HGM] first erase both, then draw new!
4066 if (hi2X != toX || hi2Y != toY) {
4067 if (hi2X >= 0 && hi2Y >= 0) {
4068 drawHighlight(hi2X, hi2Y, lineGC);
4071 if (hi1X != fromX || hi1Y != fromY) {
4072 if (fromX >= 0 && fromY >= 0) {
4073 drawHighlight(fromX, fromY, highlineGC);
4076 if (hi2X != toX || hi2Y != toY) {
4077 if (toX >= 0 && toY >= 0) {
4078 drawHighlight(toX, toY, highlineGC);
4090 SetHighlights(-1, -1, -1, -1);
4095 SetPremoveHighlights(fromX, fromY, toX, toY)
4096 int fromX, fromY, toX, toY;
4098 if (pm1X != fromX || pm1Y != fromY) {
4099 if (pm1X >= 0 && pm1Y >= 0) {
4100 drawHighlight(pm1X, pm1Y, lineGC);
4102 if (fromX >= 0 && fromY >= 0) {
4103 drawHighlight(fromX, fromY, prelineGC);
4106 if (pm2X != toX || pm2Y != toY) {
4107 if (pm2X >= 0 && pm2Y >= 0) {
4108 drawHighlight(pm2X, pm2Y, lineGC);
4110 if (toX >= 0 && toY >= 0) {
4111 drawHighlight(toX, toY, prelineGC);
4121 ClearPremoveHighlights()
4123 SetPremoveHighlights(-1, -1, -1, -1);
4126 static int CutOutSquare(x, y, x0, y0, kind)
4127 int x, y, *x0, *y0, kind;
4129 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
4130 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
4132 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
4133 if(textureW[kind] < W*squareSize)
4134 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
4136 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
4137 if(textureH[kind] < H*squareSize)
4138 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
4140 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
4144 static void BlankSquare(x, y, color, piece, dest, fac)
4145 int x, y, color, fac;
4148 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
4150 if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
4151 XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
4152 squareSize, squareSize, x*fac, y*fac);
4154 if (useImages && useImageSqs) {
4158 pm = xpmLightSquare;
4163 case 2: /* neutral */
4168 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4169 squareSize, squareSize, x*fac, y*fac);
4179 case 2: /* neutral */
4184 XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
4189 I split out the routines to draw a piece so that I could
4190 make a generic flash routine.
4192 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4194 int square_color, x, y;
4197 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4198 switch (square_color) {
4200 case 2: /* neutral */
4202 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4203 ? *pieceToOutline(piece)
4204 : *pieceToSolid(piece),
4205 dest, bwPieceGC, 0, 0,
4206 squareSize, squareSize, x, y);
4209 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4210 ? *pieceToSolid(piece)
4211 : *pieceToOutline(piece),
4212 dest, wbPieceGC, 0, 0,
4213 squareSize, squareSize, x, y);
4218 static void monoDrawPiece(piece, square_color, x, y, dest)
4220 int square_color, x, y;
4223 switch (square_color) {
4225 case 2: /* neutral */
4227 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4228 ? *pieceToOutline(piece)
4229 : *pieceToSolid(piece),
4230 dest, bwPieceGC, 0, 0,
4231 squareSize, squareSize, x, y, 1);
4234 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4235 ? *pieceToSolid(piece)
4236 : *pieceToOutline(piece),
4237 dest, wbPieceGC, 0, 0,
4238 squareSize, squareSize, x, y, 1);
4243 static void colorDrawPiece(piece, square_color, x, y, dest)
4245 int square_color, x, y;
4248 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4249 switch (square_color) {
4251 XCopyPlane(xDisplay, *pieceToSolid(piece),
4252 dest, (int) piece < (int) BlackPawn
4253 ? wlPieceGC : blPieceGC, 0, 0,
4254 squareSize, squareSize, x, y, 1);
4257 XCopyPlane(xDisplay, *pieceToSolid(piece),
4258 dest, (int) piece < (int) BlackPawn
4259 ? wdPieceGC : bdPieceGC, 0, 0,
4260 squareSize, squareSize, x, y, 1);
4262 case 2: /* neutral */
4264 XCopyPlane(xDisplay, *pieceToSolid(piece),
4265 dest, (int) piece < (int) BlackPawn
4266 ? wjPieceGC : bjPieceGC, 0, 0,
4267 squareSize, squareSize, x, y, 1);
4272 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4274 int square_color, x, y;
4277 int kind, p = piece;
4279 switch (square_color) {
4281 case 2: /* neutral */
4283 if ((int)piece < (int) BlackPawn) {
4291 if ((int)piece < (int) BlackPawn) {
4299 if(appData.upsideDown && flipView) { kind ^= 2; p += p < BlackPawn ? BlackPawn : -BlackPawn; }// swap white and black pieces
4300 if(useTexture & square_color+1) {
4301 BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background
4302 XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]);
4303 XSetClipOrigin(xDisplay, wlPieceGC, x, y);
4304 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y);
4305 XSetClipMask(xDisplay, wlPieceGC, None);
4306 XSetClipOrigin(xDisplay, wlPieceGC, 0, 0);
4308 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4309 dest, wlPieceGC, 0, 0,
4310 squareSize, squareSize, x, y);
4313 typedef void (*DrawFunc)();
4315 DrawFunc ChooseDrawFunc()
4317 if (appData.monoMode) {
4318 if (DefaultDepth(xDisplay, xScreen) == 1) {
4319 return monoDrawPiece_1bit;
4321 return monoDrawPiece;
4325 return colorDrawPieceImage;
4327 return colorDrawPiece;
4331 /* [HR] determine square color depending on chess variant. */
4332 static int SquareColor(row, column)
4337 if (gameInfo.variant == VariantXiangqi) {
4338 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4340 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4342 } else if (row <= 4) {
4348 square_color = ((column + row) % 2) == 1;
4351 /* [hgm] holdings: next line makes all holdings squares light */
4352 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4354 return square_color;
4357 void DrawSquare(row, column, piece, do_flash)
4358 int row, column, do_flash;
4361 int square_color, x, y, direction, font_ascent, font_descent;
4364 XCharStruct overall;
4368 /* Calculate delay in milliseconds (2-delays per complete flash) */
4369 flash_delay = 500 / appData.flashRate;
4372 x = lineGap + ((BOARD_WIDTH-1)-column) *
4373 (squareSize + lineGap);
4374 y = lineGap + row * (squareSize + lineGap);
4376 x = lineGap + column * (squareSize + lineGap);
4377 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4378 (squareSize + lineGap);
4381 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4383 square_color = SquareColor(row, column);
4385 if ( // [HGM] holdings: blank out area between board and holdings
4386 column == BOARD_LEFT-1 || column == BOARD_RGHT
4387 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4388 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4389 BlankSquare(x, y, 2, EmptySquare, xBoardWindow, 1);
4391 // [HGM] print piece counts next to holdings
4392 string[1] = NULLCHAR;
4393 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4394 string[0] = '0' + piece;
4395 XTextExtents(countFontStruct, string, 1, &direction,
4396 &font_ascent, &font_descent, &overall);
4397 if (appData.monoMode) {
4398 XDrawImageString(xDisplay, xBoardWindow, countGC,
4399 x + squareSize - overall.width - 2,
4400 y + font_ascent + 1, string, 1);
4402 XDrawString(xDisplay, xBoardWindow, countGC,
4403 x + squareSize - overall.width - 2,
4404 y + font_ascent + 1, string, 1);
4407 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4408 string[0] = '0' + piece;
4409 XTextExtents(countFontStruct, string, 1, &direction,
4410 &font_ascent, &font_descent, &overall);
4411 if (appData.monoMode) {
4412 XDrawImageString(xDisplay, xBoardWindow, countGC,
4413 x + 2, y + font_ascent + 1, string, 1);
4415 XDrawString(xDisplay, xBoardWindow, countGC,
4416 x + 2, y + font_ascent + 1, string, 1);
4420 if (piece == EmptySquare || appData.blindfold) {
4421 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4423 drawfunc = ChooseDrawFunc();
4425 if (do_flash && appData.flashCount > 0) {
4426 for (i=0; i<appData.flashCount; ++i) {
4427 drawfunc(piece, square_color, x, y, xBoardWindow);
4428 XSync(xDisplay, False);
4429 do_flash_delay(flash_delay);
4431 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4432 XSync(xDisplay, False);
4433 do_flash_delay(flash_delay);
4436 drawfunc(piece, square_color, x, y, xBoardWindow);
4440 string[1] = NULLCHAR;
4441 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4442 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4443 string[0] = 'a' + column - BOARD_LEFT;
4444 XTextExtents(coordFontStruct, string, 1, &direction,
4445 &font_ascent, &font_descent, &overall);
4446 if (appData.monoMode) {
4447 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4448 x + squareSize - overall.width - 2,
4449 y + squareSize - font_descent - 1, string, 1);
4451 XDrawString(xDisplay, xBoardWindow, coordGC,
4452 x + squareSize - overall.width - 2,
4453 y + squareSize - font_descent - 1, string, 1);
4456 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4457 string[0] = ONE + row;
4458 XTextExtents(coordFontStruct, string, 1, &direction,
4459 &font_ascent, &font_descent, &overall);
4460 if (appData.monoMode) {
4461 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4462 x + 2, y + font_ascent + 1, string, 1);
4464 XDrawString(xDisplay, xBoardWindow, coordGC,
4465 x + 2, y + font_ascent + 1, string, 1);
4468 if(!partnerUp && marker[row][column]) {
4469 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4470 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4475 /* Why is this needed on some versions of X? */
4476 void EventProc(widget, unused, event)
4481 if (!XtIsRealized(widget))
4484 switch (event->type) {
4486 if (event->xexpose.count > 0) return; /* no clipping is done */
4487 XDrawPosition(widget, True, NULL);
4488 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4489 flipView = !flipView; partnerUp = !partnerUp;
4490 XDrawPosition(widget, True, NULL);
4491 flipView = !flipView; partnerUp = !partnerUp;
4495 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
4502 void DrawPosition(fullRedraw, board)
4503 /*Boolean*/int fullRedraw;
4506 XDrawPosition(boardWidget, fullRedraw, board);
4509 /* Returns 1 if there are "too many" differences between b1 and b2
4510 (i.e. more than 1 move was made) */
4511 static int too_many_diffs(b1, b2)
4517 for (i=0; i<BOARD_HEIGHT; ++i) {
4518 for (j=0; j<BOARD_WIDTH; ++j) {
4519 if (b1[i][j] != b2[i][j]) {
4520 if (++c > 4) /* Castling causes 4 diffs */
4528 /* Matrix describing castling maneuvers */
4529 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4530 static int castling_matrix[4][5] = {
4531 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4532 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4533 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4534 { 7, 7, 4, 5, 6 } /* 0-0, black */
4537 /* Checks whether castling occurred. If it did, *rrow and *rcol
4538 are set to the destination (row,col) of the rook that moved.
4540 Returns 1 if castling occurred, 0 if not.
4542 Note: Only handles a max of 1 castling move, so be sure
4543 to call too_many_diffs() first.
4545 static int check_castle_draw(newb, oldb, rrow, rcol)
4552 /* For each type of castling... */
4553 for (i=0; i<4; ++i) {
4554 r = castling_matrix[i];
4556 /* Check the 4 squares involved in the castling move */
4558 for (j=1; j<=4; ++j) {
4559 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4566 /* All 4 changed, so it must be a castling move */
4575 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4576 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4578 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4581 void DrawSeekBackground( int left, int top, int right, int bottom )
4583 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4586 void DrawSeekText(char *buf, int x, int y)
4588 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4591 void DrawSeekDot(int x, int y, int colorNr)
4593 int square = colorNr & 0x80;
4596 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4598 XFillRectangle(xDisplay, xBoardWindow, color,
4599 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4601 XFillArc(xDisplay, xBoardWindow, color,
4602 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4605 static int damage[2][BOARD_RANKS][BOARD_FILES];
4608 * event handler for redrawing the board
4610 void XDrawPosition(w, repaint, board)
4612 /*Boolean*/int repaint;
4616 static int lastFlipView = 0;
4617 static int lastBoardValid[2] = {0, 0};
4618 static Board lastBoard[2];
4621 int nr = twoBoards*partnerUp;
4623 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4625 if (board == NULL) {
4626 if (!lastBoardValid[nr]) return;
4627 board = lastBoard[nr];
4629 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4630 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4631 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Flip View"),
4636 * It would be simpler to clear the window with XClearWindow()
4637 * but this causes a very distracting flicker.
4640 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4642 if ( lineGap && IsDrawArrowEnabled())
4643 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4644 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4646 /* If too much changes (begin observing new game, etc.), don't
4648 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4650 /* Special check for castling so we don't flash both the king
4651 and the rook (just flash the king). */
4653 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4654 /* Draw rook with NO flashing. King will be drawn flashing later */
4655 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4656 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4660 /* First pass -- Draw (newly) empty squares and repair damage.
4661 This prevents you from having a piece show up twice while it
4662 is flashing on its new square */
4663 for (i = 0; i < BOARD_HEIGHT; i++)
4664 for (j = 0; j < BOARD_WIDTH; j++)
4665 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4666 || damage[nr][i][j]) {
4667 DrawSquare(i, j, board[i][j], 0);
4668 damage[nr][i][j] = False;
4671 /* Second pass -- Draw piece(s) in new position and flash them */
4672 for (i = 0; i < BOARD_HEIGHT; i++)
4673 for (j = 0; j < BOARD_WIDTH; j++)
4674 if (board[i][j] != lastBoard[nr][i][j]) {
4675 DrawSquare(i, j, board[i][j], do_flash);
4679 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4680 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4681 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4683 for (i = 0; i < BOARD_HEIGHT; i++)
4684 for (j = 0; j < BOARD_WIDTH; j++) {
4685 DrawSquare(i, j, board[i][j], 0);
4686 damage[nr][i][j] = False;
4690 CopyBoard(lastBoard[nr], board);
4691 lastBoardValid[nr] = 1;
4692 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4693 lastFlipView = flipView;
4695 /* Draw highlights */
4696 if (pm1X >= 0 && pm1Y >= 0) {
4697 drawHighlight(pm1X, pm1Y, prelineGC);
4699 if (pm2X >= 0 && pm2Y >= 0) {
4700 drawHighlight(pm2X, pm2Y, prelineGC);
4702 if (hi1X >= 0 && hi1Y >= 0) {
4703 drawHighlight(hi1X, hi1Y, highlineGC);
4705 if (hi2X >= 0 && hi2Y >= 0) {
4706 drawHighlight(hi2X, hi2Y, highlineGC);
4708 DrawArrowHighlight(hi1X, hi1Y, hi2X, hi2Y);
4710 /* If piece being dragged around board, must redraw that too */
4713 XSync(xDisplay, False);
4718 * event handler for redrawing the board
4720 void DrawPositionProc(w, event, prms, nprms)
4726 XDrawPosition(w, True, NULL);
4731 * event handler for parsing user moves
4733 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4734 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4735 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4736 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4737 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4738 // and at the end FinishMove() to perform the move after optional promotion popups.
4739 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4740 void HandleUserMove(w, event, prms, nprms)
4746 if (w != boardWidget || errorExitStatus != -1) return;
4747 if(nprms) shiftKey = !strcmp(prms[0], "1");
4750 if (event->type == ButtonPress) {
4751 XtPopdown(promotionShell);
4752 XtDestroyWidget(promotionShell);
4753 promotionUp = False;
4761 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4762 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4763 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4766 void AnimateUserMove (Widget w, XEvent * event,
4767 String * params, Cardinal * nParams)
4769 extern ChessSquare promoSweep;
4770 if(promoSweep != EmptySquare && appData.sweepSelect) PromoScroll(event->xmotion.x, event->xmotion.y); else
4771 DragPieceMove(event->xmotion.x, event->xmotion.y);
4774 void HandlePV (Widget w, XEvent * event,
4775 String * params, Cardinal * nParams)
4776 { // [HGM] pv: walk PV
4777 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4780 static int savedIndex; /* gross that this is global */
4782 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
4785 XawTextPosition index, dummy;
4788 XawTextGetSelectionPos(w, &index, &dummy);
4789 XtSetArg(arg, XtNstring, &val);
4790 XtGetValues(w, &arg, 1);
4791 ReplaceComment(savedIndex, val);
4792 if(savedIndex != currentMove) ToNrEvent(savedIndex);
4793 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
4796 void EditCommentPopUp(index, title, text)
4801 if (text == NULL) text = "";
4802 NewCommentPopup(title, text, index);
4805 void ICSInputBoxPopUp()
4810 extern Option boxOptions[];
4812 void ICSInputSendText()
4819 edit = boxOptions[0].handle;
4821 XtSetArg(args[j], XtNstring, &val); j++;
4822 XtGetValues(edit, args, j);
4824 SendMultiLineToICS(val);
4825 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4826 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4829 void ICSInputBoxPopDown()
4834 void CommentPopUp(title, text)
4837 savedIndex = currentMove; // [HGM] vari
4838 NewCommentPopup(title, text, currentMove);
4841 void CommentPopDown()
4846 void FileNamePopUp(label, def, filter, proc, openMode)
4853 fileProc = proc; /* I can't see a way not */
4854 fileOpenMode = openMode; /* to use globals here */
4855 { // [HGM] use file-selector dialog stolen from Ghostview
4857 int index; // this is not supported yet
4859 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
4860 (def[0] ? def : NULL), filter, openMode, NULL, &name))
4861 (void) (*fileProc)(f, index=0, name);
4865 void FileNamePopDown()
4867 if (!filenameUp) return;
4868 XtPopdown(fileNameShell);
4869 XtDestroyWidget(fileNameShell);
4874 void FileNameCallback(w, client_data, call_data)
4876 XtPointer client_data, call_data;
4881 XtSetArg(args[0], XtNlabel, &name);
4882 XtGetValues(w, args, 1);
4884 if (strcmp(name, _("cancel")) == 0) {
4889 FileNameAction(w, NULL, NULL, NULL);
4892 void FileNameAction(w, event, prms, nprms)
4904 name = XawDialogGetValueString(w = XtParent(w));
4906 if ((name != NULL) && (*name != NULLCHAR)) {
4907 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
4908 XtPopdown(w = XtParent(XtParent(w)));
4912 p = strrchr(buf, ' ');
4919 fullname = ExpandPathName(buf);
4921 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
4924 f = fopen(fullname, fileOpenMode);
4926 DisplayError(_("Failed to open file"), errno);
4928 (void) (*fileProc)(f, index, buf);
4935 XtPopdown(w = XtParent(XtParent(w)));
4941 void PromotionPopUp()
4944 Widget dialog, layout;
4946 Dimension bw_width, pw_width;
4950 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4951 XtGetValues(boardWidget, args, j);
4954 XtSetArg(args[j], XtNresizable, True); j++;
4955 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
4957 XtCreatePopupShell("Promotion", transientShellWidgetClass,
4958 shellWidget, args, j);
4960 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
4961 layoutArgs, XtNumber(layoutArgs));
4964 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
4965 XtSetArg(args[j], XtNborderWidth, 0); j++;
4966 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
4969 if(gameInfo.variant != VariantShogi) {
4970 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) {
4971 XawDialogAddButton(dialog, _("Warlord"), PromotionCallback,
4972 (XtPointer) dialog);
4973 XawDialogAddButton(dialog, _("General"), PromotionCallback,
4974 (XtPointer) dialog);
4975 XawDialogAddButton(dialog, _("Lieutenant"), PromotionCallback,
4976 (XtPointer) dialog);
4977 XawDialogAddButton(dialog, _("Captain"), PromotionCallback,
4978 (XtPointer) dialog);
4980 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
4981 (XtPointer) dialog);
4982 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
4983 (XtPointer) dialog);
4984 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
4985 (XtPointer) dialog);
4986 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
4987 (XtPointer) dialog);
4989 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
4990 gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
\r
4991 gameInfo.variant == VariantGiveaway) {
4992 XawDialogAddButton(dialog, _("King"), PromotionCallback,
4993 (XtPointer) dialog);
4995 if(gameInfo.variant == VariantCapablanca ||
4996 gameInfo.variant == VariantGothic ||
4997 gameInfo.variant == VariantCapaRandom) {
4998 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
4999 (XtPointer) dialog);
5000 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5001 (XtPointer) dialog);
5003 } else // [HGM] shogi
5005 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5006 (XtPointer) dialog);
5007 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5008 (XtPointer) dialog);
5010 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5011 (XtPointer) dialog);
5013 XtRealizeWidget(promotionShell);
5014 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5017 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5018 XtGetValues(promotionShell, args, j);
5020 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5021 lineGap + squareSize/3 +
5022 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5023 0 : 6*(squareSize + lineGap)), &x, &y);
5026 XtSetArg(args[j], XtNx, x); j++;
5027 XtSetArg(args[j], XtNy, y); j++;
5028 XtSetValues(promotionShell, args, j);
5030 XtPopup(promotionShell, XtGrabNone);
5035 void PromotionPopDown()
5037 if (!promotionUp) return;
5038 XtPopdown(promotionShell);
5039 XtDestroyWidget(promotionShell);
5040 promotionUp = False;
5043 void PromotionCallback(w, client_data, call_data)
5045 XtPointer client_data, call_data;
5051 XtSetArg(args[0], XtNlabel, &name);
5052 XtGetValues(w, args, 1);
5056 if (fromX == -1) return;
5058 if (strcmp(name, _("cancel")) == 0) {
5062 } else if (strcmp(name, _("Knight")) == 0) {
5064 } else if (strcmp(name, _("Promote")) == 0) {
5066 } else if (strcmp(name, _("Defer")) == 0) {
5069 promoChar = ToLower(name[0]);
5072 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5074 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5075 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5080 void ErrorCallback(w, client_data, call_data)
5082 XtPointer client_data, call_data;
5085 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5087 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5093 if (!errorUp) return;
5095 XtPopdown(errorShell);
5096 XtDestroyWidget(errorShell);
5097 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5100 void ErrorPopUp(title, label, modal)
5101 char *title, *label;
5105 Widget dialog, layout;
5109 Dimension bw_width, pw_width;
5110 Dimension pw_height;
5114 XtSetArg(args[i], XtNresizable, True); i++;
5115 XtSetArg(args[i], XtNtitle, title); i++;
5117 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5118 shellWidget, args, i);
5120 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5121 layoutArgs, XtNumber(layoutArgs));
5124 XtSetArg(args[i], XtNlabel, label); i++;
5125 XtSetArg(args[i], XtNborderWidth, 0); i++;
5126 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5129 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5131 XtRealizeWidget(errorShell);
5132 CatchDeleteWindow(errorShell, "ErrorPopDown");
5135 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5136 XtGetValues(boardWidget, args, i);
5138 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5139 XtSetArg(args[i], XtNheight, &pw_height); i++;
5140 XtGetValues(errorShell, args, i);
5143 /* This code seems to tickle an X bug if it is executed too soon
5144 after xboard starts up. The coordinates get transformed as if
5145 the main window was positioned at (0, 0).
5147 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5148 0 - pw_height + squareSize / 3, &x, &y);
5150 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5151 RootWindowOfScreen(XtScreen(boardWidget)),
5152 (bw_width - pw_width) / 2,
5153 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5157 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5160 XtSetArg(args[i], XtNx, x); i++;
5161 XtSetArg(args[i], XtNy, y); i++;
5162 XtSetValues(errorShell, args, i);
5165 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5168 /* Disable all user input other than deleting the window */
5169 static int frozen = 0;
5173 /* Grab by a widget that doesn't accept input */
5174 XtAddGrab(messageWidget, TRUE, FALSE);
5178 /* Undo a FreezeUI */
5181 if (!frozen) return;
5182 XtRemoveGrab(messageWidget);
5186 char *ModeToWidgetName(mode)
5190 case BeginningOfGame:
5191 if (appData.icsActive)
5192 return "menuMode.ICS Client";
5193 else if (appData.noChessProgram ||
5194 *appData.cmailGameName != NULLCHAR)
5195 return "menuMode.Edit Game";
5197 return "menuMode.Machine Black";
5198 case MachinePlaysBlack:
5199 return "menuMode.Machine Black";
5200 case MachinePlaysWhite:
5201 return "menuMode.Machine White";
5203 return "menuMode.Analysis Mode";
5205 return "menuMode.Analyze File";
5206 case TwoMachinesPlay:
5207 return "menuMode.Two Machines";
5209 return "menuMode.Edit Game";
5210 case PlayFromGameFile:
5211 return "menuFile.Load Game";
5213 return "menuMode.Edit Position";
5215 return "menuMode.Training";
5216 case IcsPlayingWhite:
5217 case IcsPlayingBlack:
5221 return "menuMode.ICS Client";
5228 void ModeHighlight()
5231 static int oldPausing = FALSE;
5232 static GameMode oldmode = (GameMode) -1;
5235 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5237 if (pausing != oldPausing) {
5238 oldPausing = pausing;
5240 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5242 XtSetArg(args[0], XtNleftBitmap, None);
5244 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5247 if (appData.showButtonBar) {
5248 /* Always toggle, don't set. Previous code messes up when
5249 invoked while the button is pressed, as releasing it
5250 toggles the state again. */
5253 XtSetArg(args[0], XtNbackground, &oldbg);
5254 XtSetArg(args[1], XtNforeground, &oldfg);
5255 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5257 XtSetArg(args[0], XtNbackground, oldfg);
5258 XtSetArg(args[1], XtNforeground, oldbg);
5260 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5264 wname = ModeToWidgetName(oldmode);
5265 if (wname != NULL) {
5266 XtSetArg(args[0], XtNleftBitmap, None);
5267 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5269 wname = ModeToWidgetName(gameMode);
5270 if (wname != NULL) {
5271 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5272 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5276 /* Maybe all the enables should be handled here, not just this one */
5277 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5278 gameMode == Training || gameMode == PlayFromGameFile);
5283 * Button/menu procedures
5285 void ResetProc(w, event, prms, nprms)
5294 int LoadGamePopUp(f, gameNumber, title)
5299 cmailMsgLoaded = FALSE;
5300 if (gameNumber == 0) {
5301 int error = GameListBuild(f);
5303 DisplayError(_("Cannot build game list"), error);
5304 } else if (!ListEmpty(&gameList) &&
5305 ((ListGame *) gameList.tailPred)->number > 1) {
5306 GameListPopUp(f, title);
5312 return LoadGame(f, gameNumber, title, FALSE);
5315 void LoadGameProc(w, event, prms, nprms)
5321 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5324 FileNamePopUp(_("Load game file name?"), "", ".pgn .game", LoadGamePopUp, "rb");
5327 void LoadNextGameProc(w, event, prms, nprms)
5336 void LoadPrevGameProc(w, event, prms, nprms)
5345 void ReloadGameProc(w, event, prms, nprms)
5354 void LoadNextPositionProc(w, event, prms, nprms)
5363 void LoadPrevPositionProc(w, event, prms, nprms)
5372 void ReloadPositionProc(w, event, prms, nprms)
5381 void LoadPositionProc(w, event, prms, nprms)
5387 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5390 FileNamePopUp(_("Load position file name?"), "", ".fen .epd .pos", LoadPosition, "rb");
5393 void SaveGameProc(w, event, prms, nprms)
5399 FileNamePopUp(_("Save game file name?"),
5400 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5401 appData.oldSaveStyle ? ".game" : ".pgn",
5405 void SavePositionProc(w, event, prms, nprms)
5411 FileNamePopUp(_("Save position file name?"),
5412 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5413 appData.oldSaveStyle ? ".pos" : ".fen",
5417 void ReloadCmailMsgProc(w, event, prms, nprms)
5423 ReloadCmailMsgEvent(FALSE);
5426 void MailMoveProc(w, event, prms, nprms)
5435 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5436 char *selected_fen_position=NULL;
5439 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5440 Atom *type_return, XtPointer *value_return,
5441 unsigned long *length_return, int *format_return)
5443 char *selection_tmp;
5445 if (!selected_fen_position) return False; /* should never happen */
5446 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5447 /* note: since no XtSelectionDoneProc was registered, Xt will
5448 * automatically call XtFree on the value returned. So have to
5449 * make a copy of it allocated with XtMalloc */
5450 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5451 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
5453 *value_return=selection_tmp;
5454 *length_return=strlen(selection_tmp);
5455 *type_return=*target;
5456 *format_return = 8; /* bits per byte */
5458 } else if (*target == XA_TARGETS(xDisplay)) {
5459 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5460 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5461 targets_tmp[1] = XA_STRING;
5462 *value_return = targets_tmp;
5463 *type_return = XA_ATOM;
5465 *format_return = 8 * sizeof(Atom);
5466 if (*format_return > 32) {
5467 *length_return *= *format_return / 32;
5468 *format_return = 32;
5476 /* note: when called from menu all parameters are NULL, so no clue what the
5477 * Widget which was clicked on was, or what the click event was
5479 void CopyPositionProc(w, event, prms, nprms)
5486 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5487 * have a notion of a position that is selected but not copied.
5488 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5490 if(gameMode == EditPosition) EditPositionDone(TRUE);
5491 if (selected_fen_position) free(selected_fen_position);
5492 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5493 if (!selected_fen_position) return;
5494 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5496 SendPositionSelection,
5497 NULL/* lose_ownership_proc */ ,
5498 NULL/* transfer_done_proc */);
5499 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5501 SendPositionSelection,
5502 NULL/* lose_ownership_proc */ ,
5503 NULL/* transfer_done_proc */);
5506 /* function called when the data to Paste is ready */
5508 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5509 Atom *type, XtPointer value, unsigned long *len, int *format)
5512 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5513 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5514 EditPositionPasteFEN(fenstr);
5518 /* called when Paste Position button is pressed,
5519 * all parameters will be NULL */
5520 void PastePositionProc(w, event, prms, nprms)
5526 XtGetSelectionValue(menuBarWidget,
5527 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5528 /* (XtSelectionCallbackProc) */ PastePositionCB,
5529 NULL, /* client_data passed to PastePositionCB */
5531 /* better to use the time field from the event that triggered the
5532 * call to this function, but that isn't trivial to get
5540 SendGameSelection(Widget w, Atom *selection, Atom *target,
5541 Atom *type_return, XtPointer *value_return,
5542 unsigned long *length_return, int *format_return)
5544 char *selection_tmp;
5546 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5547 FILE* f = fopen(gameCopyFilename, "r");
5550 if (f == NULL) return False;
5554 selection_tmp = XtMalloc(len + 1);
5555 count = fread(selection_tmp, 1, len, f);
5558 XtFree(selection_tmp);
5561 selection_tmp[len] = NULLCHAR;
5562 *value_return = selection_tmp;
5563 *length_return = len;
5564 *type_return = *target;
5565 *format_return = 8; /* bits per byte */
5567 } else if (*target == XA_TARGETS(xDisplay)) {
5568 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5569 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5570 targets_tmp[1] = XA_STRING;
5571 *value_return = targets_tmp;
5572 *type_return = XA_ATOM;
5574 *format_return = 8 * sizeof(Atom);
5575 if (*format_return > 32) {
5576 *length_return *= *format_return / 32;
5577 *format_return = 32;
5585 /* note: when called from menu all parameters are NULL, so no clue what the
5586 * Widget which was clicked on was, or what the click event was
5588 void CopyGameProc(w, event, prms, nprms)
5596 ret = SaveGameToFile(gameCopyFilename, FALSE);
5600 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5601 * have a notion of a game that is selected but not copied.
5602 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5604 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5607 NULL/* lose_ownership_proc */ ,
5608 NULL/* transfer_done_proc */);
5609 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5612 NULL/* lose_ownership_proc */ ,
5613 NULL/* transfer_done_proc */);
5616 /* function called when the data to Paste is ready */
5618 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5619 Atom *type, XtPointer value, unsigned long *len, int *format)
5622 if (value == NULL || *len == 0) {
5623 return; /* nothing had been selected to copy */
5625 f = fopen(gamePasteFilename, "w");
5627 DisplayError(_("Can't open temp file"), errno);
5630 fwrite(value, 1, *len, f);
5633 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5636 /* called when Paste Game button is pressed,
5637 * all parameters will be NULL */
5638 void PasteGameProc(w, event, prms, nprms)
5644 XtGetSelectionValue(menuBarWidget,
5645 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5646 /* (XtSelectionCallbackProc) */ PasteGameCB,
5647 NULL, /* client_data passed to PasteGameCB */
5649 /* better to use the time field from the event that triggered the
5650 * call to this function, but that isn't trivial to get
5660 SaveGameProc(NULL, NULL, NULL, NULL);
5664 void QuitProc(w, event, prms, nprms)
5673 void PauseProc(w, event, prms, nprms)
5683 void MachineBlackProc(w, event, prms, nprms)
5689 MachineBlackEvent();
5692 void MachineWhiteProc(w, event, prms, nprms)
5698 MachineWhiteEvent();
5701 void AnalyzeModeProc(w, event, prms, nprms)
5709 if (!first.analysisSupport) {
5710 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5711 DisplayError(buf, 0);
5714 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5715 if (appData.icsActive) {
5716 if (gameMode != IcsObserving) {
5717 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
5718 DisplayError(buf, 0);
5720 if (appData.icsEngineAnalyze) {
5721 if (appData.debugMode)
5722 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5728 /* if enable, use want disable icsEngineAnalyze */
5729 if (appData.icsEngineAnalyze) {
5734 appData.icsEngineAnalyze = TRUE;
5735 if (appData.debugMode)
5736 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5738 #ifndef OPTIONSDIALOG
5739 if (!appData.showThinking)
5740 ShowThinkingProc(w,event,prms,nprms);
5746 void AnalyzeFileProc(w, event, prms, nprms)
5752 if (!first.analysisSupport) {
5754 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5755 DisplayError(buf, 0);
5759 #ifndef OPTIONSDIALOG
5760 if (!appData.showThinking)
5761 ShowThinkingProc(w,event,prms,nprms);
5764 FileNamePopUp(_("File to analyze"), "", ".pgn .game", LoadGamePopUp, "rb");
5765 AnalysisPeriodicEvent(1);
5768 void TwoMachinesProc(w, event, prms, nprms)
5777 void MatchProc(w, event, prms, nprms)
5783 if(gameMode != BeginningOfGame) { DisplayError(_("You can only start a match from the initial position."), 0); return; }
5784 matchMode = 2; // This is back-end, really
\r
5785 appData.matchGames = appData.defaultMatchGames;
\r
5787 first.matchWins = second.matchWins = 0;
\r
5791 void IcsClientProc(w, event, prms, nprms)
5800 void EditGameProc(w, event, prms, nprms)
5809 void EditPositionProc(w, event, prms, nprms)
5815 EditPositionEvent();
5818 void TrainingProc(w, event, prms, nprms)
5827 void EditCommentProc(w, event, prms, nprms)
5835 if (PopDown(1)) { // popdown succesful
5837 XtSetArg(args[j], XtNleftBitmap, None); j++;
5838 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"), args, j);
5839 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"), args, j);
5840 } else // was not up
5844 void IcsInputBoxProc(w, event, prms, nprms)
5850 if (!PopDown(4)) ICSInputBoxPopUp();
5853 void AcceptProc(w, event, prms, nprms)
5862 void DeclineProc(w, event, prms, nprms)
5871 void RematchProc(w, event, prms, nprms)
5880 void CallFlagProc(w, event, prms, nprms)
5889 void DrawProc(w, event, prms, nprms)
5898 void AbortProc(w, event, prms, nprms)
5907 void AdjournProc(w, event, prms, nprms)
5916 void ResignProc(w, event, prms, nprms)
5925 void AdjuWhiteProc(w, event, prms, nprms)
5931 UserAdjudicationEvent(+1);
5934 void AdjuBlackProc(w, event, prms, nprms)
5940 UserAdjudicationEvent(-1);
5943 void AdjuDrawProc(w, event, prms, nprms)
5949 UserAdjudicationEvent(0);
5952 void EnterKeyProc(w, event, prms, nprms)
5958 if (shellUp[4] == True)
5962 void UpKeyProc(w, event, prms, nprms)
5967 { // [HGM] input: let up-arrow recall previous line from history
5974 if (!shellUp[4]) return;
5975 edit = boxOptions[0].handle;
5977 XtSetArg(args[j], XtNstring, &val); j++;
5978 XtGetValues(edit, args, j);
5979 val = PrevInHistory(val);
5980 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5981 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5983 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
5984 XawTextReplace(edit, 0, 0, &t);
5985 XawTextSetInsertionPoint(edit, 9999);
5989 void DownKeyProc(w, event, prms, nprms)
5994 { // [HGM] input: let down-arrow recall next line from history
5999 if (!shellUp[4]) return;
6000 edit = boxOptions[0].handle;
6001 val = NextInHistory();
6002 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6003 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6005 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6006 XawTextReplace(edit, 0, 0, &t);
6007 XawTextSetInsertionPoint(edit, 9999);
6011 void StopObservingProc(w, event, prms, nprms)
6017 StopObservingEvent();
6020 void StopExaminingProc(w, event, prms, nprms)
6026 StopExaminingEvent();
6029 void UploadProc(w, event, prms, nprms)
6039 void ForwardProc(w, event, prms, nprms)
6049 void BackwardProc(w, event, prms, nprms)
6058 void ToStartProc(w, event, prms, nprms)
6067 void ToEndProc(w, event, prms, nprms)
6076 void RevertProc(w, event, prms, nprms)
6085 void AnnotateProc(w, event, prms, nprms)
6094 void TruncateGameProc(w, event, prms, nprms)
6100 TruncateGameEvent();
6102 void RetractMoveProc(w, event, prms, nprms)
6111 void MoveNowProc(w, event, prms, nprms)
6120 void FlipViewProc(w, event, prms, nprms)
6126 flipView = !flipView;
6127 DrawPosition(True, NULL);
6130 void PonderNextMoveProc(w, event, prms, nprms)
6138 PonderNextMoveEvent(!appData.ponderNextMove);
6139 #ifndef OPTIONSDIALOG
6140 if (appData.ponderNextMove) {
6141 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6143 XtSetArg(args[0], XtNleftBitmap, None);
6145 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6150 #ifndef OPTIONSDIALOG
6151 void AlwaysQueenProc(w, event, prms, nprms)
6159 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6161 if (appData.alwaysPromoteToQueen) {
6162 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6164 XtSetArg(args[0], XtNleftBitmap, None);
6166 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6170 void AnimateDraggingProc(w, event, prms, nprms)
6178 appData.animateDragging = !appData.animateDragging;
6180 if (appData.animateDragging) {
6181 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6184 XtSetArg(args[0], XtNleftBitmap, None);
6186 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6190 void AnimateMovingProc(w, event, prms, nprms)
6198 appData.animate = !appData.animate;
6200 if (appData.animate) {
6201 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6204 XtSetArg(args[0], XtNleftBitmap, None);
6206 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6210 void AutoflagProc(w, event, prms, nprms)
6218 appData.autoCallFlag = !appData.autoCallFlag;
6220 if (appData.autoCallFlag) {
6221 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6223 XtSetArg(args[0], XtNleftBitmap, None);
6225 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6229 void AutoflipProc(w, event, prms, nprms)
6237 appData.autoFlipView = !appData.autoFlipView;
6239 if (appData.autoFlipView) {
6240 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6242 XtSetArg(args[0], XtNleftBitmap, None);
6244 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6248 void BlindfoldProc(w, event, prms, nprms)
6256 appData.blindfold = !appData.blindfold;
6258 if (appData.blindfold) {
6259 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6261 XtSetArg(args[0], XtNleftBitmap, None);
6263 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6266 DrawPosition(True, NULL);
6269 void TestLegalityProc(w, event, prms, nprms)
6277 appData.testLegality = !appData.testLegality;
6279 if (appData.testLegality) {
6280 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6282 XtSetArg(args[0], XtNleftBitmap, None);
6284 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6289 void FlashMovesProc(w, event, prms, nprms)
6297 if (appData.flashCount == 0) {
6298 appData.flashCount = 3;
6300 appData.flashCount = -appData.flashCount;
6303 if (appData.flashCount > 0) {
6304 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6306 XtSetArg(args[0], XtNleftBitmap, None);
6308 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6313 void HighlightDraggingProc(w, event, prms, nprms)
6321 appData.highlightDragging = !appData.highlightDragging;
6323 if (appData.highlightDragging) {
6324 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6326 XtSetArg(args[0], XtNleftBitmap, None);
6328 XtSetValues(XtNameToWidget(menuBarWidget,
6329 "menuOptions.Highlight Dragging"), args, 1);
6333 void HighlightLastMoveProc(w, event, prms, nprms)
6341 appData.highlightLastMove = !appData.highlightLastMove;
6343 if (appData.highlightLastMove) {
6344 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6346 XtSetArg(args[0], XtNleftBitmap, None);
6348 XtSetValues(XtNameToWidget(menuBarWidget,
6349 "menuOptions.Highlight Last Move"), args, 1);
6352 void HighlightArrowProc(w, event, prms, nprms)
6360 appData.highlightMoveWithArrow = !appData.highlightMoveWithArrow;
6362 if (appData.highlightMoveWithArrow) {
6363 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6365 XtSetArg(args[0], XtNleftBitmap, None);
6367 XtSetValues(XtNameToWidget(menuBarWidget,
6368 "menuOptions.Arrow"), args, 1);
6372 void IcsAlarmProc(w, event, prms, nprms)
6380 appData.icsAlarm = !appData.icsAlarm;
6382 if (appData.icsAlarm) {
6383 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6385 XtSetArg(args[0], XtNleftBitmap, None);
6387 XtSetValues(XtNameToWidget(menuBarWidget,
6388 "menuOptions.ICS Alarm"), args, 1);
6392 void MoveSoundProc(w, event, prms, nprms)
6400 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6402 if (appData.ringBellAfterMoves) {
6403 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6405 XtSetArg(args[0], XtNleftBitmap, None);
6407 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6411 void OneClickProc(w, event, prms, nprms)
6419 appData.oneClick = !appData.oneClick;
6421 if (appData.oneClick) {
6422 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6424 XtSetArg(args[0], XtNleftBitmap, None);
6426 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.OneClick"),
6430 void PeriodicUpdatesProc(w, event, prms, nprms)
6438 PeriodicUpdatesEvent(!appData.periodicUpdates);
6440 if (appData.periodicUpdates) {
6441 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6443 XtSetArg(args[0], XtNleftBitmap, None);
6445 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6449 void PopupExitMessageProc(w, event, prms, nprms)
6457 appData.popupExitMessage = !appData.popupExitMessage;
6459 if (appData.popupExitMessage) {
6460 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6462 XtSetArg(args[0], XtNleftBitmap, None);
6464 XtSetValues(XtNameToWidget(menuBarWidget,
6465 "menuOptions.Popup Exit Message"), args, 1);
6468 void PopupMoveErrorsProc(w, event, prms, nprms)
6476 appData.popupMoveErrors = !appData.popupMoveErrors;
6478 if (appData.popupMoveErrors) {
6479 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6481 XtSetArg(args[0], XtNleftBitmap, None);
6483 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6488 void PremoveProc(w, event, prms, nprms)
6496 appData.premove = !appData.premove;
6498 if (appData.premove) {
6499 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6501 XtSetArg(args[0], XtNleftBitmap, None);
6503 XtSetValues(XtNameToWidget(menuBarWidget,
6504 "menuOptions.Premove"), args, 1);
6508 void ShowCoordsProc(w, event, prms, nprms)
6516 appData.showCoords = !appData.showCoords;
6518 if (appData.showCoords) {
6519 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6521 XtSetArg(args[0], XtNleftBitmap, None);
6523 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6526 DrawPosition(True, NULL);
6529 void ShowThinkingProc(w, event, prms, nprms)
6535 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6536 ShowThinkingEvent();
6539 void HideThinkingProc(w, event, prms, nprms)
6547 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6548 ShowThinkingEvent();
6550 if (appData.hideThinkingFromHuman) {
6551 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6553 XtSetArg(args[0], XtNleftBitmap, None);
6555 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6560 void SaveOnExitProc(w, event, prms, nprms)
6568 saveSettingsOnExit = !saveSettingsOnExit;
6570 if (saveSettingsOnExit) {
6571 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6573 XtSetArg(args[0], XtNleftBitmap, None);
6575 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6579 void SaveSettingsProc(w, event, prms, nprms)
6585 SaveSettings(settingsFileName);
6588 void InfoProc(w, event, prms, nprms)
6595 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6600 void ManProc(w, event, prms, nprms)
6608 if (nprms && *nprms > 0)
6612 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6616 void HintProc(w, event, prms, nprms)
6625 void BookProc(w, event, prms, nprms)
6634 void AboutProc(w, event, prms, nprms)
6642 char *zippy = " (with Zippy code)";
6646 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6647 programVersion, zippy,
6648 "Copyright 1991 Digital Equipment Corporation",
6649 "Enhancements Copyright 1992-2009 Free Software Foundation",
6650 "Enhancements Copyright 2005 Alessandro Scotti",
6651 PACKAGE, " is free software and carries NO WARRANTY;",
6652 "see the file COPYING for more information.");
6653 ErrorPopUp(_("About XBoard"), buf, FALSE);
6656 void DebugProc(w, event, prms, nprms)
6662 appData.debugMode = !appData.debugMode;
6665 void AboutGameProc(w, event, prms, nprms)
6674 void NothingProc(w, event, prms, nprms)
6683 void Iconify(w, event, prms, nprms)
6692 XtSetArg(args[0], XtNiconic, True);
6693 XtSetValues(shellWidget, args, 1);
6696 void DisplayMessage(message, extMessage)
6697 char *message, *extMessage;
6699 /* display a message in the message widget */
6708 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
6713 message = extMessage;
6717 /* need to test if messageWidget already exists, since this function
6718 can also be called during the startup, if for example a Xresource
6719 is not set up correctly */
6722 XtSetArg(arg, XtNlabel, message);
6723 XtSetValues(messageWidget, &arg, 1);
6729 void DisplayTitle(text)
6734 char title[MSG_SIZ];
6737 if (text == NULL) text = "";
6739 if (appData.titleInWindow) {
6741 XtSetArg(args[i], XtNlabel, text); i++;
6742 XtSetValues(titleWidget, args, i);
6745 if (*text != NULLCHAR) {
6746 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
6747 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
6748 } else if (appData.icsActive) {
6749 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
6750 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
6751 } else if (appData.cmailGameName[0] != NULLCHAR) {
6752 snprintf(icon, sizeof(icon), "%s", "CMail");
6753 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
6755 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
6756 } else if (gameInfo.variant == VariantGothic) {
6757 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6758 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
6761 } else if (gameInfo.variant == VariantFalcon) {
6762 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6763 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
6765 } else if (appData.noChessProgram) {
6766 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6767 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
6769 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
6770 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
6773 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
6774 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
6775 XtSetValues(shellWidget, args, i);
6780 DisplayError(message, error)
6787 if (appData.debugMode || appData.matchMode) {
6788 fprintf(stderr, "%s: %s\n", programName, message);
6791 if (appData.debugMode || appData.matchMode) {
6792 fprintf(stderr, "%s: %s: %s\n",
6793 programName, message, strerror(error));
6795 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6798 ErrorPopUp(_("Error"), message, FALSE);
6802 void DisplayMoveError(message)
6807 DrawPosition(FALSE, NULL);
6808 if (appData.debugMode || appData.matchMode) {
6809 fprintf(stderr, "%s: %s\n", programName, message);
6811 if (appData.popupMoveErrors) {
6812 ErrorPopUp(_("Error"), message, FALSE);
6814 DisplayMessage(message, "");
6819 void DisplayFatalError(message, error, status)
6825 errorExitStatus = status;
6827 fprintf(stderr, "%s: %s\n", programName, message);
6829 fprintf(stderr, "%s: %s: %s\n",
6830 programName, message, strerror(error));
6831 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6834 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
6835 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
6841 void DisplayInformation(message)
6845 ErrorPopUp(_("Information"), message, TRUE);
6848 void DisplayNote(message)
6852 ErrorPopUp(_("Note"), message, FALSE);
6856 NullXErrorCheck(dpy, error_event)
6858 XErrorEvent *error_event;
6863 void DisplayIcsInteractionTitle(message)
6866 if (oldICSInteractionTitle == NULL) {
6867 /* Magic to find the old window title, adapted from vim */
6868 char *wina = getenv("WINDOWID");
6870 Window win = (Window) atoi(wina);
6871 Window root, parent, *children;
6872 unsigned int nchildren;
6873 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
6875 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
6876 if (!XQueryTree(xDisplay, win, &root, &parent,
6877 &children, &nchildren)) break;
6878 if (children) XFree((void *)children);
6879 if (parent == root || parent == 0) break;
6882 XSetErrorHandler(oldHandler);
6884 if (oldICSInteractionTitle == NULL) {
6885 oldICSInteractionTitle = "xterm";
6888 printf("\033]0;%s\007", message);
6892 char pendingReplyPrefix[MSG_SIZ];
6893 ProcRef pendingReplyPR;
6895 void AskQuestionProc(w, event, prms, nprms)
6902 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
6906 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
6909 void AskQuestionPopDown()
6911 if (!askQuestionUp) return;
6912 XtPopdown(askQuestionShell);
6913 XtDestroyWidget(askQuestionShell);
6914 askQuestionUp = False;
6917 void AskQuestionReplyAction(w, event, prms, nprms)
6927 reply = XawDialogGetValueString(w = XtParent(w));
6928 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
6929 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
6930 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
6931 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
6932 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
6933 AskQuestionPopDown();
6935 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
6938 void AskQuestionCallback(w, client_data, call_data)
6940 XtPointer client_data, call_data;
6945 XtSetArg(args[0], XtNlabel, &name);
6946 XtGetValues(w, args, 1);
6948 if (strcmp(name, _("cancel")) == 0) {
6949 AskQuestionPopDown();
6951 AskQuestionReplyAction(w, NULL, NULL, NULL);
6955 void AskQuestion(title, question, replyPrefix, pr)
6956 char *title, *question, *replyPrefix;
6960 Widget popup, layout, dialog, edit;
6966 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
6967 pendingReplyPR = pr;
6970 XtSetArg(args[i], XtNresizable, True); i++;
6971 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
6972 askQuestionShell = popup =
6973 XtCreatePopupShell(title, transientShellWidgetClass,
6974 shellWidget, args, i);
6977 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
6978 layoutArgs, XtNumber(layoutArgs));
6981 XtSetArg(args[i], XtNlabel, question); i++;
6982 XtSetArg(args[i], XtNvalue, ""); i++;
6983 XtSetArg(args[i], XtNborderWidth, 0); i++;
6984 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
6987 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
6988 (XtPointer) dialog);
6989 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
6990 (XtPointer) dialog);
6992 XtRealizeWidget(popup);
6993 CatchDeleteWindow(popup, "AskQuestionPopDown");
6995 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
6996 &x, &y, &win_x, &win_y, &mask);
6998 XtSetArg(args[0], XtNx, x - 10);
6999 XtSetArg(args[1], XtNy, y - 30);
7000 XtSetValues(popup, args, 2);
7002 XtPopup(popup, XtGrabExclusive);
7003 askQuestionUp = True;
7005 edit = XtNameToWidget(dialog, "*value");
7006 XtSetKeyboardFocus(popup, edit);
7014 if (*name == NULLCHAR) {
7016 } else if (strcmp(name, "$") == 0) {
7017 putc(BELLCHAR, stderr);
7020 char *prefix = "", *sep = "";
7021 if(!strchr(name, '/')) { prefix = appData.soundDirectory; sep = "/"; }
7022 snprintf(buf, sizeof(buf), "%s '%s%s%s' &", appData.soundProgram, prefix, sep, name);
7030 PlaySound(appData.soundMove);
7036 PlaySound(appData.soundIcsWin);
7042 PlaySound(appData.soundIcsLoss);
7048 PlaySound(appData.soundIcsDraw);
7052 PlayIcsUnfinishedSound()
7054 PlaySound(appData.soundIcsUnfinished);
7060 PlaySound(appData.soundIcsAlarm);
7066 system("stty echo");
7072 system("stty -echo");
7076 Colorize(cc, continuation)
7081 int count, outCount, error;
7083 if (textColors[(int)cc].bg > 0) {
7084 if (textColors[(int)cc].fg > 0) {
7085 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7086 textColors[(int)cc].fg, textColors[(int)cc].bg);
7088 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7089 textColors[(int)cc].bg);
7092 if (textColors[(int)cc].fg > 0) {
7093 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7094 textColors[(int)cc].fg);
7096 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7099 count = strlen(buf);
7100 outCount = OutputToProcess(NoProc, buf, count, &error);
7101 if (outCount < count) {
7102 DisplayFatalError(_("Error writing to display"), error, 1);
7105 if (continuation) return;
7108 PlaySound(appData.soundShout);
7111 PlaySound(appData.soundSShout);
7114 PlaySound(appData.soundChannel1);
7117 PlaySound(appData.soundChannel);
7120 PlaySound(appData.soundKibitz);
7123 PlaySound(appData.soundTell);
7125 case ColorChallenge:
7126 PlaySound(appData.soundChallenge);
7129 PlaySound(appData.soundRequest);
7132 PlaySound(appData.soundSeek);
7143 return getpwuid(getuid())->pw_name;
7147 ExpandPathName(path)
7150 static char static_buf[4*MSG_SIZ];
7151 char *d, *s, buf[4*MSG_SIZ];
7157 while (*s && isspace(*s))
7166 if (*(s+1) == '/') {
7167 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7171 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7172 { char *p; if(p = strchr(buf, '/')) *p = 0; }
7173 pwd = getpwnam(buf);
7176 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7180 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7181 strcat(d, strchr(s+1, '/'));
7185 safeStrCpy(d, s, 4*MSG_SIZ );
7192 static char host_name[MSG_SIZ];
7194 #if HAVE_GETHOSTNAME
7195 gethostname(host_name, MSG_SIZ);
7197 #else /* not HAVE_GETHOSTNAME */
7198 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7199 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7201 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7203 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7204 #endif /* not HAVE_GETHOSTNAME */
7207 XtIntervalId delayedEventTimerXID = 0;
7208 DelayedEventCallback delayedEventCallback = 0;
7213 delayedEventTimerXID = 0;
7214 delayedEventCallback();
7218 ScheduleDelayedEvent(cb, millisec)
7219 DelayedEventCallback cb; long millisec;
7221 if(delayedEventTimerXID && delayedEventCallback == cb)
7222 // [HGM] alive: replace, rather than add or flush identical event
7223 XtRemoveTimeOut(delayedEventTimerXID);
7224 delayedEventCallback = cb;
7225 delayedEventTimerXID =
7226 XtAppAddTimeOut(appContext, millisec,
7227 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7230 DelayedEventCallback
7233 if (delayedEventTimerXID) {
7234 return delayedEventCallback;
7241 CancelDelayedEvent()
7243 if (delayedEventTimerXID) {
7244 XtRemoveTimeOut(delayedEventTimerXID);
7245 delayedEventTimerXID = 0;
7249 XtIntervalId loadGameTimerXID = 0;
7251 int LoadGameTimerRunning()
7253 return loadGameTimerXID != 0;
7256 int StopLoadGameTimer()
7258 if (loadGameTimerXID != 0) {
7259 XtRemoveTimeOut(loadGameTimerXID);
7260 loadGameTimerXID = 0;
7268 LoadGameTimerCallback(arg, id)
7272 loadGameTimerXID = 0;
7277 StartLoadGameTimer(millisec)
7281 XtAppAddTimeOut(appContext, millisec,
7282 (XtTimerCallbackProc) LoadGameTimerCallback,
7286 XtIntervalId analysisClockXID = 0;
7289 AnalysisClockCallback(arg, id)
7293 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7294 || appData.icsEngineAnalyze) { // [DM]
7295 AnalysisPeriodicEvent(0);
7296 StartAnalysisClock();
7301 StartAnalysisClock()
7304 XtAppAddTimeOut(appContext, 2000,
7305 (XtTimerCallbackProc) AnalysisClockCallback,
7309 XtIntervalId clockTimerXID = 0;
7311 int ClockTimerRunning()
7313 return clockTimerXID != 0;
7316 int StopClockTimer()
7318 if (clockTimerXID != 0) {
7319 XtRemoveTimeOut(clockTimerXID);
7328 ClockTimerCallback(arg, id)
7337 StartClockTimer(millisec)
7341 XtAppAddTimeOut(appContext, millisec,
7342 (XtTimerCallbackProc) ClockTimerCallback,
7347 DisplayTimerLabel(w, color, timer, highlight)
7356 /* check for low time warning */
7357 Pixel foregroundOrWarningColor = timerForegroundPixel;
7360 appData.lowTimeWarning &&
7361 (timer / 1000) < appData.icsAlarmTime)
7362 foregroundOrWarningColor = lowTimeWarningColor;
7364 if (appData.clockMode) {
7365 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7366 XtSetArg(args[0], XtNlabel, buf);
7368 snprintf(buf, MSG_SIZ, "%s ", color);
7369 XtSetArg(args[0], XtNlabel, buf);
7374 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7375 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7377 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7378 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7381 XtSetValues(w, args, 3);
7385 DisplayWhiteClock(timeRemaining, highlight)
7391 if(appData.noGUI) return;
7392 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7393 if (highlight && iconPixmap == bIconPixmap) {
7394 iconPixmap = wIconPixmap;
7395 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7396 XtSetValues(shellWidget, args, 1);
7401 DisplayBlackClock(timeRemaining, highlight)
7407 if(appData.noGUI) return;
7408 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7409 if (highlight && iconPixmap == wIconPixmap) {
7410 iconPixmap = bIconPixmap;
7411 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7412 XtSetValues(shellWidget, args, 1);
7430 int StartChildProcess(cmdLine, dir, pr)
7437 int to_prog[2], from_prog[2];
7441 if (appData.debugMode) {
7442 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7445 /* We do NOT feed the cmdLine to the shell; we just
7446 parse it into blank-separated arguments in the
7447 most simple-minded way possible.
7450 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7453 while(*p == ' ') p++;
7455 if(*p == '"' || *p == '\'')
7456 p = strchr(++argv[i-1], *p);
7457 else p = strchr(p, ' ');
7458 if (p == NULL) break;
7463 SetUpChildIO(to_prog, from_prog);
7465 if ((pid = fork()) == 0) {
7467 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7468 close(to_prog[1]); // first close the unused pipe ends
7469 close(from_prog[0]);
7470 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7471 dup2(from_prog[1], 1);
7472 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7473 close(from_prog[1]); // and closing again loses one of the pipes!
7474 if(fileno(stderr) >= 2) // better safe than sorry...
7475 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7477 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7482 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7484 execvp(argv[0], argv);
7486 /* If we get here, exec failed */
7491 /* Parent process */
7493 close(from_prog[1]);
7495 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7498 cp->fdFrom = from_prog[0];
7499 cp->fdTo = to_prog[1];
7504 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7505 static RETSIGTYPE AlarmCallBack(int n)
7511 DestroyChildProcess(pr, signalType)
7515 ChildProc *cp = (ChildProc *) pr;
7517 if (cp->kind != CPReal) return;
7519 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7520 signal(SIGALRM, AlarmCallBack);
7522 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7523 kill(cp->pid, SIGKILL); // kill it forcefully
7524 wait((int *) 0); // and wait again
7528 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7530 /* Process is exiting either because of the kill or because of
7531 a quit command sent by the backend; either way, wait for it to die.
7540 InterruptChildProcess(pr)
7543 ChildProc *cp = (ChildProc *) pr;
7545 if (cp->kind != CPReal) return;
7546 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7549 int OpenTelnet(host, port, pr)
7554 char cmdLine[MSG_SIZ];
7556 if (port[0] == NULLCHAR) {
7557 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7559 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7561 return StartChildProcess(cmdLine, "", pr);
7564 int OpenTCP(host, port, pr)
7570 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7571 #else /* !OMIT_SOCKETS */
7573 struct sockaddr_in sa;
7575 unsigned short uport;
7578 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7582 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7583 sa.sin_family = AF_INET;
7584 sa.sin_addr.s_addr = INADDR_ANY;
7585 uport = (unsigned short) 0;
7586 sa.sin_port = htons(uport);
7587 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7591 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7592 if (!(hp = gethostbyname(host))) {
7594 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7595 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7596 hp->h_addrtype = AF_INET;
7598 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7599 hp->h_addr_list[0] = (char *) malloc(4);
7600 hp->h_addr_list[0][0] = b0;
7601 hp->h_addr_list[0][1] = b1;
7602 hp->h_addr_list[0][2] = b2;
7603 hp->h_addr_list[0][3] = b3;
7608 sa.sin_family = hp->h_addrtype;
7609 uport = (unsigned short) atoi(port);
7610 sa.sin_port = htons(uport);
7611 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7613 if (connect(s, (struct sockaddr *) &sa,
7614 sizeof(struct sockaddr_in)) < 0) {
7618 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7625 #endif /* !OMIT_SOCKETS */
7630 int OpenCommPort(name, pr)
7637 fd = open(name, 2, 0);
7638 if (fd < 0) return errno;
7640 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7650 int OpenLoopback(pr)
7656 SetUpChildIO(to, from);
7658 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7661 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7668 int OpenRcmd(host, user, cmd, pr)
7669 char *host, *user, *cmd;
7672 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7676 #define INPUT_SOURCE_BUF_SIZE 8192
7685 char buf[INPUT_SOURCE_BUF_SIZE];
7690 DoInputCallback(closure, source, xid)
7695 InputSource *is = (InputSource *) closure;
7700 if (is->lineByLine) {
7701 count = read(is->fd, is->unused,
7702 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7704 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7707 is->unused += count;
7709 while (p < is->unused) {
7710 q = memchr(p, '\n', is->unused - p);
7711 if (q == NULL) break;
7713 (is->func)(is, is->closure, p, q - p, 0);
7717 while (p < is->unused) {
7722 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
7727 (is->func)(is, is->closure, is->buf, count, error);
7731 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
7738 ChildProc *cp = (ChildProc *) pr;
7740 is = (InputSource *) calloc(1, sizeof(InputSource));
7741 is->lineByLine = lineByLine;
7745 is->fd = fileno(stdin);
7747 is->kind = cp->kind;
7748 is->fd = cp->fdFrom;
7751 is->unused = is->buf;
7754 is->xid = XtAppAddInput(appContext, is->fd,
7755 (XtPointer) (XtInputReadMask),
7756 (XtInputCallbackProc) DoInputCallback,
7758 is->closure = closure;
7759 return (InputSourceRef) is;
7763 RemoveInputSource(isr)
7766 InputSource *is = (InputSource *) isr;
7768 if (is->xid == 0) return;
7769 XtRemoveInput(is->xid);
7773 int OutputToProcess(pr, message, count, outError)
7779 static int line = 0;
7780 ChildProc *cp = (ChildProc *) pr;
7785 if (appData.noJoin || !appData.useInternalWrap)
7786 outCount = fwrite(message, 1, count, stdout);
7789 int width = get_term_width();
7790 int len = wrap(NULL, message, count, width, &line);
7791 char *msg = malloc(len);
7795 outCount = fwrite(message, 1, count, stdout);
7798 dbgchk = wrap(msg, message, count, width, &line);
7799 if (dbgchk != len && appData.debugMode)
7800 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
7801 outCount = fwrite(msg, 1, dbgchk, stdout);
7807 outCount = write(cp->fdTo, message, count);
7817 /* Output message to process, with "ms" milliseconds of delay
7818 between each character. This is needed when sending the logon
7819 script to ICC, which for some reason doesn't like the
7820 instantaneous send. */
7821 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
7828 ChildProc *cp = (ChildProc *) pr;
7833 r = write(cp->fdTo, message++, 1);
7846 /**** Animation code by Hugh Fisher, DCS, ANU.
7848 Known problem: if a window overlapping the board is
7849 moved away while a piece is being animated underneath,
7850 the newly exposed area won't be updated properly.
7851 I can live with this.
7853 Known problem: if you look carefully at the animation
7854 of pieces in mono mode, they are being drawn as solid
7855 shapes without interior detail while moving. Fixing
7856 this would be a major complication for minimal return.
7859 /* Masks for XPM pieces. Black and white pieces can have
7860 different shapes, but in the interest of retaining my
7861 sanity pieces must have the same outline on both light
7862 and dark squares, and all pieces must use the same
7863 background square colors/images. */
7865 static int xpmDone = 0;
7868 CreateAnimMasks (pieceDepth)
7875 unsigned long plane;
7878 /* Need a bitmap just to get a GC with right depth */
7879 buf = XCreatePixmap(xDisplay, xBoardWindow,
7881 values.foreground = 1;
7882 values.background = 0;
7883 /* Don't use XtGetGC, not read only */
7884 maskGC = XCreateGC(xDisplay, buf,
7885 GCForeground | GCBackground, &values);
7886 XFreePixmap(xDisplay, buf);
7888 buf = XCreatePixmap(xDisplay, xBoardWindow,
7889 squareSize, squareSize, pieceDepth);
7890 values.foreground = XBlackPixel(xDisplay, xScreen);
7891 values.background = XWhitePixel(xDisplay, xScreen);
7892 bufGC = XCreateGC(xDisplay, buf,
7893 GCForeground | GCBackground, &values);
7895 for (piece = WhitePawn; piece <= BlackKing; piece++) {
7896 /* Begin with empty mask */
7897 if(!xpmDone) // [HGM] pieces: keep using existing
7898 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
7899 squareSize, squareSize, 1);
7900 XSetFunction(xDisplay, maskGC, GXclear);
7901 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
7902 0, 0, squareSize, squareSize);
7904 /* Take a copy of the piece */
7909 XSetFunction(xDisplay, bufGC, GXcopy);
7910 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
7912 0, 0, squareSize, squareSize, 0, 0);
7914 /* XOR the background (light) over the piece */
7915 XSetFunction(xDisplay, bufGC, GXxor);
7917 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
7918 0, 0, squareSize, squareSize, 0, 0);
7920 XSetForeground(xDisplay, bufGC, lightSquareColor);
7921 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
7924 /* We now have an inverted piece image with the background
7925 erased. Construct mask by just selecting all the non-zero
7926 pixels - no need to reconstruct the original image. */
7927 XSetFunction(xDisplay, maskGC, GXor);
7929 /* Might be quicker to download an XImage and create bitmap
7930 data from it rather than this N copies per piece, but it
7931 only takes a fraction of a second and there is a much
7932 longer delay for loading the pieces. */
7933 for (n = 0; n < pieceDepth; n ++) {
7934 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
7935 0, 0, squareSize, squareSize,
7941 XFreePixmap(xDisplay, buf);
7942 XFreeGC(xDisplay, bufGC);
7943 XFreeGC(xDisplay, maskGC);
7947 InitAnimState (anim, info)
7949 XWindowAttributes * info;
7954 /* Each buffer is square size, same depth as window */
7955 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
7956 squareSize, squareSize, info->depth);
7957 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
7958 squareSize, squareSize, info->depth);
7960 /* Create a plain GC for blitting */
7961 mask = GCForeground | GCBackground | GCFunction |
7962 GCPlaneMask | GCGraphicsExposures;
7963 values.foreground = XBlackPixel(xDisplay, xScreen);
7964 values.background = XWhitePixel(xDisplay, xScreen);
7965 values.function = GXcopy;
7966 values.plane_mask = AllPlanes;
7967 values.graphics_exposures = False;
7968 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
7970 /* Piece will be copied from an existing context at
7971 the start of each new animation/drag. */
7972 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
7974 /* Outline will be a read-only copy of an existing */
7975 anim->outlineGC = None;
7981 XWindowAttributes info;
7983 if (xpmDone && gameInfo.variant == oldVariant) return;
7984 if(xpmDone) oldVariant = gameInfo.variant; // first time pieces might not be created yet
7985 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
7987 InitAnimState(&game, &info);
7988 InitAnimState(&player, &info);
7990 /* For XPM pieces, we need bitmaps to use as masks. */
7992 CreateAnimMasks(info.depth);
7998 static Boolean frameWaiting;
8000 static RETSIGTYPE FrameAlarm (sig)
8003 frameWaiting = False;
8004 /* In case System-V style signals. Needed?? */
8005 signal(SIGALRM, FrameAlarm);
8012 struct itimerval delay;
8014 XSync(xDisplay, False);
8017 frameWaiting = True;
8018 signal(SIGALRM, FrameAlarm);
8019 delay.it_interval.tv_sec =
8020 delay.it_value.tv_sec = time / 1000;
8021 delay.it_interval.tv_usec =
8022 delay.it_value.tv_usec = (time % 1000) * 1000;
8023 setitimer(ITIMER_REAL, &delay, NULL);
8024 while (frameWaiting) pause();
8025 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8026 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8027 setitimer(ITIMER_REAL, &delay, NULL);
8037 XSync(xDisplay, False);
8039 usleep(time * 1000);
8044 /* Convert board position to corner of screen rect and color */
8047 ScreenSquare(column, row, pt, color)
8048 int column; int row; XPoint * pt; int * color;
8051 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8052 pt->y = lineGap + row * (squareSize + lineGap);
8054 pt->x = lineGap + column * (squareSize + lineGap);
8055 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8057 *color = SquareColor(row, column);
8060 /* Convert window coords to square */
8063 BoardSquare(x, y, column, row)
8064 int x; int y; int * column; int * row;
8066 *column = EventToSquare(x, BOARD_WIDTH);
8067 if (flipView && *column >= 0)
8068 *column = BOARD_WIDTH - 1 - *column;
8069 *row = EventToSquare(y, BOARD_HEIGHT);
8070 if (!flipView && *row >= 0)
8071 *row = BOARD_HEIGHT - 1 - *row;
8076 #undef Max /* just in case */
8078 #define Max(a, b) ((a) > (b) ? (a) : (b))
8079 #define Min(a, b) ((a) < (b) ? (a) : (b))
8082 SetRect(rect, x, y, width, height)
8083 XRectangle * rect; int x; int y; int width; int height;
8087 rect->width = width;
8088 rect->height = height;
8091 /* Test if two frames overlap. If they do, return
8092 intersection rect within old and location of
8093 that rect within new. */
8096 Intersect(old, new, size, area, pt)
8097 XPoint * old; XPoint * new;
8098 int size; XRectangle * area; XPoint * pt;
8100 if (old->x > new->x + size || new->x > old->x + size ||
8101 old->y > new->y + size || new->y > old->y + size) {
8104 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8105 size - abs(old->x - new->x), size - abs(old->y - new->y));
8106 pt->x = Max(old->x - new->x, 0);
8107 pt->y = Max(old->y - new->y, 0);
8112 /* For two overlapping frames, return the rect(s)
8113 in the old that do not intersect with the new. */
8116 CalcUpdateRects(old, new, size, update, nUpdates)
8117 XPoint * old; XPoint * new; int size;
8118 XRectangle update[]; int * nUpdates;
8122 /* If old = new (shouldn't happen) then nothing to draw */
8123 if (old->x == new->x && old->y == new->y) {
8127 /* Work out what bits overlap. Since we know the rects
8128 are the same size we don't need a full intersect calc. */
8130 /* Top or bottom edge? */
8131 if (new->y > old->y) {
8132 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8134 } else if (old->y > new->y) {
8135 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8136 size, old->y - new->y);
8139 /* Left or right edge - don't overlap any update calculated above. */
8140 if (new->x > old->x) {
8141 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8142 new->x - old->x, size - abs(new->y - old->y));
8144 } else if (old->x > new->x) {
8145 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8146 old->x - new->x, size - abs(new->y - old->y));
8153 /* Generate a series of frame coords from start->mid->finish.
8154 The movement rate doubles until the half way point is
8155 reached, then halves back down to the final destination,
8156 which gives a nice slow in/out effect. The algorithmn
8157 may seem to generate too many intermediates for short
8158 moves, but remember that the purpose is to attract the
8159 viewers attention to the piece about to be moved and
8160 then to where it ends up. Too few frames would be less
8164 Tween(start, mid, finish, factor, frames, nFrames)
8165 XPoint * start; XPoint * mid;
8166 XPoint * finish; int factor;
8167 XPoint frames[]; int * nFrames;
8169 int fraction, n, count;
8173 /* Slow in, stepping 1/16th, then 1/8th, ... */
8175 for (n = 0; n < factor; n++)
8177 for (n = 0; n < factor; n++) {
8178 frames[count].x = start->x + (mid->x - start->x) / fraction;
8179 frames[count].y = start->y + (mid->y - start->y) / fraction;
8181 fraction = fraction / 2;
8185 frames[count] = *mid;
8188 /* Slow out, stepping 1/2, then 1/4, ... */
8190 for (n = 0; n < factor; n++) {
8191 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8192 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8194 fraction = fraction * 2;
8199 /* Draw a piece on the screen without disturbing what's there */
8202 SelectGCMask(piece, clip, outline, mask)
8203 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8207 /* Bitmap for piece being moved. */
8208 if (appData.monoMode) {
8209 *mask = *pieceToSolid(piece);
8210 } else if (useImages) {
8212 *mask = xpmMask[piece];
8214 *mask = ximMaskPm[piece];
8217 *mask = *pieceToSolid(piece);
8220 /* GC for piece being moved. Square color doesn't matter, but
8221 since it gets modified we make a copy of the original. */
8223 if (appData.monoMode)
8228 if (appData.monoMode)
8233 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8235 /* Outline only used in mono mode and is not modified */
8237 *outline = bwPieceGC;
8239 *outline = wbPieceGC;
8243 OverlayPiece(piece, clip, outline, dest)
8244 ChessSquare piece; GC clip; GC outline; Drawable dest;
8249 /* Draw solid rectangle which will be clipped to shape of piece */
8250 XFillRectangle(xDisplay, dest, clip,
8251 0, 0, squareSize, squareSize);
8252 if (appData.monoMode)
8253 /* Also draw outline in contrasting color for black
8254 on black / white on white cases */
8255 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8256 0, 0, squareSize, squareSize, 0, 0, 1);
8258 /* Copy the piece */
8263 if(appData.upsideDown && flipView) kind ^= 2;
8264 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8266 0, 0, squareSize, squareSize,
8271 /* Animate the movement of a single piece */
8274 BeginAnimation(anim, piece, startColor, start)
8282 if(appData.upsideDown && flipView) piece += piece < BlackPawn ? BlackPawn : -BlackPawn;
8283 /* The old buffer is initialised with the start square (empty) */
8284 BlankSquare(start->x, start->y, startColor, EmptySquare, anim->saveBuf, 0);
8285 anim->prevFrame = *start;
8287 /* The piece will be drawn using its own bitmap as a matte */
8288 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8289 XSetClipMask(xDisplay, anim->pieceGC, mask);
8293 AnimationFrame(anim, frame, piece)
8298 XRectangle updates[4];
8303 /* Save what we are about to draw into the new buffer */
8304 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8305 frame->x, frame->y, squareSize, squareSize,
8308 /* Erase bits of the previous frame */
8309 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8310 /* Where the new frame overlapped the previous,
8311 the contents in newBuf are wrong. */
8312 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8313 overlap.x, overlap.y,
8314 overlap.width, overlap.height,
8316 /* Repaint the areas in the old that don't overlap new */
8317 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8318 for (i = 0; i < count; i++)
8319 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8320 updates[i].x - anim->prevFrame.x,
8321 updates[i].y - anim->prevFrame.y,
8322 updates[i].width, updates[i].height,
8323 updates[i].x, updates[i].y);
8325 /* Easy when no overlap */
8326 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8327 0, 0, squareSize, squareSize,
8328 anim->prevFrame.x, anim->prevFrame.y);
8331 /* Save this frame for next time round */
8332 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8333 0, 0, squareSize, squareSize,
8335 anim->prevFrame = *frame;
8337 /* Draw piece over original screen contents, not current,
8338 and copy entire rect. Wipes out overlapping piece images. */
8339 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8340 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8341 0, 0, squareSize, squareSize,
8342 frame->x, frame->y);
8346 EndAnimation (anim, finish)
8350 XRectangle updates[4];
8355 /* The main code will redraw the final square, so we
8356 only need to erase the bits that don't overlap. */
8357 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8358 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8359 for (i = 0; i < count; i++)
8360 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8361 updates[i].x - anim->prevFrame.x,
8362 updates[i].y - anim->prevFrame.y,
8363 updates[i].width, updates[i].height,
8364 updates[i].x, updates[i].y);
8366 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8367 0, 0, squareSize, squareSize,
8368 anim->prevFrame.x, anim->prevFrame.y);
8373 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8375 ChessSquare piece; int startColor;
8376 XPoint * start; XPoint * finish;
8377 XPoint frames[]; int nFrames;
8381 BeginAnimation(anim, piece, startColor, start);
8382 for (n = 0; n < nFrames; n++) {
8383 AnimationFrame(anim, &(frames[n]), piece);
8384 FrameDelay(appData.animSpeed);
8386 EndAnimation(anim, finish);
8390 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
8393 ChessSquare piece = board[fromY][toY];
8394 board[fromY][toY] = EmptySquare;
8395 DrawPosition(FALSE, board);
8397 x = lineGap + ((BOARD_WIDTH-1)-toX) * (squareSize + lineGap);
8398 y = lineGap + toY * (squareSize + lineGap);
8400 x = lineGap + toX * (squareSize + lineGap);
8401 y = lineGap + ((BOARD_HEIGHT-1)-toY) * (squareSize + lineGap);
8403 for(i=1; i<4*kFactor; i++) {
8404 int r = squareSize * 9 * i/(20*kFactor - 5);
8405 XFillArc(xDisplay, xBoardWindow, highlineGC,
8406 x + squareSize/2 - r, y+squareSize/2 - r, 2*r, 2*r, 0, 64*360);
8407 FrameDelay(appData.animSpeed);
8409 board[fromY][toY] = piece;
8412 /* Main control logic for deciding what to animate and how */
8415 AnimateMove(board, fromX, fromY, toX, toY)
8424 XPoint start, finish, mid;
8425 XPoint frames[kFactor * 2 + 1];
8426 int nFrames, startColor, endColor;
8428 /* Are we animating? */
8429 if (!appData.animate || appData.blindfold)
8432 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8433 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8434 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8436 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8437 piece = board[fromY][fromX];
8438 if (piece >= EmptySquare) return;
8443 hop = abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1;
8446 if (appData.debugMode) {
8447 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8448 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8449 piece, fromX, fromY, toX, toY); }
8451 ScreenSquare(fromX, fromY, &start, &startColor);
8452 ScreenSquare(toX, toY, &finish, &endColor);
8455 /* Knight: make straight movement then diagonal */
8456 if (abs(toY - fromY) < abs(toX - fromX)) {
8457 mid.x = start.x + (finish.x - start.x) / 2;
8461 mid.y = start.y + (finish.y - start.y) / 2;
8464 mid.x = start.x + (finish.x - start.x) / 2;
8465 mid.y = start.y + (finish.y - start.y) / 2;
8468 /* Don't use as many frames for very short moves */
8469 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8470 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8472 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8473 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8474 if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged
8476 for(i=0; i<BOARD_WIDTH; i++) for(j=0; j<BOARD_HEIGHT; j++)
8477 if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] = True;
8480 /* Be sure end square is redrawn */
8481 damage[0][toY][toX] = True;
8485 DragPieceBegin(x, y)
8488 int boardX, boardY, color;
8491 /* Are we animating? */
8492 if (!appData.animateDragging || appData.blindfold)
8495 /* Figure out which square we start in and the
8496 mouse position relative to top left corner. */
8497 BoardSquare(x, y, &boardX, &boardY);
8498 player.startBoardX = boardX;
8499 player.startBoardY = boardY;
8500 ScreenSquare(boardX, boardY, &corner, &color);
8501 player.startSquare = corner;
8502 player.startColor = color;
8503 /* As soon as we start dragging, the piece will jump slightly to
8504 be centered over the mouse pointer. */
8505 player.mouseDelta.x = squareSize/2;
8506 player.mouseDelta.y = squareSize/2;
8507 /* Initialise animation */
8508 player.dragPiece = PieceForSquare(boardX, boardY);
8510 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8511 player.dragActive = True;
8512 BeginAnimation(&player, player.dragPiece, color, &corner);
8513 /* Mark this square as needing to be redrawn. Note that
8514 we don't remove the piece though, since logically (ie
8515 as seen by opponent) the move hasn't been made yet. */
8516 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8517 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8518 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8519 corner.x, corner.y, squareSize, squareSize,
8520 0, 0); // [HGM] zh: unstack in stead of grab
8521 if(gatingPiece != EmptySquare) {
8522 /* Kludge alert: When gating we want the introduced
8523 piece to appear on the from square. To generate an
8524 image of it, we draw it on the board, copy the image,
8525 and draw the original piece again. */
8526 ChessSquare piece = boards[currentMove][boardY][boardX];
8527 DrawSquare(boardY, boardX, gatingPiece, 0);
8528 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8529 corner.x, corner.y, squareSize, squareSize, 0, 0);
8530 DrawSquare(boardY, boardX, piece, 0);
8532 damage[0][boardY][boardX] = True;
8534 player.dragActive = False;
8544 /* Are we animating? */
8545 if (!appData.animateDragging || appData.blindfold)
8549 if (! player.dragActive)
8551 /* Move piece, maintaining same relative position
8552 of mouse within square */
8553 corner.x = x - player.mouseDelta.x;
8554 corner.y = y - player.mouseDelta.y;
8555 AnimationFrame(&player, &corner, player.dragPiece);
8557 if (appData.highlightDragging) {
8559 BoardSquare(x, y, &boardX, &boardY);
8560 SetHighlights(fromX, fromY, boardX, boardY);
8569 int boardX, boardY, color;
8572 /* Are we animating? */
8573 if (!appData.animateDragging || appData.blindfold)
8577 if (! player.dragActive)
8579 /* Last frame in sequence is square piece is
8580 placed on, which may not match mouse exactly. */
8581 BoardSquare(x, y, &boardX, &boardY);
8582 ScreenSquare(boardX, boardY, &corner, &color);
8583 EndAnimation(&player, &corner);
8585 /* Be sure end square is redrawn */
8586 damage[0][boardY][boardX] = True;
8588 /* This prevents weird things happening with fast successive
8589 clicks which on my Sun at least can cause motion events
8590 without corresponding press/release. */
8591 player.dragActive = False;
8594 /* Handle expose event while piece being dragged */
8599 if (!player.dragActive || appData.blindfold)
8602 /* What we're doing: logically, the move hasn't been made yet,
8603 so the piece is still in it's original square. But visually
8604 it's being dragged around the board. So we erase the square
8605 that the piece is on and draw it at the last known drag point. */
8606 BlankSquare(player.startSquare.x, player.startSquare.y,
8607 player.startColor, EmptySquare, xBoardWindow, 1);
8608 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8609 damage[0][player.startBoardY][player.startBoardX] = TRUE;
8612 #include <sys/ioctl.h>
8613 int get_term_width()
8615 int fd, default_width;
8618 default_width = 79; // this is FICS default anyway...
8620 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8622 if (!ioctl(fd, TIOCGSIZE, &win))
8623 default_width = win.ts_cols;
8624 #elif defined(TIOCGWINSZ)
8626 if (!ioctl(fd, TIOCGWINSZ, &win))
8627 default_width = win.ws_col;
8629 return default_width;
8635 static int old_width = 0;
8636 int new_width = get_term_width();
8638 if (old_width != new_width)
8639 ics_printf("set width %d\n", new_width);
8640 old_width = new_width;
8643 void NotifyFrontendLogin()
8648 /* [AS] Arrow highlighting support */
8650 static double A_WIDTH = 5; /* Width of arrow body */
8652 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
8653 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
8655 static double Sqr( double x )
8660 static int Round( double x )
8662 return (int) (x + 0.5);
8665 void SquareToPos(int rank, int file, int *x, int *y)
8668 *x = lineGap + ((BOARD_WIDTH-1)-file) * (squareSize + lineGap);
8669 *y = lineGap + rank * (squareSize + lineGap);
8671 *x = lineGap + file * (squareSize + lineGap);
8672 *y = lineGap + ((BOARD_HEIGHT-1)-rank) * (squareSize + lineGap);
8676 /* Draw an arrow between two points using current settings */
8677 void DrawArrowBetweenPoints( int s_x, int s_y, int d_x, int d_y )
8680 double dx, dy, j, k, x, y;
8683 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
8685 arrow[0].x = s_x + A_WIDTH + 0.5;
8688 arrow[1].x = s_x + A_WIDTH + 0.5;
8689 arrow[1].y = d_y - h;
8691 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8692 arrow[2].y = d_y - h;
8697 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
8698 arrow[5].y = d_y - h;
8700 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8701 arrow[4].y = d_y - h;
8703 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
8706 else if( d_y == s_y ) {
8707 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
8710 arrow[0].y = s_y + A_WIDTH + 0.5;
8712 arrow[1].x = d_x - w;
8713 arrow[1].y = s_y + A_WIDTH + 0.5;
8715 arrow[2].x = d_x - w;
8716 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8721 arrow[5].x = d_x - w;
8722 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
8724 arrow[4].x = d_x - w;
8725 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8728 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
8731 /* [AS] Needed a lot of paper for this! :-) */
8732 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
8733 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
8735 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
8737 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
8742 arrow[0].x = Round(x - j);
8743 arrow[0].y = Round(y + j*dx);
8745 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
8746 arrow[1].y = Round(arrow[0].y - 2*j*dx);
8749 x = (double) d_x - k;
8750 y = (double) d_y - k*dy;
8753 x = (double) d_x + k;
8754 y = (double) d_y + k*dy;
8757 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
8759 arrow[6].x = Round(x - j);
8760 arrow[6].y = Round(y + j*dx);
8762 arrow[2].x = Round(arrow[6].x + 2*j);
8763 arrow[2].y = Round(arrow[6].y - 2*j*dx);
8765 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
8766 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
8771 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
8772 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
8775 XFillPolygon(xDisplay, xBoardWindow, highlineGC, arrow, 7, Nonconvex, CoordModeOrigin);
8776 // Polygon( hdc, arrow, 7 );
8779 /* [AS] Draw an arrow between two squares */
8780 void DrawArrowBetweenSquares( int s_col, int s_row, int d_col, int d_row )
8782 int s_x, s_y, d_x, d_y, hor, vert, i;
8784 if( s_col == d_col && s_row == d_row ) {
8788 /* Get source and destination points */
8789 SquareToPos( s_row, s_col, &s_x, &s_y);
8790 SquareToPos( d_row, d_col, &d_x, &d_y);
8793 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
8795 else if( d_y < s_y ) {
8796 d_y += squareSize / 2 + squareSize / 4;
8799 d_y += squareSize / 2;
8803 d_x += squareSize / 2 - squareSize / 4;
8805 else if( d_x < s_x ) {
8806 d_x += squareSize / 2 + squareSize / 4;
8809 d_x += squareSize / 2;
8812 s_x += squareSize / 2;
8813 s_y += squareSize / 2;
8816 A_WIDTH = squareSize / 14.; //[HGM] make float
8818 DrawArrowBetweenPoints( s_x, s_y, d_x, d_y );
8820 hor = 64*s_col + 32; vert = 64*s_row + 32;
8821 for(i=0; i<= 64; i++) {
8822 damage[0][vert+6>>6][hor+6>>6] = True;
8823 damage[0][vert-6>>6][hor+6>>6] = True;
8824 damage[0][vert+6>>6][hor-6>>6] = True;
8825 damage[0][vert-6>>6][hor-6>>6] = True;
8826 hor += d_col - s_col; vert += d_row - s_row;
8830 Boolean IsDrawArrowEnabled()
8832 return appData.highlightMoveWithArrow && squareSize >= 32;
8835 void DrawArrowHighlight(int fromX, int fromY, int toX,int toY)
8837 if( IsDrawArrowEnabled() && fromX >= 0 && fromY >= 0 && toX >= 0 && toY >= 0)
8838 DrawArrowBetweenSquares(fromX, fromY, toX, toY);