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
149 #include <X11/Intrinsic.h>
150 #include <X11/StringDefs.h>
151 #include <X11/Shell.h>
152 #include <X11/cursorfont.h>
153 #include <X11/Xatom.h>
154 #include <X11/Xmu/Atoms.h>
156 #include <X11/Xaw3d/Dialog.h>
157 #include <X11/Xaw3d/Form.h>
158 #include <X11/Xaw3d/List.h>
159 #include <X11/Xaw3d/Label.h>
160 #include <X11/Xaw3d/SimpleMenu.h>
161 #include <X11/Xaw3d/SmeBSB.h>
162 #include <X11/Xaw3d/SmeLine.h>
163 #include <X11/Xaw3d/Box.h>
164 #include <X11/Xaw3d/MenuButton.h>
165 #include <X11/Xaw3d/Text.h>
166 #include <X11/Xaw3d/AsciiText.h>
168 #include <X11/Xaw/Dialog.h>
169 #include <X11/Xaw/Form.h>
170 #include <X11/Xaw/List.h>
171 #include <X11/Xaw/Label.h>
172 #include <X11/Xaw/SimpleMenu.h>
173 #include <X11/Xaw/SmeBSB.h>
174 #include <X11/Xaw/SmeLine.h>
175 #include <X11/Xaw/Box.h>
176 #include <X11/Xaw/MenuButton.h>
177 #include <X11/Xaw/Text.h>
178 #include <X11/Xaw/AsciiText.h>
181 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
186 #include "pixmaps/pixmaps.h"
187 #define IMAGE_EXT "xpm"
189 #define IMAGE_EXT "xim"
190 #include "bitmaps/bitmaps.h"
193 #include "bitmaps/icon_white.bm"
194 #include "bitmaps/icon_black.bm"
195 #include "bitmaps/checkmark.bm"
197 #include "frontend.h"
199 #include "backendz.h"
203 #include "xgamelist.h"
204 #include "xhistory.h"
205 #include "xedittags.h"
208 // must be moved to xengineoutput.h
210 void EngineOutputProc P((Widget w, XEvent *event,
211 String *prms, Cardinal *nprms));
212 void EvalGraphProc P((Widget w, XEvent *event,
213 String *prms, Cardinal *nprms));
220 #define usleep(t) _sleep2(((t)+500)/1000)
224 # define _(s) gettext (s)
225 # define N_(s) gettext_noop (s)
243 int main P((int argc, char **argv));
244 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
245 char *init_path, char *filter, char *mode, int (*show_entry)(), char **name_return));
246 RETSIGTYPE CmailSigHandler P((int sig));
247 RETSIGTYPE IntSigHandler P((int sig));
248 RETSIGTYPE TermSizeSigHandler P((int sig));
249 void CreateGCs P((int redo));
250 void CreateAnyPieces P((void));
251 void CreateXIMPieces P((void));
252 void CreateXPMPieces P((void));
253 void CreateXPMBoard P((char *s, int n));
254 void CreatePieces P((void));
255 void CreatePieceMenus P((void));
256 Widget CreateMenuBar P((Menu *mb));
257 Widget CreateButtonBar P ((MenuItem *mi));
259 char *InsertPxlSize P((char *pattern, int targetPxlSize));
260 XFontSet CreateFontSet P((char *base_fnt_lst));
262 char *FindFont P((char *pattern, int targetPxlSize));
264 void PieceMenuPopup P((Widget w, XEvent *event,
265 String *params, Cardinal *num_params));
266 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
267 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
268 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
269 u_int wreq, u_int hreq));
270 void CreateGrid P((void));
271 int EventToSquare P((int x, int limit));
272 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
273 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
274 void MoveTypeInProc P((Widget widget, caddr_t unused, XEvent *event));
275 void HandleUserMove P((Widget w, XEvent *event,
276 String *prms, Cardinal *nprms));
277 void AnimateUserMove P((Widget w, XEvent * event,
278 String * params, Cardinal * nParams));
279 void HandlePV P((Widget w, XEvent * event,
280 String * params, Cardinal * nParams));
281 void SelectPV P((Widget w, XEvent * event,
282 String * params, Cardinal * nParams));
283 void StopPV P((Widget w, XEvent * event,
284 String * params, Cardinal * nParams));
285 void WhiteClock P((Widget w, XEvent *event,
286 String *prms, Cardinal *nprms));
287 void BlackClock P((Widget w, XEvent *event,
288 String *prms, Cardinal *nprms));
289 void DrawPositionProc P((Widget w, XEvent *event,
290 String *prms, Cardinal *nprms));
291 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
293 void CommentClick P((Widget w, XEvent * event,
294 String * params, Cardinal * nParams));
295 void CommentPopUp P((char *title, char *label));
296 void CommentPopDown P((void));
297 void ICSInputBoxPopUp P((void));
298 void ICSInputBoxPopDown P((void));
299 void FileNamePopUp P((char *label, char *def, char *filter,
300 FileProc proc, char *openMode));
301 void FileNamePopDown P((void));
302 void FileNameCallback P((Widget w, XtPointer client_data,
303 XtPointer call_data));
304 void FileNameAction P((Widget w, XEvent *event,
305 String *prms, Cardinal *nprms));
306 void AskQuestionReplyAction P((Widget w, XEvent *event,
307 String *prms, Cardinal *nprms));
308 void AskQuestionProc P((Widget w, XEvent *event,
309 String *prms, Cardinal *nprms));
310 void AskQuestionPopDown P((void));
311 void PromotionPopDown P((void));
312 void PromotionCallback P((Widget w, XtPointer client_data,
313 XtPointer call_data));
314 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
315 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
316 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
317 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
319 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
321 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
323 void LoadPositionProc P((Widget w, XEvent *event,
324 String *prms, Cardinal *nprms));
325 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
327 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
329 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
331 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
333 void PastePositionProc P((Widget w, XEvent *event, String *prms,
335 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
336 void CopyGameListProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
337 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
338 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
339 void SavePositionProc P((Widget w, XEvent *event,
340 String *prms, Cardinal *nprms));
341 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
342 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
344 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
345 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
346 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
348 void MachineWhiteProc P((Widget w, XEvent *event,
349 String *prms, Cardinal *nprms));
350 void AnalyzeModeProc P((Widget w, XEvent *event,
351 String *prms, Cardinal *nprms));
352 void AnalyzeFileProc P((Widget w, XEvent *event,
353 String *prms, Cardinal *nprms));
354 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
356 void MatchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
357 void MatchOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
358 void IcsClientProc P((Widget w, XEvent *event, String *prms,
360 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void EditPositionProc P((Widget w, XEvent *event,
362 String *prms, Cardinal *nprms));
363 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void EditCommentProc P((Widget w, XEvent *event,
365 String *prms, Cardinal *nprms));
366 void IcsInputBoxProc P((Widget w, XEvent *event,
367 String *prms, Cardinal *nprms));
368 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
369 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
370 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
371 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
372 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
373 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
374 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
375 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
376 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
377 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
379 void TypeInProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
380 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void StopObservingProc P((Widget w, XEvent *event, String *prms,
385 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
387 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
388 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
389 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
390 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
391 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
392 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
393 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
394 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
396 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
398 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
399 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
401 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
403 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
405 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
406 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
407 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
408 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
410 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
411 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
413 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
415 void HighlightArrowProc P((Widget w, XEvent *event, String *prms,
417 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
418 //void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
419 void OneClickProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
420 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
422 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
424 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
426 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
428 //void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
429 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
431 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
433 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
435 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
437 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
442 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
443 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
444 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
445 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
446 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
447 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
448 void DisplayMove P((int moveNumber));
449 void DisplayTitle P((char *title));
450 void ICSInitScript P((void));
451 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
452 void ErrorPopUp P((char *title, char *text, int modal));
453 void ErrorPopDown P((void));
454 static char *ExpandPathName P((char *path));
455 static void CreateAnimVars P((void));
456 static void DragPieceMove P((int x, int y));
457 static void DrawDragPiece P((void));
458 char *ModeToWidgetName P((GameMode mode));
459 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
460 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
461 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
462 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
463 void OptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
464 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
465 void IcsTextProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
466 void LoadEngineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
467 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
468 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
469 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
470 void IcsOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
471 void SoundOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
472 void BoardOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
473 void LoadOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
474 void SaveOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
475 void EditBookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
476 void SelectMove P((Widget w, XEvent * event, String * params, Cardinal * nParams));
477 void GameListOptionsPopDown P(());
478 void GenericPopDown P(());
479 void update_ics_width P(());
480 int get_term_width P(());
481 int CopyMemoProc P(());
482 void DrawArrowHighlight P((int fromX, int fromY, int toX,int toY));
483 Boolean IsDrawArrowEnabled P(());
486 * XBoard depends on Xt R4 or higher
488 int xtVersion = XtSpecificationRelease;
493 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
494 jailSquareColor, highlightSquareColor, premoveHighlightColor;
495 Pixel lowTimeWarningColor;
496 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
497 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
498 wjPieceGC, bjPieceGC, prelineGC, countGC;
499 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
500 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
501 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
502 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
503 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
504 ICSInputShell, fileNameShell, askQuestionShell;
505 Widget historyShell, evalGraphShell, gameListShell;
506 int hOffset; // [HGM] dual
507 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
508 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
509 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
511 XFontSet fontSet, clockFontSet;
514 XFontStruct *clockFontStruct;
516 Font coordFontID, countFontID;
517 XFontStruct *coordFontStruct, *countFontStruct;
518 XtAppContext appContext;
520 char *oldICSInteractionTitle;
524 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
526 Position commentX = -1, commentY = -1;
527 Dimension commentW, commentH;
528 typedef unsigned int BoardSize;
530 Boolean chessProgram;
532 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
533 int squareSize, smallLayout = 0, tinyLayout = 0,
534 marginW, marginH, // [HGM] for run-time resizing
535 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
536 ICSInputBoxUp = False, askQuestionUp = False,
537 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
538 errorUp = False, errorExitStatus = -1, lineGap, defaultLineGap;
539 Pixel timerForegroundPixel, timerBackgroundPixel;
540 Pixel buttonForegroundPixel, buttonBackgroundPixel;
541 char *chessDir, *programName, *programVersion,
542 *gameCopyFilename, *gamePasteFilename;
543 Boolean alwaysOnTop = False;
544 Boolean saveSettingsOnExit;
545 char *settingsFileName;
546 char *icsTextMenuString;
548 char *firstChessProgramNames;
549 char *secondChessProgramNames;
551 WindowPlacement wpMain;
552 WindowPlacement wpConsole;
553 WindowPlacement wpComment;
554 WindowPlacement wpMoveHistory;
555 WindowPlacement wpEvalGraph;
556 WindowPlacement wpEngineOutput;
557 WindowPlacement wpGameList;
558 WindowPlacement wpTags;
560 extern Widget shells[];
561 extern Boolean shellUp[];
565 Pixmap pieceBitmap[2][(int)BlackPawn];
566 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
567 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
568 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
569 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
570 Pixmap xpmBoardBitmap[2];
571 int useImages, useImageSqs, useTexture, textureW[2], textureH[2];
572 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
573 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
574 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
575 XImage *ximLightSquare, *ximDarkSquare;
578 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
579 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
581 #define White(piece) ((int)(piece) < (int)BlackPawn)
583 /* Variables for doing smooth animation. This whole thing
584 would be much easier if the board was double-buffered,
585 but that would require a fairly major rewrite. */
590 GC blitGC, pieceGC, outlineGC;
591 XPoint startSquare, prevFrame, mouseDelta;
595 int startBoardX, startBoardY;
598 /* There can be two pieces being animated at once: a player
599 can begin dragging a piece before the remote opponent has moved. */
601 static AnimState game, player;
603 /* Bitmaps for use as masks when drawing XPM pieces.
604 Need one for each black and white piece. */
605 static Pixmap xpmMask[BlackKing + 1];
607 /* This magic number is the number of intermediate frames used
608 in each half of the animation. For short moves it's reduced
609 by 1. The total number of frames will be factor * 2 + 1. */
612 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
614 MenuItem fileMenu[] = {
615 {N_("New Game Ctrl+N"), "New Game", ResetProc},
616 {N_("New Shuffle Game ..."), "New Shuffle Game", ShuffleMenuProc},
617 {N_("New Variant ... Alt+Shift+V"), "New Variant", NewVariantProc}, // [HGM] variant: not functional yet
618 {"----", NULL, NothingProc},
619 {N_("Load Game Ctrl+O"), "Load Game", LoadGameProc},
620 {N_("Load Position Ctrl+Shift+O"), "Load Position", LoadPositionProc},
621 // {N_("Load Next Game"), "Load Next Game", LoadNextGameProc},
622 // {N_("Load Previous Game"), "Load Previous Game", LoadPrevGameProc},
623 // {N_("Reload Same Game"), "Reload Same Game", ReloadGameProc},
624 {N_("Next Position Shift+PgDn"), "Load Next Position", LoadNextPositionProc},
625 {N_("Prev Position Shift+PgUp"), "Load Previous Position", LoadPrevPositionProc},
626 {"----", NULL, NothingProc},
627 // {N_("Reload Same Position"), "Reload Same Position", ReloadPositionProc},
628 {N_("Save Game Ctrl+S"), "Save Game", SaveGameProc},
629 {N_("Save Position Ctrl+Shift+S"), "Save Position", SavePositionProc},
630 {"----", NULL, NothingProc},
631 {N_("Mail Move"), "Mail Move", MailMoveProc},
632 {N_("Reload CMail Message"), "Reload CMail Message", ReloadCmailMsgProc},
633 {"----", NULL, NothingProc},
634 {N_("Quit Ctr+Q"), "Exit", QuitProc},
638 MenuItem editMenu[] = {
639 {N_("Copy Game Ctrl+C"), "Copy Game", CopyGameProc},
640 {N_("Copy Position Ctrl+Shift+C"), "Copy Position", CopyPositionProc},
641 {N_("Copy Game List"), "Copy Game List", CopyGameListProc},
642 {"----", NULL, NothingProc},
643 {N_("Paste Game Ctrl+V"), "Paste Game", PasteGameProc},
644 {N_("Paste Position Ctrl+Shift+V"), "Paste Position", PastePositionProc},
645 {"----", NULL, NothingProc},
646 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
647 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
648 {N_("Edit Tags"), "Edit Tags", EditTagsProc},
649 {N_("Edit Comment"), "Edit Comment", EditCommentProc},
650 {N_("Edit Book"), "Edit Book", EditBookProc},
651 {"----", NULL, NothingProc},
652 {N_("Revert Home"), "Revert", RevertProc},
653 {N_("Annotate"), "Annotate", AnnotateProc},
654 {N_("Truncate Game End"), "Truncate Game", TruncateGameProc},
655 {"----", NULL, NothingProc},
656 {N_("Backward Alt+Left"), "Backward", BackwardProc},
657 {N_("Forward Alt+Right"), "Forward", ForwardProc},
658 {N_("Back to Start Alt+Home"), "Back to Start", ToStartProc},
659 {N_("Forward to End Alt+End"), "Forward to End", ToEndProc},
663 MenuItem viewMenu[] = {
664 {N_("Flip View F2"), "Flip View", FlipViewProc},
665 {"----", NULL, NothingProc},
666 {N_("Engine Output Alt+Shift+O"), "Show Engine Output", EngineOutputProc},
667 {N_("Move History Alt+Shift+H"), "Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
668 {N_("Evaluation Graph Alt+Shift+E"), "Show Evaluation Graph", EvalGraphProc},
669 {N_("Game List Alt+Shift+G"), "Show Game List", ShowGameListProc},
670 {N_("ICS text menu"), "ICStex", IcsTextProc},
671 {"----", NULL, NothingProc},
672 {N_("Tags"), "Show Tags", EditTagsProc},
673 {N_("Comments"), "Show Comments", EditCommentProc},
674 {N_("ICS Input Box"), "ICS Input Box", IcsInputBoxProc},
675 {"----", NULL, NothingProc},
676 {N_("Board..."), "Board Options", BoardOptionsProc},
677 {N_("Game List Tags..."), "Game List", GameListOptionsPopUp},
681 MenuItem modeMenu[] = {
682 {N_("Machine White Ctrl+W"), "Machine White", MachineWhiteProc},
683 {N_("Machine Black Ctrl+B"), "Machine Black", MachineBlackProc},
684 {N_("Two Machines Ctrl+T"), "Two Machines", TwoMachinesProc},
685 {N_("Analysis Mode Ctrl+A"), "Analysis Mode", AnalyzeModeProc},
686 {N_("Analyze File Ctrl+F"), "Analyze File", AnalyzeFileProc },
687 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
688 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
689 {N_("Training"), "Training", TrainingProc},
690 {N_("ICS Client"), "ICS Client", IcsClientProc},
691 {"----", NULL, NothingProc},
692 {N_("Machine Match"), "Machine Match", MatchProc},
693 {N_("Pause Pause"), "Pause", PauseProc},
697 MenuItem actionMenu[] = {
698 {N_("Accept F3"), "Accept", AcceptProc},
699 {N_("Decline F4"), "Decline", DeclineProc},
700 {N_("Rematch F12"), "Rematch", RematchProc},
701 {"----", NULL, NothingProc},
702 {N_("Call Flag F5"), "Call Flag", CallFlagProc},
703 {N_("Draw F6"), "Draw", DrawProc},
704 {N_("Adjourn F7"), "Adjourn", AdjournProc},
705 {N_("Abort F8"),"Abort", AbortProc},
706 {N_("Resign F9"), "Resign", ResignProc},
707 {"----", NULL, NothingProc},
708 {N_("Stop Observing F10"), "Stop Observing", StopObservingProc},
709 {N_("Stop Examining F11"), "Stop Examining", StopExaminingProc},
710 {N_("Upload to Examine"), "Upload to Examine", UploadProc},
711 {"----", NULL, NothingProc},
712 {N_("Adjudicate to White"), "Adjudicate to White", AdjuWhiteProc},
713 {N_("Adjudicate to Black"), "Adjudicate to Black", AdjuBlackProc},
714 {N_("Adjudicate Draw"), "Adjudicate Draw", AdjuDrawProc},
718 MenuItem engineMenu[] = {
719 {N_("Load New Engine ..."), "Load Engine", LoadEngineProc},
720 {"----", NULL, NothingProc},
721 {N_("Engine #1 Settings ..."), "Engine #1 Settings", FirstSettingsProc},
722 {N_("Engine #2 Settings ..."), "Engine #2 Settings", SecondSettingsProc},
723 {"----", NULL, NothingProc},
724 {N_("Hint"), "Hint", HintProc},
725 {N_("Book"), "Book", BookProc},
726 {"----", NULL, NothingProc},
727 {N_("Move Now Ctrl+M"), "Move Now", MoveNowProc},
728 {N_("Retract Move Ctrl+X"), "Retract Move", RetractMoveProc},
732 MenuItem optionsMenu[] = {
733 #define OPTIONSDIALOG
735 {N_("General ..."), "General", OptionsProc},
737 {N_("Time Control ... Alt+Shift+T"), "Time Control", TimeControlProc},
738 {N_("Common Engine ... Alt+Shift+U"), "Common Engine", UciMenuProc},
739 {N_("Adjudications ... Alt+Shift+J"), "Adjudications", EngineMenuProc},
740 {N_("ICS ..."), "ICS", IcsOptionsProc},
741 {N_("Match ..."), "Match", MatchOptionsProc},
742 {N_("Load Game ..."), "Load Game", LoadOptionsProc},
743 {N_("Save Game ..."), "Save Game", SaveOptionsProc},
744 // {N_(" ..."), "", OptionsProc},
745 {N_("Game List ..."), "Game List", GameListOptionsPopUp},
746 {N_("Sounds ..."), "Sounds", SoundOptionsProc},
747 {"----", NULL, NothingProc},
748 #ifndef OPTIONSDIALOG
749 {N_("Always Queen Ctrl+Shift+Q"), "Always Queen", AlwaysQueenProc},
750 {N_("Animate Dragging"), "Animate Dragging", AnimateDraggingProc},
751 {N_("Animate Moving Ctrl+Shift+A"), "Animate Moving", AnimateMovingProc},
752 {N_("Auto Flag Ctrl+Shift+F"), "Auto Flag", AutoflagProc},
753 {N_("Auto Flip View"), "Auto Flip View", AutoflipProc},
754 {N_("Blindfold"), "Blindfold", BlindfoldProc},
755 {N_("Flash Moves"), "Flash Moves", FlashMovesProc},
757 {N_("Highlight Dragging"), "Highlight Dragging", HighlightDraggingProc},
759 {N_("Highlight Last Move"), "Highlight Last Move", HighlightLastMoveProc},
760 {N_("Highlight With Arrow"), "Arrow", HighlightArrowProc},
761 {N_("Move Sound"), "Move Sound", MoveSoundProc},
762 // {N_("ICS Alarm"), "ICS Alarm", IcsAlarmProc},
763 {N_("One-Click Moving"), "OneClick", OneClickProc},
764 {N_("Periodic Updates"), "Periodic Updates", PeriodicUpdatesProc},
765 {N_("Ponder Next Move Ctrl+Shift+P"), "Ponder Next Move", PonderNextMoveProc},
766 {N_("Popup Exit Message"), "Popup Exit Message", PopupExitMessageProc},
767 {N_("Popup Move Errors"), "Popup Move Errors", PopupMoveErrorsProc},
768 // {N_("Premove"), "Premove", PremoveProc},
769 {N_("Show Coords"), "Show Coords", ShowCoordsProc},
770 {N_("Hide Thinking Ctrl+Shift+H"), "Hide Thinking", HideThinkingProc},
771 {N_("Test Legality Ctrl+Shift+L"), "Test Legality", TestLegalityProc},
772 {"----", NULL, NothingProc},
774 {N_("Save Settings Now"), "Save Settings Now", SaveSettingsProc},
775 {N_("Save Settings on Exit"), "Save Settings on Exit", SaveOnExitProc},
779 MenuItem helpMenu[] = {
780 {N_("Info XBoard"), "Info XBoard", InfoProc},
781 {N_("Man XBoard F1"), "Man XBoard", ManProc},
782 {"----", NULL, NothingProc},
783 {N_("About XBoard"), "About XBoard", AboutProc},
788 {N_("File"), "File", fileMenu},
789 {N_("Edit"), "Edit", editMenu},
790 {N_("View"), "View", viewMenu},
791 {N_("Mode"), "Mode", modeMenu},
792 {N_("Action"), "Action", actionMenu},
793 {N_("Engine"), "Engine", engineMenu},
794 {N_("Options"), "Options", optionsMenu},
795 {N_("Help"), "Help", helpMenu},
799 #define PAUSE_BUTTON "P"
800 MenuItem buttonBar[] = {
801 {"<<", "<<", ToStartProc},
802 {"<", "<", BackwardProc},
803 {PAUSE_BUTTON, PAUSE_BUTTON, PauseProc},
804 {">", ">", ForwardProc},
805 {">>", ">>", ToEndProc},
809 #define PIECE_MENU_SIZE 18
810 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
811 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
812 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
813 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
814 N_("Empty square"), N_("Clear board") },
815 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
816 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
817 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
818 N_("Empty square"), N_("Clear board") }
820 /* must be in same order as pieceMenuStrings! */
821 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
822 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
823 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
824 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
825 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
826 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
827 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
828 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
829 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
832 #define DROP_MENU_SIZE 6
833 String dropMenuStrings[DROP_MENU_SIZE] = {
834 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
836 /* must be in same order as dropMenuStrings! */
837 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
838 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
839 WhiteRook, WhiteQueen
847 DropMenuEnables dmEnables[] = {
865 { XtNborderWidth, 0 },
866 { XtNdefaultDistance, 0 },
870 { XtNborderWidth, 0 },
871 { XtNresizable, (XtArgVal) True },
875 { XtNborderWidth, 0 },
881 { XtNjustify, (XtArgVal) XtJustifyRight },
882 { XtNlabel, (XtArgVal) "..." },
883 { XtNresizable, (XtArgVal) True },
884 { XtNresize, (XtArgVal) False }
887 Arg messageArgs[] = {
888 { XtNjustify, (XtArgVal) XtJustifyLeft },
889 { XtNlabel, (XtArgVal) "..." },
890 { XtNresizable, (XtArgVal) True },
891 { XtNresize, (XtArgVal) False }
895 { XtNborderWidth, 0 },
896 { XtNjustify, (XtArgVal) XtJustifyLeft }
899 XtResource clientResources[] = {
900 { "flashCount", "flashCount", XtRInt, sizeof(int),
901 XtOffset(AppDataPtr, flashCount), XtRImmediate,
902 (XtPointer) FLASH_COUNT },
905 XrmOptionDescRec shellOptions[] = {
906 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
907 { "-flash", "flashCount", XrmoptionNoArg, "3" },
908 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
911 XtActionsRec boardActions[] = {
912 { "DrawPosition", DrawPositionProc },
913 { "HandleUserMove", HandleUserMove },
914 { "AnimateUserMove", AnimateUserMove },
915 { "HandlePV", HandlePV },
916 { "SelectPV", SelectPV },
917 { "StopPV", StopPV },
918 { "FileNameAction", FileNameAction },
919 { "AskQuestionProc", AskQuestionProc },
920 { "AskQuestionReplyAction", AskQuestionReplyAction },
921 { "PieceMenuPopup", PieceMenuPopup },
922 { "WhiteClock", WhiteClock },
923 { "BlackClock", BlackClock },
924 { "Iconify", Iconify },
925 { "ResetProc", ResetProc },
926 { "NewVariantProc", NewVariantProc },
927 { "LoadGameProc", LoadGameProc },
928 { "LoadNextGameProc", LoadNextGameProc },
929 { "LoadPrevGameProc", LoadPrevGameProc },
930 { "LoadSelectedProc", LoadSelectedProc },
931 { "SetFilterProc", SetFilterProc },
932 { "ReloadGameProc", ReloadGameProc },
933 { "LoadPositionProc", LoadPositionProc },
934 { "LoadNextPositionProc", LoadNextPositionProc },
935 { "LoadPrevPositionProc", LoadPrevPositionProc },
936 { "ReloadPositionProc", ReloadPositionProc },
937 { "CopyPositionProc", CopyPositionProc },
938 { "PastePositionProc", PastePositionProc },
939 { "CopyGameProc", CopyGameProc },
940 { "CopyGameListProc", CopyGameListProc },
941 { "PasteGameProc", PasteGameProc },
942 { "SaveGameProc", SaveGameProc },
943 { "SavePositionProc", SavePositionProc },
944 { "MailMoveProc", MailMoveProc },
945 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
946 { "QuitProc", QuitProc },
947 { "MachineWhiteProc", MachineWhiteProc },
948 { "MachineBlackProc", MachineBlackProc },
949 { "AnalysisModeProc", AnalyzeModeProc },
950 { "AnalyzeFileProc", AnalyzeFileProc },
951 { "TwoMachinesProc", TwoMachinesProc },
952 { "IcsClientProc", IcsClientProc },
953 { "EditGameProc", EditGameProc },
954 { "EditPositionProc", EditPositionProc },
955 { "TrainingProc", EditPositionProc },
956 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
957 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
958 { "ShowGameListProc", ShowGameListProc },
959 { "ShowMoveListProc", HistoryShowProc},
960 { "EditTagsProc", EditCommentProc },
961 { "EditBookProc", EditBookProc },
962 { "EditCommentProc", EditCommentProc },
963 { "IcsInputBoxProc", IcsInputBoxProc },
964 { "PauseProc", PauseProc },
965 { "AcceptProc", AcceptProc },
966 { "DeclineProc", DeclineProc },
967 { "RematchProc", RematchProc },
968 { "CallFlagProc", CallFlagProc },
969 { "DrawProc", DrawProc },
970 { "AdjournProc", AdjournProc },
971 { "AbortProc", AbortProc },
972 { "ResignProc", ResignProc },
973 { "AdjuWhiteProc", AdjuWhiteProc },
974 { "AdjuBlackProc", AdjuBlackProc },
975 { "AdjuDrawProc", AdjuDrawProc },
976 { "TypeInProc", TypeInProc },
977 { "EnterKeyProc", EnterKeyProc },
978 { "UpKeyProc", UpKeyProc },
979 { "DownKeyProc", DownKeyProc },
980 { "StopObservingProc", StopObservingProc },
981 { "StopExaminingProc", StopExaminingProc },
982 { "UploadProc", UploadProc },
983 { "BackwardProc", BackwardProc },
984 { "ForwardProc", ForwardProc },
985 { "ToStartProc", ToStartProc },
986 { "ToEndProc", ToEndProc },
987 { "RevertProc", RevertProc },
988 { "AnnotateProc", AnnotateProc },
989 { "TruncateGameProc", TruncateGameProc },
990 { "MoveNowProc", MoveNowProc },
991 { "RetractMoveProc", RetractMoveProc },
992 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
993 { "UciMenuProc", (XtActionProc) UciMenuProc },
994 { "TimeControlProc", (XtActionProc) TimeControlProc },
995 { "FlipViewProc", FlipViewProc },
996 { "PonderNextMoveProc", PonderNextMoveProc },
997 #ifndef OPTIONSDIALOG
998 { "AlwaysQueenProc", AlwaysQueenProc },
999 { "AnimateDraggingProc", AnimateDraggingProc },
1000 { "AnimateMovingProc", AnimateMovingProc },
1001 { "AutoflagProc", AutoflagProc },
1002 { "AutoflipProc", AutoflipProc },
1003 { "BlindfoldProc", BlindfoldProc },
1004 { "FlashMovesProc", FlashMovesProc },
1006 { "HighlightDraggingProc", HighlightDraggingProc },
1008 { "HighlightLastMoveProc", HighlightLastMoveProc },
1009 // { "IcsAlarmProc", IcsAlarmProc },
1010 { "MoveSoundProc", MoveSoundProc },
1011 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
1012 { "PopupExitMessageProc", PopupExitMessageProc },
1013 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
1014 // { "PremoveProc", PremoveProc },
1015 { "ShowCoordsProc", ShowCoordsProc },
1016 { "ShowThinkingProc", ShowThinkingProc },
1017 { "HideThinkingProc", HideThinkingProc },
1018 { "TestLegalityProc", TestLegalityProc },
1020 { "SaveSettingsProc", SaveSettingsProc },
1021 { "SaveOnExitProc", SaveOnExitProc },
1022 { "InfoProc", InfoProc },
1023 { "ManProc", ManProc },
1024 { "HintProc", HintProc },
1025 { "BookProc", BookProc },
1026 { "AboutGameProc", AboutGameProc },
1027 { "AboutProc", AboutProc },
1028 { "DebugProc", DebugProc },
1029 { "NothingProc", NothingProc },
1030 { "CommentClick", (XtActionProc) CommentClick },
1031 { "CommentPopDown", (XtActionProc) CommentPopDown },
1032 { "TagsPopDown", (XtActionProc) TagsPopDown },
1033 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
1034 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
1035 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
1036 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
1037 { "GameListPopDown", (XtActionProc) GameListPopDown },
1038 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
1039 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1040 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1041 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1042 { "GenericPopDown", (XtActionProc) GenericPopDown },
1043 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1044 { "SelectMove", (XtActionProc) SelectMove },
1047 char globalTranslations[] =
1048 ":<Key>F9: ResignProc() \n \
1049 :Ctrl<Key>n: ResetProc() \n \
1050 :Meta<Key>V: NewVariantProc() \n \
1051 :Ctrl<Key>o: LoadGameProc() \n \
1052 :Meta<Key>Next: LoadNextGameProc() \n \
1053 :Meta<Key>Prior: LoadPrevGameProc() \n \
1054 :Ctrl<Key>s: SaveGameProc() \n \
1055 :Ctrl<Key>c: CopyGameProc() \n \
1056 :Ctrl<Key>v: PasteGameProc() \n \
1057 :Ctrl<Key>O: LoadPositionProc() \n \
1058 :Shift<Key>Next: LoadNextPositionProc() \n \
1059 :Shift<Key>Prior: LoadPrevPositionProc() \n \
1060 :Ctrl<Key>S: SavePositionProc() \n \
1061 :Ctrl<Key>C: CopyPositionProc() \n \
1062 :Ctrl<Key>V: PastePositionProc() \n \
1063 :Ctrl<Key>q: QuitProc() \n \
1064 :Ctrl<Key>w: MachineWhiteProc() \n \
1065 :Ctrl<Key>b: MachineBlackProc() \n \
1066 :Ctrl<Key>t: TwoMachinesProc() \n \
1067 :Ctrl<Key>a: AnalysisModeProc() \n \
1068 :Ctrl<Key>f: AnalyzeFileProc() \n \
1069 :Ctrl<Key>e: EditGameProc() \n \
1070 :Ctrl<Key>E: EditPositionProc() \n \
1071 :Meta<Key>O: EngineOutputProc() \n \
1072 :Meta<Key>E: EvalGraphProc() \n \
1073 :Meta<Key>G: ShowGameListProc() \n \
1074 :Meta<Key>H: ShowMoveListProc() \n \
1075 :<Key>Pause: PauseProc() \n \
1076 :<Key>F3: AcceptProc() \n \
1077 :<Key>F4: DeclineProc() \n \
1078 :<Key>F12: RematchProc() \n \
1079 :<Key>F5: CallFlagProc() \n \
1080 :<Key>F6: DrawProc() \n \
1081 :<Key>F7: AdjournProc() \n \
1082 :<Key>F8: AbortProc() \n \
1083 :<Key>F10: StopObservingProc() \n \
1084 :<Key>F11: StopExaminingProc() \n \
1085 :Meta Ctrl<Key>F12: DebugProc() \n \
1086 :Meta<Key>End: ToEndProc() \n \
1087 :Meta<Key>Right: ForwardProc() \n \
1088 :Meta<Key>Home: ToStartProc() \n \
1089 :Meta<Key>Left: BackwardProc() \n \
1090 :<Key>Left: BackwardProc() \n \
1091 :<Key>Right: ForwardProc() \n \
1092 :<Key>Home: RevertProc() \n \
1093 :<Key>End: TruncateGameProc() \n \
1094 :Ctrl<Key>m: MoveNowProc() \n \
1095 :Ctrl<Key>x: RetractMoveProc() \n \
1096 :Meta<Key>J: EngineMenuProc() \n \
1097 :Meta<Key>U: UciMenuProc() \n \
1098 :Meta<Key>T: TimeControlProc() \n \
1099 :Ctrl<Key>P: PonderNextMoveProc() \n "
1100 #ifndef OPTIONSDIALOG
1102 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1103 :Ctrl<Key>F: AutoflagProc() \n \
1104 :Ctrl<Key>A: AnimateMovingProc() \n \
1105 :Ctrl<Key>L: TestLegalityProc() \n \
1106 :Ctrl<Key>H: HideThinkingProc() \n "
1109 :<Key>-: Iconify() \n \
1110 :<Key>F1: ManProc() \n \
1111 :<Key>F2: FlipViewProc() \n \
1112 <KeyDown>.: BackwardProc() \n \
1113 <KeyUp>.: ForwardProc() \n \
1114 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1115 \"Send to chess program:\",,1) \n \
1116 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1117 \"Send to second chess program:\",,2) \n";
1119 char boardTranslations[] =
1120 "<Btn1Down>: HandleUserMove(0) \n \
1121 Shift<Btn1Up>: HandleUserMove(1) \n \
1122 <Btn1Up>: HandleUserMove(0) \n \
1123 <Btn1Motion>: AnimateUserMove() \n \
1124 <Btn3Motion>: HandlePV() \n \
1125 <Btn3Up>: PieceMenuPopup(menuB) \n \
1126 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1127 PieceMenuPopup(menuB) \n \
1128 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1129 PieceMenuPopup(menuW) \n \
1130 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1131 PieceMenuPopup(menuW) \n \
1132 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1133 PieceMenuPopup(menuB) \n";
1135 char whiteTranslations[] =
1136 "Shift<BtnDown>: WhiteClock(1)\n \
1137 <BtnDown>: WhiteClock(0)\n";
1138 char blackTranslations[] =
1139 "Shift<BtnDown>: BlackClock(1)\n \
1140 <BtnDown>: BlackClock(0)\n";
1142 char ICSInputTranslations[] =
1143 "<Key>Up: UpKeyProc() \n "
1144 "<Key>Down: DownKeyProc() \n "
1145 "<Key>Return: EnterKeyProc() \n";
1147 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1148 // as the widget is destroyed before the up-click can call extend-end
1149 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1151 String xboardResources[] = {
1152 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1153 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1154 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1159 /* Max possible square size */
1160 #define MAXSQSIZE 256
1162 static int xpm_avail[MAXSQSIZE];
1164 #ifdef HAVE_DIR_STRUCT
1166 /* Extract piece size from filename */
1168 xpm_getsize(name, len, ext)
1179 if ((p=strchr(name, '.')) == NULL ||
1180 StrCaseCmp(p+1, ext) != 0)
1186 while (*p && isdigit(*p))
1193 /* Setup xpm_avail */
1195 xpm_getavail(dirname, ext)
1203 for (i=0; i<MAXSQSIZE; ++i)
1206 if (appData.debugMode)
1207 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1209 dir = opendir(dirname);
1212 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1213 programName, dirname);
1217 while ((ent=readdir(dir)) != NULL) {
1218 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1219 if (i > 0 && i < MAXSQSIZE)
1229 xpm_print_avail(fp, ext)
1235 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1236 for (i=1; i<MAXSQSIZE; ++i) {
1242 /* Return XPM piecesize closest to size */
1244 xpm_closest_to(dirname, size, ext)
1250 int sm_diff = MAXSQSIZE;
1254 xpm_getavail(dirname, ext);
1256 if (appData.debugMode)
1257 xpm_print_avail(stderr, ext);
1259 for (i=1; i<MAXSQSIZE; ++i) {
1262 diff = (diff<0) ? -diff : diff;
1263 if (diff < sm_diff) {
1271 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1277 #else /* !HAVE_DIR_STRUCT */
1278 /* If we are on a system without a DIR struct, we can't
1279 read the directory, so we can't collect a list of
1280 filenames, etc., so we can't do any size-fitting. */
1282 xpm_closest_to(dirname, size, ext)
1287 fprintf(stderr, _("\
1288 Warning: No DIR structure found on this system --\n\
1289 Unable to autosize for XPM/XIM pieces.\n\
1290 Please report this error to %s.\n\
1291 Include system type & operating system in message.\n"), PACKAGE_BUGREPORT););
1294 #endif /* HAVE_DIR_STRUCT */
1296 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1297 "magenta", "cyan", "white" };
1301 TextColors textColors[(int)NColorClasses];
1303 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1305 parse_color(str, which)
1309 char *p, buf[100], *d;
1312 if (strlen(str) > 99) /* watch bounds on buf */
1317 for (i=0; i<which; ++i) {
1324 /* Could be looking at something like:
1326 .. in which case we want to stop on a comma also */
1327 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1331 return -1; /* Use default for empty field */
1334 if (which == 2 || isdigit(*p))
1337 while (*p && isalpha(*p))
1342 for (i=0; i<8; ++i) {
1343 if (!StrCaseCmp(buf, cnames[i]))
1344 return which? (i+40) : (i+30);
1346 if (!StrCaseCmp(buf, "default")) return -1;
1348 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1353 parse_cpair(cc, str)
1357 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1358 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1363 /* bg and attr are optional */
1364 textColors[(int)cc].bg = parse_color(str, 1);
1365 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1366 textColors[(int)cc].attr = 0;
1372 /* Arrange to catch delete-window events */
1373 Atom wm_delete_window;
1375 CatchDeleteWindow(Widget w, String procname)
1378 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1379 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1380 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1387 XtSetArg(args[0], XtNiconic, False);
1388 XtSetValues(shellWidget, args, 1);
1390 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1393 //---------------------------------------------------------------------------------------------------------
1394 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1397 #define CW_USEDEFAULT (1<<31)
1398 #define ICS_TEXT_MENU_SIZE 90
1399 #define DEBUG_FILE "xboard.debug"
1400 #define SetCurrentDirectory chdir
1401 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1405 // these two must some day move to frontend.h, when they are implemented
1406 Boolean GameListIsUp();
1408 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1411 // front-end part of option handling
1413 // [HGM] This platform-dependent table provides the location for storing the color info
1414 extern char *crWhite, * crBlack;
1418 &appData.whitePieceColor,
1419 &appData.blackPieceColor,
1420 &appData.lightSquareColor,
1421 &appData.darkSquareColor,
1422 &appData.highlightSquareColor,
1423 &appData.premoveHighlightColor,
1424 &appData.lowTimeWarningColor,
1435 // [HGM] font: keep a font for each square size, even non-stndard ones
1436 #define NUM_SIZES 18
1437 #define MAX_SIZE 130
1438 Boolean fontIsSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1439 char *fontTable[NUM_FONTS][MAX_SIZE];
1442 ParseFont(char *name, int number)
1443 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1445 if(sscanf(name, "size%d:", &size)) {
1446 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1447 // defer processing it until we know if it matches our board size
1448 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1449 fontTable[number][size] = strdup(strchr(name, ':')+1);
1450 fontValid[number][size] = True;
1455 case 0: // CLOCK_FONT
1456 appData.clockFont = strdup(name);
1458 case 1: // MESSAGE_FONT
1459 appData.font = strdup(name);
1461 case 2: // COORD_FONT
1462 appData.coordFont = strdup(name);
1467 fontIsSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1472 { // only 2 fonts currently
1473 appData.clockFont = CLOCK_FONT_NAME;
1474 appData.coordFont = COORD_FONT_NAME;
1475 appData.font = DEFAULT_FONT_NAME;
1480 { // no-op, until we identify the code for this already in XBoard and move it here
1484 ParseColor(int n, char *name)
1485 { // in XBoard, just copy the color-name string
1486 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1490 ParseTextAttribs(ColorClass cc, char *s)
1492 (&appData.colorShout)[cc] = strdup(s);
1496 ParseBoardSize(void *addr, char *name)
1498 appData.boardSize = strdup(name);
1503 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1507 SetCommPortDefaults()
1508 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1511 // [HGM] args: these three cases taken out to stay in front-end
1513 SaveFontArg(FILE *f, ArgDescriptor *ad)
1516 int i, n = (int)(intptr_t)ad->argLoc;
1518 case 0: // CLOCK_FONT
1519 name = appData.clockFont;
1521 case 1: // MESSAGE_FONT
1522 name = appData.font;
1524 case 2: // COORD_FONT
1525 name = appData.coordFont;
1530 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1531 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1532 fontTable[n][squareSize] = strdup(name);
1533 fontValid[n][squareSize] = True;
1536 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1537 fprintf(f, OPTCHAR "%s" SEPCHAR "\"size%d:%s\"\n", ad->argName, i, fontTable[n][i]);
1542 { // nothing to do, as the sounds are at all times represented by their text-string names already
1546 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1547 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1548 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
1552 SaveColor(FILE *f, ArgDescriptor *ad)
1553 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1554 if(colorVariable[(int)(intptr_t)ad->argLoc])
1555 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
1559 SaveBoardSize(FILE *f, char *name, void *addr)
1560 { // wrapper to shield back-end from BoardSize & sizeInfo
1561 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1565 ParseCommPortSettings(char *s)
1566 { // no such option in XBoard (yet)
1569 extern Widget engineOutputShell;
1572 GetActualPlacement(Widget wg, WindowPlacement *wp)
1582 XtSetArg(args[i], XtNx, &x); i++;
1583 XtSetArg(args[i], XtNy, &y); i++;
1584 XtSetArg(args[i], XtNwidth, &w); i++;
1585 XtSetArg(args[i], XtNheight, &h); i++;
1586 XtGetValues(wg, args, i);
1595 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1596 // In XBoard this will have to wait until awareness of window parameters is implemented
1597 GetActualPlacement(shellWidget, &wpMain);
1598 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput);
1599 if(MoveHistoryIsUp()) GetActualPlacement(shells[7], &wpMoveHistory);
1600 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1601 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1602 if(shellUp[1]) GetActualPlacement(shells[1], &wpComment);
1603 if(shellUp[2]) GetActualPlacement(shells[2], &wpTags);
1607 PrintCommPortSettings(FILE *f, char *name)
1608 { // This option does not exist in XBoard
1612 MySearchPath(char *installDir, char *name, char *fullname)
1613 { // just append installDir and name. Perhaps ExpandPath should be used here?
1614 name = ExpandPathName(name);
1615 if(name && name[0] == '/')
1616 safeStrCpy(fullname, name, MSG_SIZ );
1618 sprintf(fullname, "%s%c%s", installDir, '/', name);
1624 MyGetFullPathName(char *name, char *fullname)
1625 { // should use ExpandPath?
1626 name = ExpandPathName(name);
1627 safeStrCpy(fullname, name, MSG_SIZ );
1632 EnsureOnScreen(int *x, int *y, int minX, int minY)
1639 { // [HGM] args: allows testing if main window is realized from back-end
1640 return xBoardWindow != 0;
1644 PopUpStartupDialog()
1645 { // start menu not implemented in XBoard
1649 ConvertToLine(int argc, char **argv)
1651 static char line[128*1024], buf[1024];
1655 for(i=1; i<argc; i++)
1657 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') || argv[i][0] == NULLCHAR)
1658 && argv[i][0] != '{' )
1659 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1661 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1662 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1665 line[strlen(line)-1] = NULLCHAR;
1669 //--------------------------------------------------------------------------------------------
1671 extern Boolean twoBoards, partnerUp;
1674 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1676 #define BoardSize int
1677 void InitDrawingSizes(BoardSize boardSize, int flags)
1678 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1679 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1681 XtGeometryResult gres;
1684 if(!formWidget) return;
1687 * Enable shell resizing.
1689 shellArgs[0].value = (XtArgVal) &w;
1690 shellArgs[1].value = (XtArgVal) &h;
1691 XtGetValues(shellWidget, shellArgs, 2);
1693 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1694 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1695 XtSetValues(shellWidget, &shellArgs[2], 4);
1697 XtSetArg(args[0], XtNdefaultDistance, &sep);
1698 XtGetValues(formWidget, args, 1);
1700 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1701 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1702 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1704 hOffset = boardWidth + 10;
1705 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1706 secondSegments[i] = gridSegments[i];
1707 secondSegments[i].x1 += hOffset;
1708 secondSegments[i].x2 += hOffset;
1711 XtSetArg(args[0], XtNwidth, boardWidth);
1712 XtSetArg(args[1], XtNheight, boardHeight);
1713 XtSetValues(boardWidget, args, 2);
1715 timerWidth = (boardWidth - sep) / 2;
1716 XtSetArg(args[0], XtNwidth, timerWidth);
1717 XtSetValues(whiteTimerWidget, args, 1);
1718 XtSetValues(blackTimerWidget, args, 1);
1720 XawFormDoLayout(formWidget, False);
1722 if (appData.titleInWindow) {
1724 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1725 XtSetArg(args[i], XtNheight, &h); i++;
1726 XtGetValues(titleWidget, args, i);
1728 w = boardWidth - 2*bor;
1730 XtSetArg(args[0], XtNwidth, &w);
1731 XtGetValues(menuBarWidget, args, 1);
1732 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1735 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1736 if (gres != XtGeometryYes && appData.debugMode) {
1738 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1739 programName, gres, w, h, wr, hr);
1743 XawFormDoLayout(formWidget, True);
1746 * Inhibit shell resizing.
1748 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1749 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1750 shellArgs[4].value = shellArgs[2].value = w;
1751 shellArgs[5].value = shellArgs[3].value = h;
1752 XtSetValues(shellWidget, &shellArgs[0], 6);
1754 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1757 for(i=0; i<4; i++) {
1759 for(p=0; p<=(int)WhiteKing; p++)
1760 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1761 if(gameInfo.variant == VariantShogi) {
1762 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1763 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1764 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1765 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1766 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1769 if(gameInfo.variant == VariantGothic) {
1770 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1773 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1774 xpmPieceBitmap[i][(int)WhiteAngel] = xpmPieceBitmap2[i][(int)WhiteFalcon];
1775 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1778 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1779 for(p=0; p<=(int)WhiteKing; p++)
1780 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1781 if(gameInfo.variant == VariantShogi) {
1782 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1783 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1784 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1785 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1786 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1789 if(gameInfo.variant == VariantGothic) {
1790 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1793 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1794 ximMaskPm[(int)WhiteAngel] = ximMaskPm2[(int)WhiteFalcon];
1795 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1800 for(i=0; i<2; i++) {
1802 for(p=0; p<=(int)WhiteKing; p++)
1803 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1804 if(gameInfo.variant == VariantShogi) {
1805 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1806 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1807 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1808 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1809 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1812 if(gameInfo.variant == VariantGothic) {
1813 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1816 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1817 pieceBitmap[i][(int)WhiteAngel] = pieceBitmap2[i][(int)WhiteFalcon];
1818 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1828 void ParseIcsTextColors()
1829 { // [HGM] tken out of main(), so it can be called from ICS-Options dialog
1830 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1831 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1832 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1833 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1834 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1835 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1836 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1837 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1838 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1839 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1841 if (appData.colorize) {
1843 _("%s: can't parse color names; disabling colorization\n"),
1846 appData.colorize = FALSE;
1851 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
1852 XrmValue vFrom, vTo;
1853 int forceMono = False;
1855 if (!appData.monoMode) {
1856 vFrom.addr = (caddr_t) appData.lightSquareColor;
1857 vFrom.size = strlen(appData.lightSquareColor);
1858 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1859 if (vTo.addr == NULL) {
1860 appData.monoMode = True;
1863 lightSquareColor = *(Pixel *) vTo.addr;
1866 if (!appData.monoMode) {
1867 vFrom.addr = (caddr_t) appData.darkSquareColor;
1868 vFrom.size = strlen(appData.darkSquareColor);
1869 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1870 if (vTo.addr == NULL) {
1871 appData.monoMode = True;
1874 darkSquareColor = *(Pixel *) vTo.addr;
1877 if (!appData.monoMode) {
1878 vFrom.addr = (caddr_t) appData.whitePieceColor;
1879 vFrom.size = strlen(appData.whitePieceColor);
1880 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1881 if (vTo.addr == NULL) {
1882 appData.monoMode = True;
1885 whitePieceColor = *(Pixel *) vTo.addr;
1888 if (!appData.monoMode) {
1889 vFrom.addr = (caddr_t) appData.blackPieceColor;
1890 vFrom.size = strlen(appData.blackPieceColor);
1891 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1892 if (vTo.addr == NULL) {
1893 appData.monoMode = True;
1896 blackPieceColor = *(Pixel *) vTo.addr;
1900 if (!appData.monoMode) {
1901 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1902 vFrom.size = strlen(appData.highlightSquareColor);
1903 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1904 if (vTo.addr == NULL) {
1905 appData.monoMode = True;
1908 highlightSquareColor = *(Pixel *) vTo.addr;
1912 if (!appData.monoMode) {
1913 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1914 vFrom.size = strlen(appData.premoveHighlightColor);
1915 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1916 if (vTo.addr == NULL) {
1917 appData.monoMode = True;
1920 premoveHighlightColor = *(Pixel *) vTo.addr;
1928 { // [HGM] taken out of main
1930 if (appData.monoMode && // [HGM] no sense to go on to certain doom
1931 (appData.bitmapDirectory == NULL || appData.bitmapDirectory[0] == NULLCHAR))
1932 appData.bitmapDirectory = DEF_BITMAP_DIR;
1934 if (appData.bitmapDirectory[0] != NULLCHAR) {
1938 CreateXPMBoard(appData.liteBackTextureFile, 1);
1939 CreateXPMBoard(appData.darkBackTextureFile, 0);
1943 /* Create regular pieces */
1944 if (!useImages) CreatePieces();
1953 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1954 XSetWindowAttributes window_attributes;
1956 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1957 XrmValue vFrom, vTo;
1958 XtGeometryResult gres;
1961 int forceMono = False;
1963 srandom(time(0)); // [HGM] book: make random truly random
1965 setbuf(stdout, NULL);
1966 setbuf(stderr, NULL);
1969 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1970 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1974 programName = strrchr(argv[0], '/');
1975 if (programName == NULL)
1976 programName = argv[0];
1981 XtSetLanguageProc(NULL, NULL, NULL);
1982 bindtextdomain(PACKAGE, LOCALEDIR);
1983 textdomain(PACKAGE);
1987 XtAppInitialize(&appContext, "XBoard", shellOptions,
1988 XtNumber(shellOptions),
1989 &argc, argv, xboardResources, NULL, 0);
1990 appData.boardSize = "";
1991 InitAppData(ConvertToLine(argc, argv));
1993 if (p == NULL) p = "/tmp";
1994 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1995 gameCopyFilename = (char*) malloc(i);
1996 gamePasteFilename = (char*) malloc(i);
1997 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1998 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
2000 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
2001 clientResources, XtNumber(clientResources),
2004 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
2005 static char buf[MSG_SIZ];
2006 EscapeExpand(buf, appData.firstInitString);
2007 appData.firstInitString = strdup(buf);
2008 EscapeExpand(buf, appData.secondInitString);
2009 appData.secondInitString = strdup(buf);
2010 EscapeExpand(buf, appData.firstComputerString);
2011 appData.firstComputerString = strdup(buf);
2012 EscapeExpand(buf, appData.secondComputerString);
2013 appData.secondComputerString = strdup(buf);
2016 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
2019 if (chdir(chessDir) != 0) {
2020 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
2026 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
2027 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
2028 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
2029 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
2032 setbuf(debugFP, NULL);
2036 if (appData.debugMode) {
2037 fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
2041 /* [HGM,HR] make sure board size is acceptable */
2042 if(appData.NrFiles > BOARD_FILES ||
2043 appData.NrRanks > BOARD_RANKS )
2044 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
2047 /* This feature does not work; animation needs a rewrite */
2048 appData.highlightDragging = FALSE;
2052 xDisplay = XtDisplay(shellWidget);
2053 xScreen = DefaultScreen(xDisplay);
2054 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
2056 gameInfo.variant = StringToVariant(appData.variant);
2057 InitPosition(FALSE);
2060 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
2062 if (isdigit(appData.boardSize[0])) {
2063 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
2064 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
2065 &fontPxlSize, &smallLayout, &tinyLayout);
2067 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
2068 programName, appData.boardSize);
2072 /* Find some defaults; use the nearest known size */
2073 SizeDefaults *szd, *nearest;
2074 int distance = 99999;
2075 nearest = szd = sizeDefaults;
2076 while (szd->name != NULL) {
2077 if (abs(szd->squareSize - squareSize) < distance) {
2079 distance = abs(szd->squareSize - squareSize);
2080 if (distance == 0) break;
2084 if (i < 2) lineGap = nearest->lineGap;
2085 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
2086 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
2087 if (i < 5) fontPxlSize = nearest->fontPxlSize;
2088 if (i < 6) smallLayout = nearest->smallLayout;
2089 if (i < 7) tinyLayout = nearest->tinyLayout;
2092 SizeDefaults *szd = sizeDefaults;
2093 if (*appData.boardSize == NULLCHAR) {
2094 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
2095 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
2098 if (szd->name == NULL) szd--;
2099 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
2101 while (szd->name != NULL &&
2102 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
2103 if (szd->name == NULL) {
2104 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
2105 programName, appData.boardSize);
2109 squareSize = szd->squareSize;
2110 lineGap = szd->lineGap;
2111 clockFontPxlSize = szd->clockFontPxlSize;
2112 coordFontPxlSize = szd->coordFontPxlSize;
2113 fontPxlSize = szd->fontPxlSize;
2114 smallLayout = szd->smallLayout;
2115 tinyLayout = szd->tinyLayout;
2116 // [HGM] font: use defaults from settings file if available and not overruled
2118 if(!fontIsSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
2119 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
2120 if(!fontIsSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
2121 appData.font = fontTable[MESSAGE_FONT][squareSize];
2122 if(!fontIsSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
2123 appData.coordFont = fontTable[COORD_FONT][squareSize];
2125 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
2126 if (strlen(appData.pixmapDirectory) > 0) {
2127 p = ExpandPathName(appData.pixmapDirectory);
2129 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
2130 appData.pixmapDirectory);
2133 if (appData.debugMode) {
2134 fprintf(stderr, _("\
2135 XBoard square size (hint): %d\n\
2136 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
2138 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
2139 if (appData.debugMode) {
2140 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
2143 defaultLineGap = lineGap;
2144 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
2146 /* [HR] height treated separately (hacked) */
2147 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
2148 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
2149 if (appData.showJail == 1) {
2150 /* Jail on top and bottom */
2151 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2152 XtSetArg(boardArgs[2], XtNheight,
2153 boardHeight + 2*(lineGap + squareSize));
2154 } else if (appData.showJail == 2) {
2156 XtSetArg(boardArgs[1], XtNwidth,
2157 boardWidth + 2*(lineGap + squareSize));
2158 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2161 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2162 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2166 * Determine what fonts to use.
2169 appData.font = InsertPxlSize(appData.font, fontPxlSize);
2170 appData.clockFont = InsertPxlSize(appData.clockFont, clockFontPxlSize);
2171 appData.coordFont = InsertPxlSize(appData.coordFont, coordFontPxlSize);
2172 fontSet = CreateFontSet(appData.font);
2173 clockFontSet = CreateFontSet(appData.clockFont);
2175 /* For the coordFont, use the 0th font of the fontset. */
2176 XFontSet coordFontSet = CreateFontSet(appData.coordFont);
2177 XFontStruct **font_struct_list;
2178 char **font_name_list;
2179 XFontsOfFontSet(coordFontSet, &font_struct_list, &font_name_list);
2180 coordFontID = XLoadFont(xDisplay, font_name_list[0]);
2181 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2184 appData.font = FindFont(appData.font, fontPxlSize);
2185 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2186 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2187 clockFontID = XLoadFont(xDisplay, appData.clockFont);
2188 clockFontStruct = XQueryFont(xDisplay, clockFontID);
2189 coordFontID = XLoadFont(xDisplay, appData.coordFont);
2190 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2192 countFontID = coordFontID; // [HGM] holdings
2193 countFontStruct = coordFontStruct;
2195 xdb = XtDatabase(xDisplay);
2197 XrmPutLineResource(&xdb, "*international: True");
2198 vTo.size = sizeof(XFontSet);
2199 vTo.addr = (XtPointer) &fontSet;
2200 XrmPutResource(&xdb, "*fontSet", XtRFontSet, &vTo);
2202 XrmPutStringResource(&xdb, "*font", appData.font);
2206 * Detect if there are not enough colors available and adapt.
2208 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2209 appData.monoMode = True;
2212 forceMono = MakeColors();
2215 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2217 appData.monoMode = True;
2220 if (appData.lowTimeWarning && !appData.monoMode) {
2221 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2222 vFrom.size = strlen(appData.lowTimeWarningColor);
2223 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2224 if (vTo.addr == NULL)
2225 appData.monoMode = True;
2227 lowTimeWarningColor = *(Pixel *) vTo.addr;
2230 if (appData.monoMode && appData.debugMode) {
2231 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2232 (unsigned long) XWhitePixel(xDisplay, xScreen),
2233 (unsigned long) XBlackPixel(xDisplay, xScreen));
2236 ParseIcsTextColors();
2237 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2238 textColors[ColorNone].attr = 0;
2240 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2246 layoutName = "tinyLayout";
2247 } else if (smallLayout) {
2248 layoutName = "smallLayout";
2250 layoutName = "normalLayout";
2252 /* Outer layoutWidget is there only to provide a name for use in
2253 resources that depend on the layout style */
2255 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2256 layoutArgs, XtNumber(layoutArgs));
2258 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2259 formArgs, XtNumber(formArgs));
2260 XtSetArg(args[0], XtNdefaultDistance, &sep);
2261 XtGetValues(formWidget, args, 1);
2264 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2265 XtSetArg(args[0], XtNtop, XtChainTop);
2266 XtSetArg(args[1], XtNbottom, XtChainTop);
2267 XtSetArg(args[2], XtNright, XtChainLeft);
2268 XtSetValues(menuBarWidget, args, 3);
2270 widgetList[j++] = whiteTimerWidget =
2271 XtCreateWidget("whiteTime", labelWidgetClass,
2272 formWidget, timerArgs, XtNumber(timerArgs));
2274 XtSetArg(args[0], XtNfontSet, clockFontSet);
2276 XtSetArg(args[0], XtNfont, clockFontStruct);
2278 XtSetArg(args[1], XtNtop, XtChainTop);
2279 XtSetArg(args[2], XtNbottom, XtChainTop);
2280 XtSetValues(whiteTimerWidget, args, 3);
2282 widgetList[j++] = blackTimerWidget =
2283 XtCreateWidget("blackTime", labelWidgetClass,
2284 formWidget, timerArgs, XtNumber(timerArgs));
2286 XtSetArg(args[0], XtNfontSet, clockFontSet);
2288 XtSetArg(args[0], XtNfont, clockFontStruct);
2290 XtSetArg(args[1], XtNtop, XtChainTop);
2291 XtSetArg(args[2], XtNbottom, XtChainTop);
2292 XtSetValues(blackTimerWidget, args, 3);
2294 if (appData.titleInWindow) {
2295 widgetList[j++] = titleWidget =
2296 XtCreateWidget("title", labelWidgetClass, formWidget,
2297 titleArgs, XtNumber(titleArgs));
2298 XtSetArg(args[0], XtNtop, XtChainTop);
2299 XtSetArg(args[1], XtNbottom, XtChainTop);
2300 XtSetValues(titleWidget, args, 2);
2303 if (appData.showButtonBar) {
2304 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2305 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2306 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2307 XtSetArg(args[2], XtNtop, XtChainTop);
2308 XtSetArg(args[3], XtNbottom, XtChainTop);
2309 XtSetValues(buttonBarWidget, args, 4);
2312 widgetList[j++] = messageWidget =
2313 XtCreateWidget("message", labelWidgetClass, formWidget,
2314 messageArgs, XtNumber(messageArgs));
2315 XtSetArg(args[0], XtNtop, XtChainTop);
2316 XtSetArg(args[1], XtNbottom, XtChainTop);
2317 XtSetValues(messageWidget, args, 2);
2319 widgetList[j++] = boardWidget =
2320 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2321 XtNumber(boardArgs));
2323 XtManageChildren(widgetList, j);
2325 timerWidth = (boardWidth - sep) / 2;
2326 XtSetArg(args[0], XtNwidth, timerWidth);
2327 XtSetValues(whiteTimerWidget, args, 1);
2328 XtSetValues(blackTimerWidget, args, 1);
2330 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2331 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2332 XtGetValues(whiteTimerWidget, args, 2);
2334 if (appData.showButtonBar) {
2335 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2336 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2337 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2341 * formWidget uses these constraints but they are stored
2345 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2346 XtSetValues(menuBarWidget, args, i);
2347 if (appData.titleInWindow) {
2350 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2351 XtSetValues(whiteTimerWidget, args, i);
2353 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2354 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2355 XtSetValues(blackTimerWidget, args, i);
2357 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2358 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2359 XtSetValues(titleWidget, args, i);
2361 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2362 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2363 XtSetValues(messageWidget, args, i);
2364 if (appData.showButtonBar) {
2366 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2367 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2368 XtSetValues(buttonBarWidget, args, i);
2372 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2373 XtSetValues(whiteTimerWidget, args, i);
2375 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2376 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2377 XtSetValues(blackTimerWidget, args, i);
2379 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2380 XtSetValues(titleWidget, args, i);
2382 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2383 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2384 XtSetValues(messageWidget, args, i);
2385 if (appData.showButtonBar) {
2387 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2388 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2389 XtSetValues(buttonBarWidget, args, i);
2394 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2395 XtSetValues(whiteTimerWidget, args, i);
2397 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2398 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2399 XtSetValues(blackTimerWidget, args, i);
2401 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2402 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2403 XtSetValues(messageWidget, args, i);
2404 if (appData.showButtonBar) {
2406 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2407 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2408 XtSetValues(buttonBarWidget, args, i);
2412 XtSetArg(args[0], XtNfromVert, messageWidget);
2413 XtSetArg(args[1], XtNtop, XtChainTop);
2414 XtSetArg(args[2], XtNbottom, XtChainBottom);
2415 XtSetArg(args[3], XtNleft, XtChainLeft);
2416 XtSetArg(args[4], XtNright, XtChainRight);
2417 XtSetValues(boardWidget, args, 5);
2419 XtRealizeWidget(shellWidget);
2422 XtSetArg(args[0], XtNx, wpMain.x);
2423 XtSetArg(args[1], XtNy, wpMain.y);
2424 XtSetValues(shellWidget, args, 2);
2428 * Correct the width of the message and title widgets.
2429 * It is not known why some systems need the extra fudge term.
2430 * The value "2" is probably larger than needed.
2432 XawFormDoLayout(formWidget, False);
2434 #define WIDTH_FUDGE 2
2436 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2437 XtSetArg(args[i], XtNheight, &h); i++;
2438 XtGetValues(messageWidget, args, i);
2439 if (appData.showButtonBar) {
2441 XtSetArg(args[i], XtNwidth, &w); i++;
2442 XtGetValues(buttonBarWidget, args, i);
2443 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2445 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2448 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2449 if (gres != XtGeometryYes && appData.debugMode) {
2450 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2451 programName, gres, w, h, wr, hr);
2454 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2455 /* The size used for the child widget in layout lags one resize behind
2456 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2458 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2459 if (gres != XtGeometryYes && appData.debugMode) {
2460 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2461 programName, gres, w, h, wr, hr);
2464 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2465 XtSetArg(args[1], XtNright, XtChainRight);
2466 XtSetValues(messageWidget, args, 2);
2468 if (appData.titleInWindow) {
2470 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2471 XtSetArg(args[i], XtNheight, &h); i++;
2472 XtGetValues(titleWidget, args, i);
2474 w = boardWidth - 2*bor;
2476 XtSetArg(args[0], XtNwidth, &w);
2477 XtGetValues(menuBarWidget, args, 1);
2478 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2481 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2482 if (gres != XtGeometryYes && appData.debugMode) {
2484 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2485 programName, gres, w, h, wr, hr);
2488 XawFormDoLayout(formWidget, True);
2490 xBoardWindow = XtWindow(boardWidget);
2492 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2493 // not need to go into InitDrawingSizes().
2497 * Create X checkmark bitmap and initialize option menu checks.
2499 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2500 checkmark_bits, checkmark_width, checkmark_height);
2501 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2502 #ifndef OPTIONSDIALOG
2503 if (appData.alwaysPromoteToQueen) {
2504 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2507 if (appData.animateDragging) {
2508 XtSetValues(XtNameToWidget(menuBarWidget,
2509 "menuOptions.Animate Dragging"),
2512 if (appData.animate) {
2513 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2516 if (appData.autoCallFlag) {
2517 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2520 if (appData.autoFlipView) {
2521 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2524 if (appData.blindfold) {
2525 XtSetValues(XtNameToWidget(menuBarWidget,
2526 "menuOptions.Blindfold"), args, 1);
2528 if (appData.flashCount > 0) {
2529 XtSetValues(XtNameToWidget(menuBarWidget,
2530 "menuOptions.Flash Moves"),
2534 if (appData.highlightDragging) {
2535 XtSetValues(XtNameToWidget(menuBarWidget,
2536 "menuOptions.Highlight Dragging"),
2540 if (appData.highlightLastMove) {
2541 XtSetValues(XtNameToWidget(menuBarWidget,
2542 "menuOptions.Highlight Last Move"),
2545 if (appData.highlightMoveWithArrow) {
2546 XtSetValues(XtNameToWidget(menuBarWidget,
2547 "menuOptions.Arrow"),
2550 // if (appData.icsAlarm) {
2551 // XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2554 if (appData.ringBellAfterMoves) {
2555 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2558 if (appData.oneClick) {
2559 XtSetValues(XtNameToWidget(menuBarWidget,
2560 "menuOptions.OneClick"), args, 1);
2562 if (appData.periodicUpdates) {
2563 XtSetValues(XtNameToWidget(menuBarWidget,
2564 "menuOptions.Periodic Updates"), args, 1);
2566 if (appData.ponderNextMove) {
2567 XtSetValues(XtNameToWidget(menuBarWidget,
2568 "menuOptions.Ponder Next Move"), args, 1);
2570 if (appData.popupExitMessage) {
2571 XtSetValues(XtNameToWidget(menuBarWidget,
2572 "menuOptions.Popup Exit Message"), args, 1);
2574 if (appData.popupMoveErrors) {
2575 XtSetValues(XtNameToWidget(menuBarWidget,
2576 "menuOptions.Popup Move Errors"), args, 1);
2578 // if (appData.premove) {
2579 // XtSetValues(XtNameToWidget(menuBarWidget,
2580 // "menuOptions.Premove"), args, 1);
2582 if (appData.showCoords) {
2583 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2586 if (appData.hideThinkingFromHuman) {
2587 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2590 if (appData.testLegality) {
2591 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2595 if (saveSettingsOnExit) {
2596 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2603 ReadBitmap(&wIconPixmap, "icon_white.bm",
2604 icon_white_bits, icon_white_width, icon_white_height);
2605 ReadBitmap(&bIconPixmap, "icon_black.bm",
2606 icon_black_bits, icon_black_width, icon_black_height);
2607 iconPixmap = wIconPixmap;
2609 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2610 XtSetValues(shellWidget, args, i);
2613 * Create a cursor for the board widget.
2615 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2616 XChangeWindowAttributes(xDisplay, xBoardWindow,
2617 CWCursor, &window_attributes);
2620 * Inhibit shell resizing.
2622 shellArgs[0].value = (XtArgVal) &w;
2623 shellArgs[1].value = (XtArgVal) &h;
2624 XtGetValues(shellWidget, shellArgs, 2);
2625 shellArgs[4].value = shellArgs[2].value = w;
2626 shellArgs[5].value = shellArgs[3].value = h;
2627 XtSetValues(shellWidget, &shellArgs[2], 4);
2628 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2629 marginH = h - boardHeight;
2631 CatchDeleteWindow(shellWidget, "QuitProc");
2639 if (appData.animate || appData.animateDragging)
2642 XtAugmentTranslations(formWidget,
2643 XtParseTranslationTable(globalTranslations));
2644 XtAugmentTranslations(boardWidget,
2645 XtParseTranslationTable(boardTranslations));
2646 XtAugmentTranslations(whiteTimerWidget,
2647 XtParseTranslationTable(whiteTranslations));
2648 XtAugmentTranslations(blackTimerWidget,
2649 XtParseTranslationTable(blackTranslations));
2651 /* Why is the following needed on some versions of X instead
2652 * of a translation? */
2653 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2654 (XtEventHandler) EventProc, NULL);
2656 XtAddEventHandler(formWidget, KeyPressMask, False,
2657 (XtEventHandler) MoveTypeInProc, NULL);
2659 /* [AS] Restore layout */
2660 if( wpMoveHistory.visible ) {
2664 if( wpEvalGraph.visible )
2669 if( wpEngineOutput.visible ) {
2670 EngineOutputPopUp();
2675 if (errorExitStatus == -1) {
2676 if (appData.icsActive) {
2677 /* We now wait until we see "login:" from the ICS before
2678 sending the logon script (problems with timestamp otherwise) */
2679 /*ICSInitScript();*/
2680 if (appData.icsInputBox) ICSInputBoxPopUp();
2684 signal(SIGWINCH, TermSizeSigHandler);
2686 signal(SIGINT, IntSigHandler);
2687 signal(SIGTERM, IntSigHandler);
2688 if (*appData.cmailGameName != NULLCHAR) {
2689 signal(SIGUSR1, CmailSigHandler);
2692 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2694 // XtSetKeyboardFocus(shellWidget, formWidget);
2695 XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
2697 XtAppMainLoop(appContext);
2698 if (appData.debugMode) fclose(debugFP); // [DM] debug
2702 static Boolean noEcho;
2707 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2708 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2710 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2711 unlink(gameCopyFilename);
2712 unlink(gamePasteFilename);
2713 if(noEcho) EchoOn();
2716 RETSIGTYPE TermSizeSigHandler(int sig)
2729 CmailSigHandler(sig)
2735 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2737 /* Activate call-back function CmailSigHandlerCallBack() */
2738 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2740 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2744 CmailSigHandlerCallBack(isr, closure, message, count, error)
2752 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2754 /**** end signal code ****/
2760 /* try to open the icsLogon script, either in the location given
2761 * or in the users HOME directory
2768 f = fopen(appData.icsLogon, "r");
2771 homedir = getenv("HOME");
2772 if (homedir != NULL)
2774 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2775 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2776 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2777 f = fopen(buf, "r");
2782 ProcessICSInitScript(f);
2784 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2807 if (!menuBarWidget) return;
2808 w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2810 DisplayError("menuEdit.Revert", 0);
2812 XtSetSensitive(w, !grey);
2814 w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2816 DisplayError("menuEdit.Annotate", 0);
2818 XtSetSensitive(w, !grey);
2823 SetMenuEnables(enab)
2827 if (!menuBarWidget) return;
2828 while (enab->name != NULL) {
2829 w = XtNameToWidget(menuBarWidget, enab->name);
2831 DisplayError(enab->name, 0);
2833 XtSetSensitive(w, enab->value);
2839 Enables icsEnables[] = {
2840 { "menuFile.Mail Move", False },
2841 { "menuFile.Reload CMail Message", False },
2842 { "menuMode.Machine Black", False },
2843 { "menuMode.Machine White", False },
2844 { "menuMode.Analysis Mode", False },
2845 { "menuMode.Analyze File", False },
2846 { "menuMode.Two Machines", False },
2847 { "menuMode.Machine Match", False },
2849 { "menuEngine.Hint", False },
2850 { "menuEngine.Book", False },
2851 { "menuEngine.Move Now", False },
2852 #ifndef OPTIONSDIALOG
2853 { "menuOptions.Periodic Updates", False },
2854 { "menuOptions.Hide Thinking", False },
2855 { "menuOptions.Ponder Next Move", False },
2858 { "menuEngine.Engine #1 Settings", False },
2859 { "menuEngine.Engine #2 Settings", False },
2860 { "menuEngine.Load Engine", False },
2861 { "menuEdit.Annotate", False },
2862 { "menuOptions.Match", False },
2866 Enables ncpEnables[] = {
2867 { "menuFile.Mail Move", False },
2868 { "menuFile.Reload CMail Message", False },
2869 { "menuMode.Machine White", False },
2870 { "menuMode.Machine Black", False },
2871 { "menuMode.Analysis Mode", False },
2872 { "menuMode.Analyze File", False },
2873 { "menuMode.Two Machines", False },
2874 { "menuMode.Machine Match", False },
2875 { "menuMode.ICS Client", False },
2876 { "menuView.ICStex", False },
2877 { "menuView.ICS Input Box", False },
2878 { "Action", False },
2879 { "menuEdit.Revert", False },
2880 { "menuEdit.Annotate", False },
2881 { "menuEngine.Engine #1 Settings", False },
2882 { "menuEngine.Engine #2 Settings", False },
2883 { "menuEngine.Move Now", False },
2884 { "menuEngine.Retract Move", False },
2885 { "menuOptions.ICS", False },
2886 #ifndef OPTIONSDIALOG
2887 { "menuOptions.Auto Flag", False },
2888 { "menuOptions.Auto Flip View", False },
2889 // { "menuOptions.ICS Alarm", False },
2890 { "menuOptions.Move Sound", False },
2891 { "menuOptions.Hide Thinking", False },
2892 { "menuOptions.Periodic Updates", False },
2893 { "menuOptions.Ponder Next Move", False },
2895 { "menuEngine.Hint", False },
2896 { "menuEngine.Book", False },
2900 Enables gnuEnables[] = {
2901 { "menuMode.ICS Client", False },
2902 { "menuView.ICStex", False },
2903 { "menuView.ICS Input Box", False },
2904 { "menuAction.Accept", False },
2905 { "menuAction.Decline", False },
2906 { "menuAction.Rematch", False },
2907 { "menuAction.Adjourn", False },
2908 { "menuAction.Stop Examining", False },
2909 { "menuAction.Stop Observing", False },
2910 { "menuAction.Upload to Examine", False },
2911 { "menuEdit.Revert", False },
2912 { "menuEdit.Annotate", False },
2913 { "menuOptions.ICS", False },
2915 /* The next two options rely on SetCmailMode being called *after* */
2916 /* SetGNUMode so that when GNU is being used to give hints these */
2917 /* menu options are still available */
2919 { "menuFile.Mail Move", False },
2920 { "menuFile.Reload CMail Message", False },
2921 // [HGM] The following have been added to make a switch from ncp to GNU mode possible
2922 { "menuMode.Machine White", True },
2923 { "menuMode.Machine Black", True },
2924 { "menuMode.Analysis Mode", True },
2925 { "menuMode.Analyze File", True },
2926 { "menuMode.Two Machines", True },
2927 { "menuMode.Machine Match", True },
2928 { "menuEngine.Engine #1 Settings", True },
2929 { "menuEngine.Engine #2 Settings", True },
2930 { "menuEngine.Hint", True },
2931 { "menuEngine.Book", True },
2932 { "menuEngine.Move Now", True },
2933 { "menuEngine.Retract Move", True },
2938 Enables cmailEnables[] = {
2940 { "menuAction.Call Flag", False },
2941 { "menuAction.Draw", True },
2942 { "menuAction.Adjourn", False },
2943 { "menuAction.Abort", False },
2944 { "menuAction.Stop Observing", False },
2945 { "menuAction.Stop Examining", False },
2946 { "menuFile.Mail Move", True },
2947 { "menuFile.Reload CMail Message", True },
2951 Enables trainingOnEnables[] = {
2952 { "menuMode.Edit Comment", False },
2953 { "menuMode.Pause", False },
2954 { "menuEdit.Forward", False },
2955 { "menuEdit.Backward", False },
2956 { "menuEdit.Forward to End", False },
2957 { "menuEdit.Back to Start", False },
2958 { "menuEngine.Move Now", False },
2959 { "menuEdit.Truncate Game", False },
2963 Enables trainingOffEnables[] = {
2964 { "menuMode.Edit Comment", True },
2965 { "menuMode.Pause", True },
2966 { "menuEdit.Forward", True },
2967 { "menuEdit.Backward", True },
2968 { "menuEdit.Forward to End", True },
2969 { "menuEdit.Back to Start", True },
2970 { "menuEngine.Move Now", True },
2971 { "menuEdit.Truncate Game", True },
2975 Enables machineThinkingEnables[] = {
2976 { "menuFile.Load Game", False },
2977 // { "menuFile.Load Next Game", False },
2978 // { "menuFile.Load Previous Game", False },
2979 // { "menuFile.Reload Same Game", False },
2980 { "menuEdit.Paste Game", False },
2981 { "menuFile.Load Position", False },
2982 // { "menuFile.Load Next Position", False },
2983 // { "menuFile.Load Previous Position", False },
2984 // { "menuFile.Reload Same Position", False },
2985 { "menuEdit.Paste Position", False },
2986 { "menuMode.Machine White", False },
2987 { "menuMode.Machine Black", False },
2988 { "menuMode.Two Machines", False },
2989 // { "menuMode.Machine Match", False },
2990 { "menuEngine.Retract Move", False },
2994 Enables userThinkingEnables[] = {
2995 { "menuFile.Load Game", True },
2996 // { "menuFile.Load Next Game", True },
2997 // { "menuFile.Load Previous Game", True },
2998 // { "menuFile.Reload Same Game", True },
2999 { "menuEdit.Paste Game", True },
3000 { "menuFile.Load Position", True },
3001 // { "menuFile.Load Next Position", True },
3002 // { "menuFile.Load Previous Position", True },
3003 // { "menuFile.Reload Same Position", True },
3004 { "menuEdit.Paste Position", True },
3005 { "menuMode.Machine White", True },
3006 { "menuMode.Machine Black", True },
3007 { "menuMode.Two Machines", True },
3008 // { "menuMode.Machine Match", True },
3009 { "menuEngine.Retract Move", True },
3015 SetMenuEnables(icsEnables);
3018 if (appData.zippyPlay && !appData.noChessProgram) { /* [DM] icsEngineAnalyze */
3019 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
3020 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuEngine.Engine #1 Settings"), True);
3028 SetMenuEnables(ncpEnables);
3034 SetMenuEnables(gnuEnables);
3040 SetMenuEnables(cmailEnables);
3046 SetMenuEnables(trainingOnEnables);
3047 if (appData.showButtonBar) {
3048 XtSetSensitive(buttonBarWidget, False);
3054 SetTrainingModeOff()
3056 SetMenuEnables(trainingOffEnables);
3057 if (appData.showButtonBar) {
3058 XtSetSensitive(buttonBarWidget, True);
3063 SetUserThinkingEnables()
3065 if (appData.noChessProgram) return;
3066 SetMenuEnables(userThinkingEnables);
3070 SetMachineThinkingEnables()
3072 if (appData.noChessProgram) return;
3073 SetMenuEnables(machineThinkingEnables);
3075 case MachinePlaysBlack:
3076 case MachinePlaysWhite:
3077 case TwoMachinesPlay:
3078 XtSetSensitive(XtNameToWidget(menuBarWidget,
3079 ModeToWidgetName(gameMode)), True);
3086 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
3087 #define HISTORY_SIZE 64
3088 static char *history[HISTORY_SIZE];
3089 int histIn = 0, histP = 0;
3092 SaveInHistory(char *cmd)
3094 if (history[histIn] != NULL) {
3095 free(history[histIn]);
3096 history[histIn] = NULL;
3098 if (*cmd == NULLCHAR) return;
3099 history[histIn] = StrSave(cmd);
3100 histIn = (histIn + 1) % HISTORY_SIZE;
3101 if (history[histIn] != NULL) {
3102 free(history[histIn]);
3103 history[histIn] = NULL;
3109 PrevInHistory(char *cmd)
3112 if (histP == histIn) {
3113 if (history[histIn] != NULL) free(history[histIn]);
3114 history[histIn] = StrSave(cmd);
3116 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
3117 if (newhp == histIn || history[newhp] == NULL) return NULL;
3119 return history[histP];
3125 if (histP == histIn) return NULL;
3126 histP = (histP + 1) % HISTORY_SIZE;
3127 return history[histP];
3129 // end of borrowed code
3131 #define Abs(n) ((n)<0 ? -(n) : (n))
3135 InsertPxlSize(pattern, targetPxlSize)
3139 char *base_fnt_lst, strInt[12], *p, *q;
3140 int alternatives, i, len, strIntLen;
3143 * Replace the "*" (if present) in the pixel-size slot of each
3144 * alternative with the targetPxlSize.
3148 while ((p = strchr(p, ',')) != NULL) {
3152 snprintf(strInt, sizeof(strInt), "%d", targetPxlSize);
3153 strIntLen = strlen(strInt);
3154 base_fnt_lst = calloc(1, strlen(pattern) + strIntLen * alternatives + 1);
3158 while (alternatives--) {
3159 char *comma = strchr(p, ',');
3160 for (i=0; i<14; i++) {
3161 char *hyphen = strchr(p, '-');
3163 if (comma && hyphen > comma) break;
3164 len = hyphen + 1 - p;
3165 if (i == 7 && *p == '*' && len == 2) {
3167 memcpy(q, strInt, strIntLen);
3177 len = comma + 1 - p;
3184 return base_fnt_lst;
3188 CreateFontSet(base_fnt_lst)
3192 char **missing_list;
3196 fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
3197 &missing_list, &missing_count, &def_string);
3198 if (appData.debugMode) {
3200 XFontStruct **font_struct_list;
3201 char **font_name_list;
3202 fprintf(debugFP, "Requested font set for list %s\n", base_fnt_lst);
3204 fprintf(debugFP, " got list %s, locale %s\n",
3205 XBaseFontNameListOfFontSet(fntSet),
3206 XLocaleOfFontSet(fntSet));
3207 count = XFontsOfFontSet(fntSet, &font_struct_list, &font_name_list);
3208 for (i = 0; i < count; i++) {
3209 fprintf(debugFP, " got charset %s\n", font_name_list[i]);
3212 for (i = 0; i < missing_count; i++) {
3213 fprintf(debugFP, " missing charset %s\n", missing_list[i]);
3216 if (fntSet == NULL) {
3217 fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
3222 #else // not ENABLE_NLS
3224 * Find a font that matches "pattern" that is as close as
3225 * possible to the targetPxlSize. Prefer fonts that are k
3226 * pixels smaller to fonts that are k pixels larger. The
3227 * pattern must be in the X Consortium standard format,
3228 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3229 * The return value should be freed with XtFree when no
3233 FindFont(pattern, targetPxlSize)
3237 char **fonts, *p, *best, *scalable, *scalableTail;
3238 int i, j, nfonts, minerr, err, pxlSize;
3240 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3242 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3243 programName, pattern);
3250 for (i=0; i<nfonts; i++) {
3253 if (*p != '-') continue;
3255 if (*p == NULLCHAR) break;
3256 if (*p++ == '-') j++;
3258 if (j < 7) continue;
3261 scalable = fonts[i];
3264 err = pxlSize - targetPxlSize;
3265 if (Abs(err) < Abs(minerr) ||
3266 (minerr > 0 && err < 0 && -err == minerr)) {
3272 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3273 /* If the error is too big and there is a scalable font,
3274 use the scalable font. */
3275 int headlen = scalableTail - scalable;
3276 p = (char *) XtMalloc(strlen(scalable) + 10);
3277 while (isdigit(*scalableTail)) scalableTail++;
3278 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3280 p = (char *) XtMalloc(strlen(best) + 2);
3281 safeStrCpy(p, best, strlen(best)+1 );
3283 if (appData.debugMode) {
3284 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3285 pattern, targetPxlSize, p);
3287 XFreeFontNames(fonts);
3293 { // [HGM] deletes GCs that are to be remade, to prevent resource leak;
3294 // must be called before all non-first callse to CreateGCs()
3295 XtReleaseGC(shellWidget, highlineGC);
3296 XtReleaseGC(shellWidget, lightSquareGC);
3297 XtReleaseGC(shellWidget, darkSquareGC);
3298 XtReleaseGC(shellWidget, lineGC);
3299 if (appData.monoMode) {
3300 if (DefaultDepth(xDisplay, xScreen) == 1) {
3301 XtReleaseGC(shellWidget, wbPieceGC);
3303 XtReleaseGC(shellWidget, bwPieceGC);
3306 XtReleaseGC(shellWidget, prelineGC);
3307 XtReleaseGC(shellWidget, jailSquareGC);
3308 XtReleaseGC(shellWidget, wdPieceGC);
3309 XtReleaseGC(shellWidget, wlPieceGC);
3310 XtReleaseGC(shellWidget, wjPieceGC);
3311 XtReleaseGC(shellWidget, bdPieceGC);
3312 XtReleaseGC(shellWidget, blPieceGC);
3313 XtReleaseGC(shellWidget, bjPieceGC);
3317 void CreateGCs(int redo)
3319 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3320 | GCBackground | GCFunction | GCPlaneMask;
3321 XGCValues gc_values;
3324 gc_values.plane_mask = AllPlanes;
3325 gc_values.line_width = lineGap;
3326 gc_values.line_style = LineSolid;
3327 gc_values.function = GXcopy;
3330 DeleteGCs(); // called a second time; clean up old GCs first
3331 } else { // [HGM] grid and font GCs created on first call only
3332 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3333 gc_values.background = XWhitePixel(xDisplay, xScreen);
3334 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3335 XSetFont(xDisplay, coordGC, coordFontID);
3337 // [HGM] make font for holdings counts (white on black)
3338 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3339 gc_values.background = XBlackPixel(xDisplay, xScreen);
3340 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3341 XSetFont(xDisplay, countGC, countFontID);
3343 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3344 gc_values.background = XBlackPixel(xDisplay, xScreen);
3345 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3347 if (appData.monoMode) {
3348 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3349 gc_values.background = XWhitePixel(xDisplay, xScreen);
3350 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3352 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3353 gc_values.background = XBlackPixel(xDisplay, xScreen);
3354 lightSquareGC = wbPieceGC
3355 = XtGetGC(shellWidget, value_mask, &gc_values);
3357 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3358 gc_values.background = XWhitePixel(xDisplay, xScreen);
3359 darkSquareGC = bwPieceGC
3360 = XtGetGC(shellWidget, value_mask, &gc_values);
3362 if (DefaultDepth(xDisplay, xScreen) == 1) {
3363 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3364 gc_values.function = GXcopyInverted;
3365 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3366 gc_values.function = GXcopy;
3367 if (XBlackPixel(xDisplay, xScreen) == 1) {
3368 bwPieceGC = darkSquareGC;
3369 wbPieceGC = copyInvertedGC;
3371 bwPieceGC = copyInvertedGC;
3372 wbPieceGC = lightSquareGC;
3376 gc_values.foreground = highlightSquareColor;
3377 gc_values.background = highlightSquareColor;
3378 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3380 gc_values.foreground = premoveHighlightColor;
3381 gc_values.background = premoveHighlightColor;
3382 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3384 gc_values.foreground = lightSquareColor;
3385 gc_values.background = darkSquareColor;
3386 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3388 gc_values.foreground = darkSquareColor;
3389 gc_values.background = lightSquareColor;
3390 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3392 gc_values.foreground = jailSquareColor;
3393 gc_values.background = jailSquareColor;
3394 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3396 gc_values.foreground = whitePieceColor;
3397 gc_values.background = darkSquareColor;
3398 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3400 gc_values.foreground = whitePieceColor;
3401 gc_values.background = lightSquareColor;
3402 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3404 gc_values.foreground = whitePieceColor;
3405 gc_values.background = jailSquareColor;
3406 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3408 gc_values.foreground = blackPieceColor;
3409 gc_values.background = darkSquareColor;
3410 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3412 gc_values.foreground = blackPieceColor;
3413 gc_values.background = lightSquareColor;
3414 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3416 gc_values.foreground = blackPieceColor;
3417 gc_values.background = jailSquareColor;
3418 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3422 void loadXIM(xim, xmask, filename, dest, mask)
3435 fp = fopen(filename, "rb");
3437 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3444 for (y=0; y<h; ++y) {
3445 for (x=0; x<h; ++x) {
3450 XPutPixel(xim, x, y, blackPieceColor);
3452 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3455 XPutPixel(xim, x, y, darkSquareColor);
3457 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3460 XPutPixel(xim, x, y, whitePieceColor);
3462 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3465 XPutPixel(xim, x, y, lightSquareColor);
3467 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3475 /* create Pixmap of piece */
3476 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3478 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3481 /* create Pixmap of clipmask
3482 Note: We assume the white/black pieces have the same
3483 outline, so we make only 6 masks. This is okay
3484 since the XPM clipmask routines do the same. */
3486 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3488 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3491 /* now create the 1-bit version */
3492 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3495 values.foreground = 1;
3496 values.background = 0;
3498 /* Don't use XtGetGC, not read only */
3499 maskGC = XCreateGC(xDisplay, *mask,
3500 GCForeground | GCBackground, &values);
3501 XCopyPlane(xDisplay, temp, *mask, maskGC,
3502 0, 0, squareSize, squareSize, 0, 0, 1);
3503 XFreePixmap(xDisplay, temp);
3508 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3510 void CreateXIMPieces()
3515 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3520 /* The XSynchronize calls were copied from CreatePieces.
3521 Not sure if needed, but can't hurt */
3522 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3525 /* temp needed by loadXIM() */
3526 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3527 0, 0, ss, ss, AllPlanes, XYPixmap);
3529 if (strlen(appData.pixmapDirectory) == 0) {
3533 if (appData.monoMode) {
3534 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3538 fprintf(stderr, _("\nLoading XIMs...\n"));
3540 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3541 fprintf(stderr, "%d", piece+1);
3542 for (kind=0; kind<4; kind++) {
3543 fprintf(stderr, ".");
3544 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3545 ExpandPathName(appData.pixmapDirectory),
3546 piece <= (int) WhiteKing ? "" : "w",
3547 pieceBitmapNames[piece],
3549 ximPieceBitmap[kind][piece] =
3550 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3551 0, 0, ss, ss, AllPlanes, XYPixmap);
3552 if (appData.debugMode)
3553 fprintf(stderr, _("(File:%s:) "), buf);
3554 loadXIM(ximPieceBitmap[kind][piece],
3556 &(xpmPieceBitmap2[kind][piece]),
3557 &(ximMaskPm2[piece]));
3558 if(piece <= (int)WhiteKing)
3559 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3561 fprintf(stderr," ");
3563 /* Load light and dark squares */
3564 /* If the LSQ and DSQ pieces don't exist, we will
3565 draw them with solid squares. */
3566 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3567 if (access(buf, 0) != 0) {
3571 fprintf(stderr, _("light square "));
3573 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3574 0, 0, ss, ss, AllPlanes, XYPixmap);
3575 if (appData.debugMode)
3576 fprintf(stderr, _("(File:%s:) "), buf);
3578 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3579 fprintf(stderr, _("dark square "));
3580 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3581 ExpandPathName(appData.pixmapDirectory), ss);
3582 if (appData.debugMode)
3583 fprintf(stderr, _("(File:%s:) "), buf);
3585 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3586 0, 0, ss, ss, AllPlanes, XYPixmap);
3587 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3588 xpmJailSquare = xpmLightSquare;
3590 fprintf(stderr, _("Done.\n"));
3592 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3595 static VariantClass oldVariant = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
3598 void CreateXPMBoard(char *s, int kind)
3602 if(s == NULL || *s == 0 || *s == '*') { useTexture &= ~(kind+1); return; }
3603 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3604 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3608 void FreeXPMPieces()
3609 { // [HGM] to prevent resoucre leak on calling CreaeXPMPieces() a second time,
3610 // thisroutine has to be called t free the old piece pixmaps
3612 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++)
3613 for (kind=0; kind<4; kind++) XFreePixmap(xDisplay, xpmPieceBitmap2[kind][piece]);
3615 XFreePixmap(xDisplay, xpmLightSquare);
3616 XFreePixmap(xDisplay, xpmDarkSquare);
3620 void CreateXPMPieces()
3624 u_int ss = squareSize;
3626 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3627 XpmColorSymbol symbols[4];
3628 static int redo = False;
3630 if(redo) FreeXPMPieces(); else redo = 1;
3632 /* The XSynchronize calls were copied from CreatePieces.
3633 Not sure if needed, but can't hurt */
3634 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3636 /* Setup translations so piece colors match square colors */
3637 symbols[0].name = "light_piece";
3638 symbols[0].value = appData.whitePieceColor;
3639 symbols[1].name = "dark_piece";
3640 symbols[1].value = appData.blackPieceColor;
3641 symbols[2].name = "light_square";
3642 symbols[2].value = appData.lightSquareColor;
3643 symbols[3].name = "dark_square";
3644 symbols[3].value = appData.darkSquareColor;
3646 attr.valuemask = XpmColorSymbols;
3647 attr.colorsymbols = symbols;
3648 attr.numsymbols = 4;
3650 if (appData.monoMode) {
3651 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3655 if (strlen(appData.pixmapDirectory) == 0) {
3656 XpmPieces* pieces = builtInXpms;
3659 while (pieces->size != squareSize && pieces->size) pieces++;
3660 if (!pieces->size) {
3661 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3664 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3665 for (kind=0; kind<4; kind++) {
3667 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3668 pieces->xpm[piece][kind],
3669 &(xpmPieceBitmap2[kind][piece]),
3670 NULL, &attr)) != 0) {
3671 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3675 if(piece <= (int) WhiteKing)
3676 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3680 xpmJailSquare = xpmLightSquare;
3684 fprintf(stderr, _("\nLoading XPMs...\n"));
3687 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3688 fprintf(stderr, "%d ", piece+1);
3689 for (kind=0; kind<4; kind++) {
3690 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3691 ExpandPathName(appData.pixmapDirectory),
3692 piece > (int) WhiteKing ? "w" : "",
3693 pieceBitmapNames[piece],
3695 if (appData.debugMode) {
3696 fprintf(stderr, _("(File:%s:) "), buf);
3698 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3699 &(xpmPieceBitmap2[kind][piece]),
3700 NULL, &attr)) != 0) {
3701 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3702 // [HGM] missing: read of unorthodox piece failed; substitute King.
3703 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3704 ExpandPathName(appData.pixmapDirectory),
3706 if (appData.debugMode) {
3707 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3709 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3710 &(xpmPieceBitmap2[kind][piece]),
3714 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3719 if(piece <= (int) WhiteKing)
3720 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3723 /* Load light and dark squares */
3724 /* If the LSQ and DSQ pieces don't exist, we will
3725 draw them with solid squares. */
3726 fprintf(stderr, _("light square "));
3727 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3728 if (access(buf, 0) != 0) {
3732 if (appData.debugMode)
3733 fprintf(stderr, _("(File:%s:) "), buf);
3735 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3736 &xpmLightSquare, NULL, &attr)) != 0) {
3737 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3740 fprintf(stderr, _("dark square "));
3741 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3742 ExpandPathName(appData.pixmapDirectory), ss);
3743 if (appData.debugMode) {
3744 fprintf(stderr, _("(File:%s:) "), buf);
3746 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3747 &xpmDarkSquare, NULL, &attr)) != 0) {
3748 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3752 xpmJailSquare = xpmLightSquare;
3753 fprintf(stderr, _("Done.\n"));
3755 oldVariant = -1; // kludge to force re-makig of animation masks
3756 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3759 #endif /* HAVE_LIBXPM */
3762 /* No built-in bitmaps */
3767 u_int ss = squareSize;
3769 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3772 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3773 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3774 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3775 pieceBitmapNames[piece],
3776 ss, kind == SOLID ? 's' : 'o');
3777 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3778 if(piece <= (int)WhiteKing)
3779 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3783 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3787 /* With built-in bitmaps */
3790 BuiltInBits* bib = builtInBits;
3793 u_int ss = squareSize;
3795 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3798 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3800 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3801 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3802 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3803 pieceBitmapNames[piece],
3804 ss, kind == SOLID ? 's' : 'o');
3805 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3806 bib->bits[kind][piece], ss, ss);
3807 if(piece <= (int)WhiteKing)
3808 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3812 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3817 void ReadBitmap(pm, name, bits, wreq, hreq)
3820 unsigned char bits[];
3826 char msg[MSG_SIZ], fullname[MSG_SIZ];
3828 if (*appData.bitmapDirectory != NULLCHAR) {
3829 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3830 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3831 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3832 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3833 &w, &h, pm, &x_hot, &y_hot);
3834 fprintf(stderr, "load %s\n", name);
3835 if (errcode != BitmapSuccess) {
3837 case BitmapOpenFailed:
3838 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3840 case BitmapFileInvalid:
3841 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3843 case BitmapNoMemory:
3844 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3848 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3852 fprintf(stderr, _("%s: %s...using built-in\n"),
3854 } else if (w != wreq || h != hreq) {
3856 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3857 programName, fullname, w, h, wreq, hreq);
3863 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3872 if (lineGap == 0) return;
3874 /* [HR] Split this into 2 loops for non-square boards. */
3876 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3877 gridSegments[i].x1 = 0;
3878 gridSegments[i].x2 =
3879 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3880 gridSegments[i].y1 = gridSegments[i].y2
3881 = lineGap / 2 + (i * (squareSize + lineGap));
3884 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3885 gridSegments[j + i].y1 = 0;
3886 gridSegments[j + i].y2 =
3887 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3888 gridSegments[j + i].x1 = gridSegments[j + i].x2
3889 = lineGap / 2 + (j * (squareSize + lineGap));
3893 static void MenuBarSelect(w, addr, index)
3898 XtActionProc proc = (XtActionProc) addr;
3900 (proc)(NULL, NULL, NULL, NULL);
3903 void CreateMenuBarPopup(parent, name, mb)
3913 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3916 XtSetArg(args[j], XtNleftMargin, 20); j++;
3917 XtSetArg(args[j], XtNrightMargin, 20); j++;
3919 while (mi->string != NULL) {
3920 if (strcmp(mi->string, "----") == 0) {
3921 entry = XtCreateManagedWidget(_(mi->string), smeLineObjectClass,
3924 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3925 entry = XtCreateManagedWidget(mi->ref, smeBSBObjectClass,
3927 XtAddCallback(entry, XtNcallback,
3928 (XtCallbackProc) MenuBarSelect,
3929 (caddr_t) mi->proc);
3935 Widget CreateMenuBar(mb)
3939 Widget anchor, menuBar;
3941 char menuName[MSG_SIZ];
3944 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3945 XtSetArg(args[j], XtNvSpace, 0); j++;
3946 XtSetArg(args[j], XtNborderWidth, 0); j++;
3947 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3948 formWidget, args, j);
3950 while (mb->name != NULL) {
3951 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3952 strncat(menuName, mb->ref, MSG_SIZ - strlen(menuName) - 1);
3954 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3957 shortName[0] = mb->name[0];
3958 shortName[1] = NULLCHAR;
3959 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3962 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3965 XtSetArg(args[j], XtNborderWidth, 0); j++;
3966 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3968 CreateMenuBarPopup(menuBar, menuName, mb);
3974 Widget CreateButtonBar(mi)
3978 Widget button, buttonBar;
3982 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3984 XtSetArg(args[j], XtNhSpace, 0); j++;
3986 XtSetArg(args[j], XtNborderWidth, 0); j++;
3987 XtSetArg(args[j], XtNvSpace, 0); j++;
3988 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3989 formWidget, args, j);
3991 while (mi->string != NULL) {
3994 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3995 XtSetArg(args[j], XtNborderWidth, 0); j++;
3997 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3998 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3999 buttonBar, args, j);
4000 XtAddCallback(button, XtNcallback,
4001 (XtCallbackProc) MenuBarSelect,
4002 (caddr_t) mi->proc);
4009 CreatePieceMenu(name, color)
4016 ChessSquare selection;
4018 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
4019 boardWidget, args, 0);
4021 for (i = 0; i < PIECE_MENU_SIZE; i++) {
4022 String item = pieceMenuStrings[color][i];
4024 if (strcmp(item, "----") == 0) {
4025 entry = XtCreateManagedWidget(item, smeLineObjectClass,
4028 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
4029 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
4031 selection = pieceMenuTranslation[color][i];
4032 XtAddCallback(entry, XtNcallback,
4033 (XtCallbackProc) PieceMenuSelect,
4034 (caddr_t) selection);
4035 if (selection == WhitePawn || selection == BlackPawn) {
4036 XtSetArg(args[0], XtNpopupOnEntry, entry);
4037 XtSetValues(menu, args, 1);
4050 ChessSquare selection;
4052 whitePieceMenu = CreatePieceMenu("menuW", 0);
4053 blackPieceMenu = CreatePieceMenu("menuB", 1);
4055 XtRegisterGrabAction(PieceMenuPopup, True,
4056 (unsigned)(ButtonPressMask|ButtonReleaseMask),
4057 GrabModeAsync, GrabModeAsync);
4059 XtSetArg(args[0], XtNlabel, _("Drop"));
4060 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
4061 boardWidget, args, 1);
4062 for (i = 0; i < DROP_MENU_SIZE; i++) {
4063 String item = dropMenuStrings[i];
4065 if (strcmp(item, "----") == 0) {
4066 entry = XtCreateManagedWidget(item, smeLineObjectClass,
4069 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
4070 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
4072 selection = dropMenuTranslation[i];
4073 XtAddCallback(entry, XtNcallback,
4074 (XtCallbackProc) DropMenuSelect,
4075 (caddr_t) selection);
4080 void SetupDropMenu()
4088 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
4089 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
4090 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
4091 dmEnables[i].piece);
4092 XtSetSensitive(entry, p != NULL || !appData.testLegality
4093 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
4094 && !appData.icsActive));
4096 while (p && *p++ == dmEnables[i].piece) count++;
4097 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
4099 XtSetArg(args[j], XtNlabel, label); j++;
4100 XtSetValues(entry, args, j);
4104 void PieceMenuPopup(w, event, params, num_params)
4108 Cardinal *num_params;
4110 String whichMenu; int menuNr = -2;
4111 shiftKey = strcmp(params[0], "menuW"); // used to indicate black
4112 if (event->type == ButtonRelease)
4113 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
4114 else if (event->type == ButtonPress)
4115 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
4117 case 0: whichMenu = params[0]; break;
4118 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
4120 case -1: if (errorUp) ErrorPopDown();
4123 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
4126 static void PieceMenuSelect(w, piece, junk)
4131 if (pmFromX < 0 || pmFromY < 0) return;
4132 EditPositionMenuEvent(piece, pmFromX, pmFromY);
4135 static void DropMenuSelect(w, piece, junk)
4140 if (pmFromX < 0 || pmFromY < 0) return;
4141 DropMenuEvent(piece, pmFromX, pmFromY);
4144 void WhiteClock(w, event, prms, nprms)
4150 shiftKey = prms[0][0] & 1;
4154 void BlackClock(w, event, prms, nprms)
4160 shiftKey = prms[0][0] & 1;
4166 * If the user selects on a border boundary, return -1; if off the board,
4167 * return -2. Otherwise map the event coordinate to the square.
4169 int EventToSquare(x, limit)
4177 if ((x % (squareSize + lineGap)) >= squareSize)
4179 x /= (squareSize + lineGap);
4185 static void do_flash_delay(msec)
4191 static void drawHighlight(file, rank, gc)
4197 if (lineGap == 0) return;
4200 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
4201 (squareSize + lineGap);
4202 y = lineGap/2 + rank * (squareSize + lineGap);
4204 x = lineGap/2 + file * (squareSize + lineGap);
4205 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
4206 (squareSize + lineGap);
4209 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
4210 squareSize+lineGap, squareSize+lineGap);
4213 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
4214 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4217 SetHighlights(fromX, fromY, toX, toY)
4218 int fromX, fromY, toX, toY;
4220 if (hi1X != fromX || hi1Y != fromY) {
4221 if (hi1X >= 0 && hi1Y >= 0) {
4222 drawHighlight(hi1X, hi1Y, lineGC);
4224 } // [HGM] first erase both, then draw new!
4225 if (hi2X != toX || hi2Y != toY) {
4226 if (hi2X >= 0 && hi2Y >= 0) {
4227 drawHighlight(hi2X, hi2Y, lineGC);
4230 if (hi1X != fromX || hi1Y != fromY) {
4231 if (fromX >= 0 && fromY >= 0) {
4232 drawHighlight(fromX, fromY, highlineGC);
4235 if (hi2X != toX || hi2Y != toY) {
4236 if (toX >= 0 && toY >= 0) {
4237 drawHighlight(toX, toY, highlineGC);
4249 SetHighlights(-1, -1, -1, -1);
4254 SetPremoveHighlights(fromX, fromY, toX, toY)
4255 int fromX, fromY, toX, toY;
4257 if (pm1X != fromX || pm1Y != fromY) {
4258 if (pm1X >= 0 && pm1Y >= 0) {
4259 drawHighlight(pm1X, pm1Y, lineGC);
4261 if (fromX >= 0 && fromY >= 0) {
4262 drawHighlight(fromX, fromY, prelineGC);
4265 if (pm2X != toX || pm2Y != toY) {
4266 if (pm2X >= 0 && pm2Y >= 0) {
4267 drawHighlight(pm2X, pm2Y, lineGC);
4269 if (toX >= 0 && toY >= 0) {
4270 drawHighlight(toX, toY, prelineGC);
4280 ClearPremoveHighlights()
4282 SetPremoveHighlights(-1, -1, -1, -1);
4285 static int CutOutSquare(x, y, x0, y0, kind)
4286 int x, y, *x0, *y0, kind;
4288 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
4289 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
4291 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
4292 if(textureW[kind] < W*squareSize)
4293 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
4295 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
4296 if(textureH[kind] < H*squareSize)
4297 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
4299 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
4303 static void BlankSquare(x, y, color, piece, dest, fac)
4304 int x, y, color, fac;
4307 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
4309 if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
4310 XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
4311 squareSize, squareSize, x*fac, y*fac);
4313 if (useImages && useImageSqs) {
4317 pm = xpmLightSquare;
4322 case 2: /* neutral */
4327 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4328 squareSize, squareSize, x*fac, y*fac);
4338 case 2: /* neutral */
4343 XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
4348 I split out the routines to draw a piece so that I could
4349 make a generic flash routine.
4351 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4353 int square_color, x, y;
4356 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4357 switch (square_color) {
4359 case 2: /* neutral */
4361 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4362 ? *pieceToOutline(piece)
4363 : *pieceToSolid(piece),
4364 dest, bwPieceGC, 0, 0,
4365 squareSize, squareSize, x, y);
4368 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4369 ? *pieceToSolid(piece)
4370 : *pieceToOutline(piece),
4371 dest, wbPieceGC, 0, 0,
4372 squareSize, squareSize, x, y);
4377 static void monoDrawPiece(piece, square_color, x, y, dest)
4379 int square_color, x, y;
4382 switch (square_color) {
4384 case 2: /* neutral */
4386 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4387 ? *pieceToOutline(piece)
4388 : *pieceToSolid(piece),
4389 dest, bwPieceGC, 0, 0,
4390 squareSize, squareSize, x, y, 1);
4393 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4394 ? *pieceToSolid(piece)
4395 : *pieceToOutline(piece),
4396 dest, wbPieceGC, 0, 0,
4397 squareSize, squareSize, x, y, 1);
4402 static void colorDrawPiece(piece, square_color, x, y, dest)
4404 int square_color, x, y;
4407 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4408 switch (square_color) {
4410 XCopyPlane(xDisplay, *pieceToSolid(piece),
4411 dest, (int) piece < (int) BlackPawn
4412 ? wlPieceGC : blPieceGC, 0, 0,
4413 squareSize, squareSize, x, y, 1);
4416 XCopyPlane(xDisplay, *pieceToSolid(piece),
4417 dest, (int) piece < (int) BlackPawn
4418 ? wdPieceGC : bdPieceGC, 0, 0,
4419 squareSize, squareSize, x, y, 1);
4421 case 2: /* neutral */
4423 XCopyPlane(xDisplay, *pieceToSolid(piece),
4424 dest, (int) piece < (int) BlackPawn
4425 ? wjPieceGC : bjPieceGC, 0, 0,
4426 squareSize, squareSize, x, y, 1);
4431 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4433 int square_color, x, y;
4436 int kind, p = piece;
4438 switch (square_color) {
4440 case 2: /* neutral */
4442 if ((int)piece < (int) BlackPawn) {
4450 if ((int)piece < (int) BlackPawn) {
4458 if(appData.upsideDown && flipView) { kind ^= 2; p += p < BlackPawn ? BlackPawn : -BlackPawn; }// swap white and black pieces
4459 if(useTexture & square_color+1) {
4460 BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background
4461 XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]);
4462 XSetClipOrigin(xDisplay, wlPieceGC, x, y);
4463 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y);
4464 XSetClipMask(xDisplay, wlPieceGC, None);
4465 XSetClipOrigin(xDisplay, wlPieceGC, 0, 0);
4467 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4468 dest, wlPieceGC, 0, 0,
4469 squareSize, squareSize, x, y);
4472 typedef void (*DrawFunc)();
4474 DrawFunc ChooseDrawFunc()
4476 if (appData.monoMode) {
4477 if (DefaultDepth(xDisplay, xScreen) == 1) {
4478 return monoDrawPiece_1bit;
4480 return monoDrawPiece;
4484 return colorDrawPieceImage;
4486 return colorDrawPiece;
4490 /* [HR] determine square color depending on chess variant. */
4491 static int SquareColor(row, column)
4496 if (gameInfo.variant == VariantXiangqi) {
4497 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4499 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4501 } else if (row <= 4) {
4507 square_color = ((column + row) % 2) == 1;
4510 /* [hgm] holdings: next line makes all holdings squares light */
4511 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4513 return square_color;
4516 void DrawSquare(row, column, piece, do_flash)
4517 int row, column, do_flash;
4520 int square_color, x, y, direction, font_ascent, font_descent;
4523 XCharStruct overall;
4527 /* Calculate delay in milliseconds (2-delays per complete flash) */
4528 flash_delay = 500 / appData.flashRate;
4531 x = lineGap + ((BOARD_WIDTH-1)-column) *
4532 (squareSize + lineGap);
4533 y = lineGap + row * (squareSize + lineGap);
4535 x = lineGap + column * (squareSize + lineGap);
4536 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4537 (squareSize + lineGap);
4540 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4542 square_color = SquareColor(row, column);
4544 if ( // [HGM] holdings: blank out area between board and holdings
4545 column == BOARD_LEFT-1 || column == BOARD_RGHT
4546 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4547 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4548 BlankSquare(x, y, 2, EmptySquare, xBoardWindow, 1);
4550 // [HGM] print piece counts next to holdings
4551 string[1] = NULLCHAR;
4552 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4553 string[0] = '0' + piece;
4554 XTextExtents(countFontStruct, string, 1, &direction,
4555 &font_ascent, &font_descent, &overall);
4556 if (appData.monoMode) {
4557 XDrawImageString(xDisplay, xBoardWindow, countGC,
4558 x + squareSize - overall.width - 2,
4559 y + font_ascent + 1, string, 1);
4561 XDrawString(xDisplay, xBoardWindow, countGC,
4562 x + squareSize - overall.width - 2,
4563 y + font_ascent + 1, string, 1);
4566 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4567 string[0] = '0' + piece;
4568 XTextExtents(countFontStruct, string, 1, &direction,
4569 &font_ascent, &font_descent, &overall);
4570 if (appData.monoMode) {
4571 XDrawImageString(xDisplay, xBoardWindow, countGC,
4572 x + 2, y + font_ascent + 1, string, 1);
4574 XDrawString(xDisplay, xBoardWindow, countGC,
4575 x + 2, y + font_ascent + 1, string, 1);
4579 if (piece == EmptySquare || appData.blindfold) {
4580 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4582 drawfunc = ChooseDrawFunc();
4584 if (do_flash && appData.flashCount > 0) {
4585 for (i=0; i<appData.flashCount; ++i) {
4586 drawfunc(piece, square_color, x, y, xBoardWindow);
4587 XSync(xDisplay, False);
4588 do_flash_delay(flash_delay);
4590 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4591 XSync(xDisplay, False);
4592 do_flash_delay(flash_delay);
4595 drawfunc(piece, square_color, x, y, xBoardWindow);
4599 string[1] = NULLCHAR;
4600 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4601 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4602 string[0] = 'a' + column - BOARD_LEFT;
4603 XTextExtents(coordFontStruct, string, 1, &direction,
4604 &font_ascent, &font_descent, &overall);
4605 if (appData.monoMode) {
4606 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4607 x + squareSize - overall.width - 2,
4608 y + squareSize - font_descent - 1, string, 1);
4610 XDrawString(xDisplay, xBoardWindow, coordGC,
4611 x + squareSize - overall.width - 2,
4612 y + squareSize - font_descent - 1, string, 1);
4615 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4616 string[0] = ONE + row;
4617 XTextExtents(coordFontStruct, string, 1, &direction,
4618 &font_ascent, &font_descent, &overall);
4619 if (appData.monoMode) {
4620 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4621 x + 2, y + font_ascent + 1, string, 1);
4623 XDrawString(xDisplay, xBoardWindow, coordGC,
4624 x + 2, y + font_ascent + 1, string, 1);
4627 if(!partnerUp && marker[row][column]) {
4628 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4629 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4634 /* Why is this needed on some versions of X? */
4635 void EventProc(widget, unused, event)
4640 if (!XtIsRealized(widget))
4643 switch (event->type) {
4645 if (event->xexpose.count > 0) return; /* no clipping is done */
4646 XDrawPosition(widget, True, NULL);
4647 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4648 flipView = !flipView; partnerUp = !partnerUp;
4649 XDrawPosition(widget, True, NULL);
4650 flipView = !flipView; partnerUp = !partnerUp;
4654 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
4661 void DrawPosition(fullRedraw, board)
4662 /*Boolean*/int fullRedraw;
4665 XDrawPosition(boardWidget, fullRedraw, board);
4668 /* Returns 1 if there are "too many" differences between b1 and b2
4669 (i.e. more than 1 move was made) */
4670 static int too_many_diffs(b1, b2)
4676 for (i=0; i<BOARD_HEIGHT; ++i) {
4677 for (j=0; j<BOARD_WIDTH; ++j) {
4678 if (b1[i][j] != b2[i][j]) {
4679 if (++c > 4) /* Castling causes 4 diffs */
4687 /* Matrix describing castling maneuvers */
4688 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4689 static int castling_matrix[4][5] = {
4690 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4691 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4692 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4693 { 7, 7, 4, 5, 6 } /* 0-0, black */
4696 /* Checks whether castling occurred. If it did, *rrow and *rcol
4697 are set to the destination (row,col) of the rook that moved.
4699 Returns 1 if castling occurred, 0 if not.
4701 Note: Only handles a max of 1 castling move, so be sure
4702 to call too_many_diffs() first.
4704 static int check_castle_draw(newb, oldb, rrow, rcol)
4711 /* For each type of castling... */
4712 for (i=0; i<4; ++i) {
4713 r = castling_matrix[i];
4715 /* Check the 4 squares involved in the castling move */
4717 for (j=1; j<=4; ++j) {
4718 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4725 /* All 4 changed, so it must be a castling move */
4734 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4735 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4737 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4740 void DrawSeekBackground( int left, int top, int right, int bottom )
4742 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4745 void DrawSeekText(char *buf, int x, int y)
4747 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4750 void DrawSeekDot(int x, int y, int colorNr)
4752 int square = colorNr & 0x80;
4755 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4757 XFillRectangle(xDisplay, xBoardWindow, color,
4758 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4760 XFillArc(xDisplay, xBoardWindow, color,
4761 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4764 static int damage[2][BOARD_RANKS][BOARD_FILES];
4767 * event handler for redrawing the board
4769 void XDrawPosition(w, repaint, board)
4771 /*Boolean*/int repaint;
4775 static int lastFlipView = 0;
4776 static int lastBoardValid[2] = {0, 0};
4777 static Board lastBoard[2];
4780 int nr = twoBoards*partnerUp;
4782 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4784 if (board == NULL) {
4785 if (!lastBoardValid[nr]) return;
4786 board = lastBoard[nr];
4788 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4789 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4790 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Flip View"),
4795 * It would be simpler to clear the window with XClearWindow()
4796 * but this causes a very distracting flicker.
4799 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4801 if ( lineGap && IsDrawArrowEnabled())
4802 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4803 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4805 /* If too much changes (begin observing new game, etc.), don't
4807 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4809 /* Special check for castling so we don't flash both the king
4810 and the rook (just flash the king). */
4812 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4813 /* Draw rook with NO flashing. King will be drawn flashing later */
4814 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4815 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4819 /* First pass -- Draw (newly) empty squares and repair damage.
4820 This prevents you from having a piece show up twice while it
4821 is flashing on its new square */
4822 for (i = 0; i < BOARD_HEIGHT; i++)
4823 for (j = 0; j < BOARD_WIDTH; j++)
4824 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4825 || damage[nr][i][j]) {
4826 DrawSquare(i, j, board[i][j], 0);
4827 damage[nr][i][j] = False;
4830 /* Second pass -- Draw piece(s) in new position and flash them */
4831 for (i = 0; i < BOARD_HEIGHT; i++)
4832 for (j = 0; j < BOARD_WIDTH; j++)
4833 if (board[i][j] != lastBoard[nr][i][j]) {
4834 DrawSquare(i, j, board[i][j], do_flash);
4838 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4839 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4840 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4842 for (i = 0; i < BOARD_HEIGHT; i++)
4843 for (j = 0; j < BOARD_WIDTH; j++) {
4844 DrawSquare(i, j, board[i][j], 0);
4845 damage[nr][i][j] = False;
4849 CopyBoard(lastBoard[nr], board);
4850 lastBoardValid[nr] = 1;
4851 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4852 lastFlipView = flipView;
4854 /* Draw highlights */
4855 if (pm1X >= 0 && pm1Y >= 0) {
4856 drawHighlight(pm1X, pm1Y, prelineGC);
4858 if (pm2X >= 0 && pm2Y >= 0) {
4859 drawHighlight(pm2X, pm2Y, prelineGC);
4861 if (hi1X >= 0 && hi1Y >= 0) {
4862 drawHighlight(hi1X, hi1Y, highlineGC);
4864 if (hi2X >= 0 && hi2Y >= 0) {
4865 drawHighlight(hi2X, hi2Y, highlineGC);
4867 DrawArrowHighlight(hi1X, hi1Y, hi2X, hi2Y);
4869 /* If piece being dragged around board, must redraw that too */
4872 XSync(xDisplay, False);
4877 * event handler for redrawing the board
4879 void DrawPositionProc(w, event, prms, nprms)
4885 XDrawPosition(w, True, NULL);
4890 * event handler for parsing user moves
4892 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4893 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4894 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4895 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4896 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4897 // and at the end FinishMove() to perform the move after optional promotion popups.
4898 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4899 void HandleUserMove(w, event, prms, nprms)
4905 if (w != boardWidget || errorExitStatus != -1) return;
4906 if(nprms) shiftKey = !strcmp(prms[0], "1");
4909 if (event->type == ButtonPress) {
4910 XtPopdown(promotionShell);
4911 XtDestroyWidget(promotionShell);
4912 promotionUp = False;
4920 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4921 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4922 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4925 void AnimateUserMove (Widget w, XEvent * event,
4926 String * params, Cardinal * nParams)
4928 if(!PromoScroll(event->xmotion.x, event->xmotion.y))
4929 DragPieceMove(event->xmotion.x, event->xmotion.y);
4932 void HandlePV (Widget w, XEvent * event,
4933 String * params, Cardinal * nParams)
4934 { // [HGM] pv: walk PV
4935 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4938 static int savedIndex; /* gross that this is global */
4940 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
4943 XawTextPosition index, dummy;
4946 XawTextGetSelectionPos(w, &index, &dummy);
4947 XtSetArg(arg, XtNstring, &val);
4948 XtGetValues(w, &arg, 1);
4949 ReplaceComment(savedIndex, val);
4950 if(savedIndex != currentMove) ToNrEvent(savedIndex);
4951 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
4954 void EditCommentPopUp(index, title, text)
4959 if (text == NULL) text = "";
4960 NewCommentPopup(title, text, index);
4963 void ICSInputBoxPopUp()
4968 extern Option boxOptions[];
4970 void ICSInputSendText()
4977 edit = boxOptions[0].handle;
4979 XtSetArg(args[j], XtNstring, &val); j++;
4980 XtGetValues(edit, args, j);
4982 SendMultiLineToICS(val);
4983 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4984 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4987 void ICSInputBoxPopDown()
4992 void CommentPopUp(title, text)
4995 savedIndex = currentMove; // [HGM] vari
4996 NewCommentPopup(title, text, currentMove);
4999 void CommentPopDown()
5004 void FileNamePopUp(label, def, filter, proc, openMode)
5011 fileProc = proc; /* I can't see a way not */
5012 fileOpenMode = openMode; /* to use globals here */
5013 { // [HGM] use file-selector dialog stolen from Ghostview
5015 int index; // this is not supported yet
5017 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5018 (def[0] ? def : NULL), filter, openMode, NULL, &name))
5019 (void) (*fileProc)(f, index=0, name);
5023 void FileNamePopDown()
5025 if (!filenameUp) return;
5026 XtPopdown(fileNameShell);
5027 XtDestroyWidget(fileNameShell);
5032 void FileNameCallback(w, client_data, call_data)
5034 XtPointer client_data, call_data;
5039 XtSetArg(args[0], XtNlabel, &name);
5040 XtGetValues(w, args, 1);
5042 if (strcmp(name, _("cancel")) == 0) {
5047 FileNameAction(w, NULL, NULL, NULL);
5050 void FileNameAction(w, event, prms, nprms)
5062 name = XawDialogGetValueString(w = XtParent(w));
5064 if ((name != NULL) && (*name != NULLCHAR)) {
5065 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
5066 XtPopdown(w = XtParent(XtParent(w)));
5070 p = strrchr(buf, ' ');
5077 fullname = ExpandPathName(buf);
5079 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5082 f = fopen(fullname, fileOpenMode);
5084 DisplayError(_("Failed to open file"), errno);
5086 (void) (*fileProc)(f, index, buf);
5093 XtPopdown(w = XtParent(XtParent(w)));
5099 void PromotionPopUp()
5102 Widget dialog, layout;
5104 Dimension bw_width, pw_width;
5108 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5109 XtGetValues(boardWidget, args, j);
5112 XtSetArg(args[j], XtNresizable, True); j++;
5113 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5115 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5116 shellWidget, args, j);
5118 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5119 layoutArgs, XtNumber(layoutArgs));
5122 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5123 XtSetArg(args[j], XtNborderWidth, 0); j++;
5124 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5127 if(gameInfo.variant != VariantShogi) {
5128 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) {
5129 XawDialogAddButton(dialog, _("Warlord"), PromotionCallback,
5130 (XtPointer) dialog);
5131 XawDialogAddButton(dialog, _("General"), PromotionCallback,
5132 (XtPointer) dialog);
5133 XawDialogAddButton(dialog, _("Lieutenant"), PromotionCallback,
5134 (XtPointer) dialog);
5135 XawDialogAddButton(dialog, _("Captain"), PromotionCallback,
5136 (XtPointer) dialog);
5138 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5139 (XtPointer) dialog);
5140 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5141 (XtPointer) dialog);
5142 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5143 (XtPointer) dialog);
5144 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5145 (XtPointer) dialog);
5147 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5148 gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
5149 gameInfo.variant == VariantGiveaway) {
5150 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5151 (XtPointer) dialog);
5153 if(gameInfo.variant == VariantCapablanca ||
5154 gameInfo.variant == VariantGothic ||
5155 gameInfo.variant == VariantCapaRandom) {
5156 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5157 (XtPointer) dialog);
5158 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5159 (XtPointer) dialog);
5161 } else // [HGM] shogi
5163 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5164 (XtPointer) dialog);
5165 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5166 (XtPointer) dialog);
5168 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5169 (XtPointer) dialog);
5171 XtRealizeWidget(promotionShell);
5172 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5175 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5176 XtGetValues(promotionShell, args, j);
5178 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5179 lineGap + squareSize/3 +
5180 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5181 0 : 6*(squareSize + lineGap)), &x, &y);
5184 XtSetArg(args[j], XtNx, x); j++;
5185 XtSetArg(args[j], XtNy, y); j++;
5186 XtSetValues(promotionShell, args, j);
5188 XtPopup(promotionShell, XtGrabNone);
5193 void PromotionPopDown()
5195 if (!promotionUp) return;
5196 XtPopdown(promotionShell);
5197 XtDestroyWidget(promotionShell);
5198 promotionUp = False;
5201 void PromotionCallback(w, client_data, call_data)
5203 XtPointer client_data, call_data;
5209 XtSetArg(args[0], XtNlabel, &name);
5210 XtGetValues(w, args, 1);
5214 if (fromX == -1) return;
5216 if (strcmp(name, _("cancel")) == 0) {
5220 } else if (strcmp(name, _("Knight")) == 0) {
5222 } else if (strcmp(name, _("Promote")) == 0) {
5224 } else if (strcmp(name, _("Defer")) == 0) {
5227 promoChar = ToLower(name[0]);
5230 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5232 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5233 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5238 void ErrorCallback(w, client_data, call_data)
5240 XtPointer client_data, call_data;
5243 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5245 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5251 if (!errorUp) return;
5253 XtPopdown(errorShell);
5254 XtDestroyWidget(errorShell);
5255 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5258 void ErrorPopUp(title, label, modal)
5259 char *title, *label;
5263 Widget dialog, layout;
5267 Dimension bw_width, pw_width;
5268 Dimension pw_height;
5272 XtSetArg(args[i], XtNresizable, True); i++;
5273 XtSetArg(args[i], XtNtitle, title); i++;
5275 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5276 shellWidget, args, i);
5278 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5279 layoutArgs, XtNumber(layoutArgs));
5282 XtSetArg(args[i], XtNlabel, label); i++;
5283 XtSetArg(args[i], XtNborderWidth, 0); i++;
5284 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5287 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5289 XtRealizeWidget(errorShell);
5290 CatchDeleteWindow(errorShell, "ErrorPopDown");
5293 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5294 XtGetValues(boardWidget, args, i);
5296 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5297 XtSetArg(args[i], XtNheight, &pw_height); i++;
5298 XtGetValues(errorShell, args, i);
5301 /* This code seems to tickle an X bug if it is executed too soon
5302 after xboard starts up. The coordinates get transformed as if
5303 the main window was positioned at (0, 0).
5305 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5306 0 - pw_height + squareSize / 3, &x, &y);
5308 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5309 RootWindowOfScreen(XtScreen(boardWidget)),
5310 (bw_width - pw_width) / 2,
5311 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5315 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5318 XtSetArg(args[i], XtNx, x); i++;
5319 XtSetArg(args[i], XtNy, y); i++;
5320 XtSetValues(errorShell, args, i);
5323 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5326 /* Disable all user input other than deleting the window */
5327 static int frozen = 0;
5331 /* Grab by a widget that doesn't accept input */
5332 XtAddGrab(messageWidget, TRUE, FALSE);
5336 /* Undo a FreezeUI */
5339 if (!frozen) return;
5340 XtRemoveGrab(messageWidget);
5344 char *ModeToWidgetName(mode)
5348 case BeginningOfGame:
5349 if (appData.icsActive)
5350 return "menuMode.ICS Client";
5351 else if (appData.noChessProgram ||
5352 *appData.cmailGameName != NULLCHAR)
5353 return "menuMode.Edit Game";
5355 return "menuMode.Machine Black";
5356 case MachinePlaysBlack:
5357 return "menuMode.Machine Black";
5358 case MachinePlaysWhite:
5359 return "menuMode.Machine White";
5361 return "menuMode.Analysis Mode";
5363 return "menuMode.Analyze File";
5364 case TwoMachinesPlay:
5365 return "menuMode.Two Machines";
5367 return "menuMode.Edit Game";
5368 case PlayFromGameFile:
5369 return "menuFile.Load Game";
5371 return "menuMode.Edit Position";
5373 return "menuMode.Training";
5374 case IcsPlayingWhite:
5375 case IcsPlayingBlack:
5379 return "menuMode.ICS Client";
5386 void ModeHighlight()
5389 static int oldPausing = FALSE;
5390 static GameMode oldmode = (GameMode) -1;
5393 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5395 if (pausing != oldPausing) {
5396 oldPausing = pausing;
5398 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5400 XtSetArg(args[0], XtNleftBitmap, None);
5402 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5405 if (appData.showButtonBar) {
5406 /* Always toggle, don't set. Previous code messes up when
5407 invoked while the button is pressed, as releasing it
5408 toggles the state again. */
5411 XtSetArg(args[0], XtNbackground, &oldbg);
5412 XtSetArg(args[1], XtNforeground, &oldfg);
5413 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5415 XtSetArg(args[0], XtNbackground, oldfg);
5416 XtSetArg(args[1], XtNforeground, oldbg);
5418 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5422 wname = ModeToWidgetName(oldmode);
5423 if (wname != NULL) {
5424 XtSetArg(args[0], XtNleftBitmap, None);
5425 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5427 wname = ModeToWidgetName(gameMode);
5428 if (wname != NULL) {
5429 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5430 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5433 XtSetArg(args[0], XtNleftBitmap, matchMode && matchGame < appData.matchGames ? xMarkPixmap : None);
5434 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Machine Match"), args, 1);
5436 /* Maybe all the enables should be handled here, not just this one */
5437 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5438 gameMode == Training || gameMode == PlayFromGameFile);
5443 * Button/menu procedures
5445 void ResetProc(w, event, prms, nprms)
5454 int LoadGamePopUp(f, gameNumber, title)
5459 cmailMsgLoaded = FALSE;
5460 if (gameNumber == 0) {
5461 int error = GameListBuild(f);
5463 DisplayError(_("Cannot build game list"), error);
5464 } else if (!ListEmpty(&gameList) &&
5465 ((ListGame *) gameList.tailPred)->number > 1) {
5466 GameListPopUp(f, title);
5472 return LoadGame(f, gameNumber, title, FALSE);
5475 void LoadGameProc(w, event, prms, nprms)
5481 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5484 FileNamePopUp(_("Load game file name?"), "", ".pgn .game", LoadGamePopUp, "rb");
5487 void LoadNextGameProc(w, event, prms, nprms)
5496 void LoadPrevGameProc(w, event, prms, nprms)
5505 void ReloadGameProc(w, event, prms, nprms)
5514 void LoadNextPositionProc(w, event, prms, nprms)
5523 void LoadPrevPositionProc(w, event, prms, nprms)
5532 void ReloadPositionProc(w, event, prms, nprms)
5541 void LoadPositionProc(w, event, prms, nprms)
5547 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5550 FileNamePopUp(_("Load position file name?"), "", ".fen .epd .pos", LoadPosition, "rb");
5553 void SaveGameProc(w, event, prms, nprms)
5559 FileNamePopUp(_("Save game file name?"),
5560 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5561 appData.oldSaveStyle ? ".game" : ".pgn",
5565 void SavePositionProc(w, event, prms, nprms)
5571 FileNamePopUp(_("Save position file name?"),
5572 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5573 appData.oldSaveStyle ? ".pos" : ".fen",
5577 void ReloadCmailMsgProc(w, event, prms, nprms)
5583 ReloadCmailMsgEvent(FALSE);
5586 void MailMoveProc(w, event, prms, nprms)
5595 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5596 char *selected_fen_position=NULL;
5599 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5600 Atom *type_return, XtPointer *value_return,
5601 unsigned long *length_return, int *format_return)
5603 char *selection_tmp;
5605 if (!selected_fen_position) return False; /* should never happen */
5606 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5607 /* note: since no XtSelectionDoneProc was registered, Xt will
5608 * automatically call XtFree on the value returned. So have to
5609 * make a copy of it allocated with XtMalloc */
5610 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5611 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
5613 *value_return=selection_tmp;
5614 *length_return=strlen(selection_tmp);
5615 *type_return=*target;
5616 *format_return = 8; /* bits per byte */
5618 } else if (*target == XA_TARGETS(xDisplay)) {
5619 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5620 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5621 targets_tmp[1] = XA_STRING;
5622 *value_return = targets_tmp;
5623 *type_return = XA_ATOM;
5625 *format_return = 8 * sizeof(Atom);
5626 if (*format_return > 32) {
5627 *length_return *= *format_return / 32;
5628 *format_return = 32;
5636 /* note: when called from menu all parameters are NULL, so no clue what the
5637 * Widget which was clicked on was, or what the click event was
5639 void CopyPositionProc(w, event, prms, nprms)
5646 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5647 * have a notion of a position that is selected but not copied.
5648 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5650 if(gameMode == EditPosition) EditPositionDone(TRUE);
5651 if (selected_fen_position) free(selected_fen_position);
5652 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5653 if (!selected_fen_position) return;
5654 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5656 SendPositionSelection,
5657 NULL/* lose_ownership_proc */ ,
5658 NULL/* transfer_done_proc */);
5659 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5661 SendPositionSelection,
5662 NULL/* lose_ownership_proc */ ,
5663 NULL/* transfer_done_proc */);
5666 /* function called when the data to Paste is ready */
5668 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5669 Atom *type, XtPointer value, unsigned long *len, int *format)
5672 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5673 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5674 EditPositionPasteFEN(fenstr);
5678 /* called when Paste Position button is pressed,
5679 * all parameters will be NULL */
5680 void PastePositionProc(w, event, prms, nprms)
5686 XtGetSelectionValue(menuBarWidget,
5687 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5688 /* (XtSelectionCallbackProc) */ PastePositionCB,
5689 NULL, /* client_data passed to PastePositionCB */
5691 /* better to use the time field from the event that triggered the
5692 * call to this function, but that isn't trivial to get
5700 SendGameSelection(Widget w, Atom *selection, Atom *target,
5701 Atom *type_return, XtPointer *value_return,
5702 unsigned long *length_return, int *format_return)
5704 char *selection_tmp;
5706 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5707 FILE* f = fopen(gameCopyFilename, "r");
5710 if (f == NULL) return False;
5714 selection_tmp = XtMalloc(len + 1);
5715 count = fread(selection_tmp, 1, len, f);
5718 XtFree(selection_tmp);
5721 selection_tmp[len] = NULLCHAR;
5722 *value_return = selection_tmp;
5723 *length_return = len;
5724 *type_return = *target;
5725 *format_return = 8; /* bits per byte */
5727 } else if (*target == XA_TARGETS(xDisplay)) {
5728 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5729 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5730 targets_tmp[1] = XA_STRING;
5731 *value_return = targets_tmp;
5732 *type_return = XA_ATOM;
5734 *format_return = 8 * sizeof(Atom);
5735 if (*format_return > 32) {
5736 *length_return *= *format_return / 32;
5737 *format_return = 32;
5745 void CopySomething()
5748 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5749 * have a notion of a game that is selected but not copied.
5750 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5752 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5755 NULL/* lose_ownership_proc */ ,
5756 NULL/* transfer_done_proc */);
5757 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5760 NULL/* lose_ownership_proc */ ,
5761 NULL/* transfer_done_proc */);
5764 /* note: when called from menu all parameters are NULL, so no clue what the
5765 * Widget which was clicked on was, or what the click event was
5767 void CopyGameProc(w, event, prms, nprms)
5775 ret = SaveGameToFile(gameCopyFilename, FALSE);
5781 void CopyGameListProc(w, event, prms, nprms)
5787 if(!SaveGameListAsText(fopen(gameCopyFilename, "w"))) return;
5791 /* function called when the data to Paste is ready */
5793 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5794 Atom *type, XtPointer value, unsigned long *len, int *format)
5797 if (value == NULL || *len == 0) {
5798 return; /* nothing had been selected to copy */
5800 f = fopen(gamePasteFilename, "w");
5802 DisplayError(_("Can't open temp file"), errno);
5805 fwrite(value, 1, *len, f);
5808 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5811 /* called when Paste Game button is pressed,
5812 * all parameters will be NULL */
5813 void PasteGameProc(w, event, prms, nprms)
5819 XtGetSelectionValue(menuBarWidget,
5820 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5821 /* (XtSelectionCallbackProc) */ PasteGameCB,
5822 NULL, /* client_data passed to PasteGameCB */
5824 /* better to use the time field from the event that triggered the
5825 * call to this function, but that isn't trivial to get
5835 SaveGameProc(NULL, NULL, NULL, NULL);
5839 void QuitProc(w, event, prms, nprms)
5848 void PauseProc(w, event, prms, nprms)
5858 void MachineBlackProc(w, event, prms, nprms)
5864 MachineBlackEvent();
5867 void MachineWhiteProc(w, event, prms, nprms)
5873 MachineWhiteEvent();
5876 void AnalyzeModeProc(w, event, prms, nprms)
5884 if (!first.analysisSupport) {
5885 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5886 DisplayError(buf, 0);
5889 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5890 if (appData.icsActive) {
5891 if (gameMode != IcsObserving) {
5892 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
5893 DisplayError(buf, 0);
5895 if (appData.icsEngineAnalyze) {
5896 if (appData.debugMode)
5897 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5903 /* if enable, use want disable icsEngineAnalyze */
5904 if (appData.icsEngineAnalyze) {
5909 appData.icsEngineAnalyze = TRUE;
5910 if (appData.debugMode)
5911 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5913 #ifndef OPTIONSDIALOG
5914 if (!appData.showThinking)
5915 ShowThinkingProc(w,event,prms,nprms);
5921 void AnalyzeFileProc(w, event, prms, nprms)
5927 if (!first.analysisSupport) {
5929 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5930 DisplayError(buf, 0);
5934 #ifndef OPTIONSDIALOG
5935 if (!appData.showThinking)
5936 ShowThinkingProc(w,event,prms,nprms);
5939 FileNamePopUp(_("File to analyze"), "", ".pgn .game", LoadGamePopUp, "rb");
5940 AnalysisPeriodicEvent(1);
5943 void TwoMachinesProc(w, event, prms, nprms)
5952 void MatchProc(w, event, prms, nprms)
5961 void IcsClientProc(w, event, prms, nprms)
5970 void EditGameProc(w, event, prms, nprms)
5979 void EditPositionProc(w, event, prms, nprms)
5985 EditPositionEvent();
5988 void TrainingProc(w, event, prms, nprms)
5997 void EditCommentProc(w, event, prms, nprms)
6005 if (PopDown(1)) { // popdown succesful
6007 XtSetArg(args[j], XtNleftBitmap, None); j++;
6008 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"), args, j);
6009 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"), args, j);
6010 } else // was not up
6014 void IcsInputBoxProc(w, event, prms, nprms)
6020 if (!PopDown(4)) ICSInputBoxPopUp();
6023 void AcceptProc(w, event, prms, nprms)
6032 void DeclineProc(w, event, prms, nprms)
6041 void RematchProc(w, event, prms, nprms)
6050 void CallFlagProc(w, event, prms, nprms)
6059 void DrawProc(w, event, prms, nprms)
6068 void AbortProc(w, event, prms, nprms)
6077 void AdjournProc(w, event, prms, nprms)
6086 void ResignProc(w, event, prms, nprms)
6095 void AdjuWhiteProc(w, event, prms, nprms)
6101 UserAdjudicationEvent(+1);
6104 void AdjuBlackProc(w, event, prms, nprms)
6110 UserAdjudicationEvent(-1);
6113 void AdjuDrawProc(w, event, prms, nprms)
6119 UserAdjudicationEvent(0);
6122 void EnterKeyProc(w, event, prms, nprms)
6128 if (shellUp[4] == True)
6132 void UpKeyProc(w, event, prms, nprms)
6137 { // [HGM] input: let up-arrow recall previous line from history
6144 if (!shellUp[4]) return;
6145 edit = boxOptions[0].handle;
6147 XtSetArg(args[j], XtNstring, &val); j++;
6148 XtGetValues(edit, args, j);
6149 val = PrevInHistory(val);
6150 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6151 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6153 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6154 XawTextReplace(edit, 0, 0, &t);
6155 XawTextSetInsertionPoint(edit, 9999);
6159 void DownKeyProc(w, event, prms, nprms)
6164 { // [HGM] input: let down-arrow recall next line from history
6169 if (!shellUp[4]) return;
6170 edit = boxOptions[0].handle;
6171 val = NextInHistory();
6172 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6173 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6175 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6176 XawTextReplace(edit, 0, 0, &t);
6177 XawTextSetInsertionPoint(edit, 9999);
6181 void StopObservingProc(w, event, prms, nprms)
6187 StopObservingEvent();
6190 void StopExaminingProc(w, event, prms, nprms)
6196 StopExaminingEvent();
6199 void UploadProc(w, event, prms, nprms)
6209 void ForwardProc(w, event, prms, nprms)
6219 void BackwardProc(w, event, prms, nprms)
6228 void ToStartProc(w, event, prms, nprms)
6237 void ToEndProc(w, event, prms, nprms)
6246 void RevertProc(w, event, prms, nprms)
6255 void AnnotateProc(w, event, prms, nprms)
6264 void TruncateGameProc(w, event, prms, nprms)
6270 TruncateGameEvent();
6272 void RetractMoveProc(w, event, prms, nprms)
6281 void MoveNowProc(w, event, prms, nprms)
6290 void FlipViewProc(w, event, prms, nprms)
6296 flipView = !flipView;
6297 DrawPosition(True, NULL);
6300 void PonderNextMoveProc(w, event, prms, nprms)
6308 PonderNextMoveEvent(!appData.ponderNextMove);
6309 #ifndef OPTIONSDIALOG
6310 if (appData.ponderNextMove) {
6311 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6313 XtSetArg(args[0], XtNleftBitmap, None);
6315 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6320 #ifndef OPTIONSDIALOG
6321 void AlwaysQueenProc(w, event, prms, nprms)
6329 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6331 if (appData.alwaysPromoteToQueen) {
6332 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6334 XtSetArg(args[0], XtNleftBitmap, None);
6336 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6340 void AnimateDraggingProc(w, event, prms, nprms)
6348 appData.animateDragging = !appData.animateDragging;
6350 if (appData.animateDragging) {
6351 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6354 XtSetArg(args[0], XtNleftBitmap, None);
6356 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6360 void AnimateMovingProc(w, event, prms, nprms)
6368 appData.animate = !appData.animate;
6370 if (appData.animate) {
6371 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6374 XtSetArg(args[0], XtNleftBitmap, None);
6376 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6380 void AutoflagProc(w, event, prms, nprms)
6388 appData.autoCallFlag = !appData.autoCallFlag;
6390 if (appData.autoCallFlag) {
6391 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6393 XtSetArg(args[0], XtNleftBitmap, None);
6395 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6399 void AutoflipProc(w, event, prms, nprms)
6407 appData.autoFlipView = !appData.autoFlipView;
6409 if (appData.autoFlipView) {
6410 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6412 XtSetArg(args[0], XtNleftBitmap, None);
6414 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6418 void BlindfoldProc(w, event, prms, nprms)
6426 appData.blindfold = !appData.blindfold;
6428 if (appData.blindfold) {
6429 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6431 XtSetArg(args[0], XtNleftBitmap, None);
6433 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6436 DrawPosition(True, NULL);
6439 void TestLegalityProc(w, event, prms, nprms)
6447 appData.testLegality = !appData.testLegality;
6449 if (appData.testLegality) {
6450 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6452 XtSetArg(args[0], XtNleftBitmap, None);
6454 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6459 void FlashMovesProc(w, event, prms, nprms)
6467 if (appData.flashCount == 0) {
6468 appData.flashCount = 3;
6470 appData.flashCount = -appData.flashCount;
6473 if (appData.flashCount > 0) {
6474 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6476 XtSetArg(args[0], XtNleftBitmap, None);
6478 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6483 void HighlightDraggingProc(w, event, prms, nprms)
6491 appData.highlightDragging = !appData.highlightDragging;
6493 if (appData.highlightDragging) {
6494 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6496 XtSetArg(args[0], XtNleftBitmap, None);
6498 XtSetValues(XtNameToWidget(menuBarWidget,
6499 "menuOptions.Highlight Dragging"), args, 1);
6503 void HighlightLastMoveProc(w, event, prms, nprms)
6511 appData.highlightLastMove = !appData.highlightLastMove;
6513 if (appData.highlightLastMove) {
6514 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6516 XtSetArg(args[0], XtNleftBitmap, None);
6518 XtSetValues(XtNameToWidget(menuBarWidget,
6519 "menuOptions.Highlight Last Move"), args, 1);
6522 void HighlightArrowProc(w, event, prms, nprms)
6530 appData.highlightMoveWithArrow = !appData.highlightMoveWithArrow;
6532 if (appData.highlightMoveWithArrow) {
6533 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6535 XtSetArg(args[0], XtNleftBitmap, None);
6537 XtSetValues(XtNameToWidget(menuBarWidget,
6538 "menuOptions.Arrow"), args, 1);
6542 void IcsAlarmProc(w, event, prms, nprms)
6550 appData.icsAlarm = !appData.icsAlarm;
6552 if (appData.icsAlarm) {
6553 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6555 XtSetArg(args[0], XtNleftBitmap, None);
6557 XtSetValues(XtNameToWidget(menuBarWidget,
6558 "menuOptions.ICS Alarm"), args, 1);
6562 void MoveSoundProc(w, event, prms, nprms)
6570 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6572 if (appData.ringBellAfterMoves) {
6573 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6575 XtSetArg(args[0], XtNleftBitmap, None);
6577 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6581 void OneClickProc(w, event, prms, nprms)
6589 appData.oneClick = !appData.oneClick;
6591 if (appData.oneClick) {
6592 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6594 XtSetArg(args[0], XtNleftBitmap, None);
6596 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.OneClick"),
6600 void PeriodicUpdatesProc(w, event, prms, nprms)
6608 PeriodicUpdatesEvent(!appData.periodicUpdates);
6610 if (appData.periodicUpdates) {
6611 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6613 XtSetArg(args[0], XtNleftBitmap, None);
6615 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6619 void PopupExitMessageProc(w, event, prms, nprms)
6627 appData.popupExitMessage = !appData.popupExitMessage;
6629 if (appData.popupExitMessage) {
6630 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6632 XtSetArg(args[0], XtNleftBitmap, None);
6634 XtSetValues(XtNameToWidget(menuBarWidget,
6635 "menuOptions.Popup Exit Message"), args, 1);
6638 void PopupMoveErrorsProc(w, event, prms, nprms)
6646 appData.popupMoveErrors = !appData.popupMoveErrors;
6648 if (appData.popupMoveErrors) {
6649 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6651 XtSetArg(args[0], XtNleftBitmap, None);
6653 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6658 void PremoveProc(w, event, prms, nprms)
6666 appData.premove = !appData.premove;
6668 if (appData.premove) {
6669 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6671 XtSetArg(args[0], XtNleftBitmap, None);
6673 XtSetValues(XtNameToWidget(menuBarWidget,
6674 "menuOptions.Premove"), args, 1);
6678 void ShowCoordsProc(w, event, prms, nprms)
6686 appData.showCoords = !appData.showCoords;
6688 if (appData.showCoords) {
6689 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6691 XtSetArg(args[0], XtNleftBitmap, None);
6693 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6696 DrawPosition(True, NULL);
6699 void ShowThinkingProc(w, event, prms, nprms)
6705 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6706 ShowThinkingEvent();
6709 void HideThinkingProc(w, event, prms, nprms)
6717 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6718 ShowThinkingEvent();
6720 if (appData.hideThinkingFromHuman) {
6721 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6723 XtSetArg(args[0], XtNleftBitmap, None);
6725 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6730 void SaveOnExitProc(w, event, prms, nprms)
6738 saveSettingsOnExit = !saveSettingsOnExit;
6740 if (saveSettingsOnExit) {
6741 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6743 XtSetArg(args[0], XtNleftBitmap, None);
6745 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6749 void SaveSettingsProc(w, event, prms, nprms)
6755 SaveSettings(settingsFileName);
6758 void InfoProc(w, event, prms, nprms)
6765 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6770 void ManProc(w, event, prms, nprms)
6778 if (nprms && *nprms > 0)
6782 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6786 void HintProc(w, event, prms, nprms)
6795 void BookProc(w, event, prms, nprms)
6804 void AboutProc(w, event, prms, nprms)
6812 char *zippy = " (with Zippy code)";
6816 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6817 programVersion, zippy,
6818 "Copyright 1991 Digital Equipment Corporation",
6819 "Enhancements Copyright 1992-2009 Free Software Foundation",
6820 "Enhancements Copyright 2005 Alessandro Scotti",
6821 PACKAGE, " is free software and carries NO WARRANTY;",
6822 "see the file COPYING for more information.");
6823 ErrorPopUp(_("About XBoard"), buf, FALSE);
6826 void DebugProc(w, event, prms, nprms)
6832 appData.debugMode = !appData.debugMode;
6835 void AboutGameProc(w, event, prms, nprms)
6844 void NothingProc(w, event, prms, nprms)
6853 void Iconify(w, event, prms, nprms)
6862 XtSetArg(args[0], XtNiconic, True);
6863 XtSetValues(shellWidget, args, 1);
6866 void DisplayMessage(message, extMessage)
6867 char *message, *extMessage;
6869 /* display a message in the message widget */
6878 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
6883 message = extMessage;
6887 safeStrCpy(lastMsg, message, MSG_SIZ); // [HGM] make available
6889 /* need to test if messageWidget already exists, since this function
6890 can also be called during the startup, if for example a Xresource
6891 is not set up correctly */
6894 XtSetArg(arg, XtNlabel, message);
6895 XtSetValues(messageWidget, &arg, 1);
6901 void DisplayTitle(text)
6906 char title[MSG_SIZ];
6909 if (text == NULL) text = "";
6911 if (appData.titleInWindow) {
6913 XtSetArg(args[i], XtNlabel, text); i++;
6914 XtSetValues(titleWidget, args, i);
6917 if (*text != NULLCHAR) {
6918 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
6919 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
6920 } else if (appData.icsActive) {
6921 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
6922 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
6923 } else if (appData.cmailGameName[0] != NULLCHAR) {
6924 snprintf(icon, sizeof(icon), "%s", "CMail");
6925 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
6927 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
6928 } else if (gameInfo.variant == VariantGothic) {
6929 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6930 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
6933 } else if (gameInfo.variant == VariantFalcon) {
6934 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6935 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
6937 } else if (appData.noChessProgram) {
6938 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6939 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
6941 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
6942 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
6945 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
6946 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
6947 XtSetValues(shellWidget, args, i);
6948 XSync(xDisplay, False);
6953 DisplayError(message, error)
6960 if (appData.debugMode || appData.matchMode) {
6961 fprintf(stderr, "%s: %s\n", programName, message);
6964 if (appData.debugMode || appData.matchMode) {
6965 fprintf(stderr, "%s: %s: %s\n",
6966 programName, message, strerror(error));
6968 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6971 ErrorPopUp(_("Error"), message, FALSE);
6975 void DisplayMoveError(message)
6980 DrawPosition(FALSE, NULL);
6981 if (appData.debugMode || appData.matchMode) {
6982 fprintf(stderr, "%s: %s\n", programName, message);
6984 if (appData.popupMoveErrors) {
6985 ErrorPopUp(_("Error"), message, FALSE);
6987 DisplayMessage(message, "");
6992 void DisplayFatalError(message, error, status)
6998 errorExitStatus = status;
7000 fprintf(stderr, "%s: %s\n", programName, message);
7002 fprintf(stderr, "%s: %s: %s\n",
7003 programName, message, strerror(error));
7004 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7007 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7008 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7014 void DisplayInformation(message)
7018 ErrorPopUp(_("Information"), message, TRUE);
7021 void DisplayNote(message)
7025 ErrorPopUp(_("Note"), message, FALSE);
7029 NullXErrorCheck(dpy, error_event)
7031 XErrorEvent *error_event;
7036 void DisplayIcsInteractionTitle(message)
7039 if (oldICSInteractionTitle == NULL) {
7040 /* Magic to find the old window title, adapted from vim */
7041 char *wina = getenv("WINDOWID");
7043 Window win = (Window) atoi(wina);
7044 Window root, parent, *children;
7045 unsigned int nchildren;
7046 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7048 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7049 if (!XQueryTree(xDisplay, win, &root, &parent,
7050 &children, &nchildren)) break;
7051 if (children) XFree((void *)children);
7052 if (parent == root || parent == 0) break;
7055 XSetErrorHandler(oldHandler);
7057 if (oldICSInteractionTitle == NULL) {
7058 oldICSInteractionTitle = "xterm";
7061 printf("\033]0;%s\007", message);
7065 char pendingReplyPrefix[MSG_SIZ];
7066 ProcRef pendingReplyPR;
7068 void AskQuestionProc(w, event, prms, nprms)
7075 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7079 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7082 void AskQuestionPopDown()
7084 if (!askQuestionUp) return;
7085 XtPopdown(askQuestionShell);
7086 XtDestroyWidget(askQuestionShell);
7087 askQuestionUp = False;
7090 void AskQuestionReplyAction(w, event, prms, nprms)
7100 reply = XawDialogGetValueString(w = XtParent(w));
7101 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
7102 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
7103 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
7104 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
7105 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7106 AskQuestionPopDown();
7108 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7111 void AskQuestionCallback(w, client_data, call_data)
7113 XtPointer client_data, call_data;
7118 XtSetArg(args[0], XtNlabel, &name);
7119 XtGetValues(w, args, 1);
7121 if (strcmp(name, _("cancel")) == 0) {
7122 AskQuestionPopDown();
7124 AskQuestionReplyAction(w, NULL, NULL, NULL);
7128 void AskQuestion(title, question, replyPrefix, pr)
7129 char *title, *question, *replyPrefix;
7133 Widget popup, layout, dialog, edit;
7139 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
7140 pendingReplyPR = pr;
7143 XtSetArg(args[i], XtNresizable, True); i++;
7144 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7145 askQuestionShell = popup =
7146 XtCreatePopupShell(title, transientShellWidgetClass,
7147 shellWidget, args, i);
7150 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7151 layoutArgs, XtNumber(layoutArgs));
7154 XtSetArg(args[i], XtNlabel, question); i++;
7155 XtSetArg(args[i], XtNvalue, ""); i++;
7156 XtSetArg(args[i], XtNborderWidth, 0); i++;
7157 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7160 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7161 (XtPointer) dialog);
7162 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7163 (XtPointer) dialog);
7165 XtRealizeWidget(popup);
7166 CatchDeleteWindow(popup, "AskQuestionPopDown");
7168 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7169 &x, &y, &win_x, &win_y, &mask);
7171 XtSetArg(args[0], XtNx, x - 10);
7172 XtSetArg(args[1], XtNy, y - 30);
7173 XtSetValues(popup, args, 2);
7175 XtPopup(popup, XtGrabExclusive);
7176 askQuestionUp = True;
7178 edit = XtNameToWidget(dialog, "*value");
7179 XtSetKeyboardFocus(popup, edit);
7187 if (*name == NULLCHAR) {
7189 } else if (strcmp(name, "$") == 0) {
7190 putc(BELLCHAR, stderr);
7193 char *prefix = "", *sep = "";
7194 if(!strchr(name, '/')) { prefix = appData.soundDirectory; sep = "/"; }
7195 snprintf(buf, sizeof(buf), "%s '%s%s%s' &", appData.soundProgram, prefix, sep, name);
7203 PlaySound(appData.soundMove);
7209 PlaySound(appData.soundIcsWin);
7215 PlaySound(appData.soundIcsLoss);
7221 PlaySound(appData.soundIcsDraw);
7225 PlayIcsUnfinishedSound()
7227 PlaySound(appData.soundIcsUnfinished);
7233 PlaySound(appData.soundIcsAlarm);
7239 PlaySound(appData.soundTell);
7245 system("stty echo");
7252 system("stty -echo");
7257 Colorize(cc, continuation)
7262 int count, outCount, error;
7264 if (textColors[(int)cc].bg > 0) {
7265 if (textColors[(int)cc].fg > 0) {
7266 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7267 textColors[(int)cc].fg, textColors[(int)cc].bg);
7269 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7270 textColors[(int)cc].bg);
7273 if (textColors[(int)cc].fg > 0) {
7274 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7275 textColors[(int)cc].fg);
7277 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7280 count = strlen(buf);
7281 outCount = OutputToProcess(NoProc, buf, count, &error);
7282 if (outCount < count) {
7283 DisplayFatalError(_("Error writing to display"), error, 1);
7286 if (continuation) return;
7289 PlaySound(appData.soundShout);
7292 PlaySound(appData.soundSShout);
7295 PlaySound(appData.soundChannel1);
7298 PlaySound(appData.soundChannel);
7301 PlaySound(appData.soundKibitz);
7304 PlaySound(appData.soundTell);
7306 case ColorChallenge:
7307 PlaySound(appData.soundChallenge);
7310 PlaySound(appData.soundRequest);
7313 PlaySound(appData.soundSeek);
7324 return getpwuid(getuid())->pw_name;
7328 ExpandPathName(path)
7331 static char static_buf[4*MSG_SIZ];
7332 char *d, *s, buf[4*MSG_SIZ];
7338 while (*s && isspace(*s))
7347 if (*(s+1) == '/') {
7348 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7352 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7353 { char *p; if(p = strchr(buf, '/')) *p = 0; }
7354 pwd = getpwnam(buf);
7357 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7361 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7362 strcat(d, strchr(s+1, '/'));
7366 safeStrCpy(d, s, 4*MSG_SIZ );
7373 static char host_name[MSG_SIZ];
7375 #if HAVE_GETHOSTNAME
7376 gethostname(host_name, MSG_SIZ);
7378 #else /* not HAVE_GETHOSTNAME */
7379 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7380 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7382 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7384 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7385 #endif /* not HAVE_GETHOSTNAME */
7388 XtIntervalId delayedEventTimerXID = 0;
7389 DelayedEventCallback delayedEventCallback = 0;
7394 delayedEventTimerXID = 0;
7395 delayedEventCallback();
7399 ScheduleDelayedEvent(cb, millisec)
7400 DelayedEventCallback cb; long millisec;
7402 if(delayedEventTimerXID && delayedEventCallback == cb)
7403 // [HGM] alive: replace, rather than add or flush identical event
7404 XtRemoveTimeOut(delayedEventTimerXID);
7405 delayedEventCallback = cb;
7406 delayedEventTimerXID =
7407 XtAppAddTimeOut(appContext, millisec,
7408 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7411 DelayedEventCallback
7414 if (delayedEventTimerXID) {
7415 return delayedEventCallback;
7422 CancelDelayedEvent()
7424 if (delayedEventTimerXID) {
7425 XtRemoveTimeOut(delayedEventTimerXID);
7426 delayedEventTimerXID = 0;
7430 XtIntervalId loadGameTimerXID = 0;
7432 int LoadGameTimerRunning()
7434 return loadGameTimerXID != 0;
7437 int StopLoadGameTimer()
7439 if (loadGameTimerXID != 0) {
7440 XtRemoveTimeOut(loadGameTimerXID);
7441 loadGameTimerXID = 0;
7449 LoadGameTimerCallback(arg, id)
7453 loadGameTimerXID = 0;
7458 StartLoadGameTimer(millisec)
7462 XtAppAddTimeOut(appContext, millisec,
7463 (XtTimerCallbackProc) LoadGameTimerCallback,
7467 XtIntervalId analysisClockXID = 0;
7470 AnalysisClockCallback(arg, id)
7474 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7475 || appData.icsEngineAnalyze) { // [DM]
7476 AnalysisPeriodicEvent(0);
7477 StartAnalysisClock();
7482 StartAnalysisClock()
7485 XtAppAddTimeOut(appContext, 2000,
7486 (XtTimerCallbackProc) AnalysisClockCallback,
7490 XtIntervalId clockTimerXID = 0;
7492 int ClockTimerRunning()
7494 return clockTimerXID != 0;
7497 int StopClockTimer()
7499 if (clockTimerXID != 0) {
7500 XtRemoveTimeOut(clockTimerXID);
7509 ClockTimerCallback(arg, id)
7518 StartClockTimer(millisec)
7522 XtAppAddTimeOut(appContext, millisec,
7523 (XtTimerCallbackProc) ClockTimerCallback,
7528 DisplayTimerLabel(w, color, timer, highlight)
7537 /* check for low time warning */
7538 Pixel foregroundOrWarningColor = timerForegroundPixel;
7541 appData.lowTimeWarning &&
7542 (timer / 1000) < appData.icsAlarmTime)
7543 foregroundOrWarningColor = lowTimeWarningColor;
7545 if (appData.clockMode) {
7546 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7547 XtSetArg(args[0], XtNlabel, buf);
7549 snprintf(buf, MSG_SIZ, "%s ", color);
7550 XtSetArg(args[0], XtNlabel, buf);
7555 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7556 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7558 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7559 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7562 XtSetValues(w, args, 3);
7566 DisplayWhiteClock(timeRemaining, highlight)
7572 if(appData.noGUI) return;
7573 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7574 if (highlight && iconPixmap == bIconPixmap) {
7575 iconPixmap = wIconPixmap;
7576 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7577 XtSetValues(shellWidget, args, 1);
7582 DisplayBlackClock(timeRemaining, highlight)
7588 if(appData.noGUI) return;
7589 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7590 if (highlight && iconPixmap == wIconPixmap) {
7591 iconPixmap = bIconPixmap;
7592 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7593 XtSetValues(shellWidget, args, 1);
7611 int StartChildProcess(cmdLine, dir, pr)
7618 int to_prog[2], from_prog[2];
7622 if (appData.debugMode) {
7623 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7626 /* We do NOT feed the cmdLine to the shell; we just
7627 parse it into blank-separated arguments in the
7628 most simple-minded way possible.
7631 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7634 while(*p == ' ') p++;
7636 if(*p == '"' || *p == '\'')
7637 p = strchr(++argv[i-1], *p);
7638 else p = strchr(p, ' ');
7639 if (p == NULL) break;
7644 SetUpChildIO(to_prog, from_prog);
7646 if ((pid = fork()) == 0) {
7648 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7649 close(to_prog[1]); // first close the unused pipe ends
7650 close(from_prog[0]);
7651 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7652 dup2(from_prog[1], 1);
7653 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7654 close(from_prog[1]); // and closing again loses one of the pipes!
7655 if(fileno(stderr) >= 2) // better safe than sorry...
7656 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7658 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7663 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7665 execvp(argv[0], argv);
7667 /* If we get here, exec failed */
7672 /* Parent process */
7674 close(from_prog[1]);
7676 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7679 cp->fdFrom = from_prog[0];
7680 cp->fdTo = to_prog[1];
7685 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7686 static RETSIGTYPE AlarmCallBack(int n)
7692 DestroyChildProcess(pr, signalType)
7696 ChildProc *cp = (ChildProc *) pr;
7698 if (cp->kind != CPReal) return;
7700 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7701 signal(SIGALRM, AlarmCallBack);
7703 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7704 kill(cp->pid, SIGKILL); // kill it forcefully
7705 wait((int *) 0); // and wait again
7709 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7711 /* Process is exiting either because of the kill or because of
7712 a quit command sent by the backend; either way, wait for it to die.
7721 InterruptChildProcess(pr)
7724 ChildProc *cp = (ChildProc *) pr;
7726 if (cp->kind != CPReal) return;
7727 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7730 int OpenTelnet(host, port, pr)
7735 char cmdLine[MSG_SIZ];
7737 if (port[0] == NULLCHAR) {
7738 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7740 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7742 return StartChildProcess(cmdLine, "", pr);
7745 int OpenTCP(host, port, pr)
7751 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7752 #else /* !OMIT_SOCKETS */
7753 struct addrinfo hints;
7754 struct addrinfo *ais, *ai;
7759 memset(&hints, 0, sizeof(hints));
7760 hints.ai_family = AF_UNSPEC;
7761 hints.ai_socktype = SOCK_STREAM;
7763 error = getaddrinfo(host, port, &hints, &ais);
7765 /* a getaddrinfo error is not an errno, so can't return it */
7766 fprintf(debugFP, "getaddrinfo(%s, %s): %s\n",
7767 host, port, gai_strerror(error));
7771 for (ai = ais; ai != NULL; ai = ai->ai_next) {
7772 if ((s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) < 0) {
7776 if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0) {
7789 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7795 #endif /* !OMIT_SOCKETS */
7800 int OpenCommPort(name, pr)
7807 fd = open(name, 2, 0);
7808 if (fd < 0) return errno;
7810 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7820 int OpenLoopback(pr)
7826 SetUpChildIO(to, from);
7828 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7831 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7838 int OpenRcmd(host, user, cmd, pr)
7839 char *host, *user, *cmd;
7842 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7846 #define INPUT_SOURCE_BUF_SIZE 8192
7855 char buf[INPUT_SOURCE_BUF_SIZE];
7860 DoInputCallback(closure, source, xid)
7865 InputSource *is = (InputSource *) closure;
7870 if (is->lineByLine) {
7871 count = read(is->fd, is->unused,
7872 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7874 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7877 is->unused += count;
7879 while (p < is->unused) {
7880 q = memchr(p, '\n', is->unused - p);
7881 if (q == NULL) break;
7883 (is->func)(is, is->closure, p, q - p, 0);
7887 while (p < is->unused) {
7892 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
7897 (is->func)(is, is->closure, is->buf, count, error);
7901 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
7908 ChildProc *cp = (ChildProc *) pr;
7910 is = (InputSource *) calloc(1, sizeof(InputSource));
7911 is->lineByLine = lineByLine;
7915 is->fd = fileno(stdin);
7917 is->kind = cp->kind;
7918 is->fd = cp->fdFrom;
7921 is->unused = is->buf;
7924 is->xid = XtAppAddInput(appContext, is->fd,
7925 (XtPointer) (XtInputReadMask),
7926 (XtInputCallbackProc) DoInputCallback,
7928 is->closure = closure;
7929 return (InputSourceRef) is;
7933 RemoveInputSource(isr)
7936 InputSource *is = (InputSource *) isr;
7938 if (is->xid == 0) return;
7939 XtRemoveInput(is->xid);
7943 int OutputToProcess(pr, message, count, outError)
7949 static int line = 0;
7950 ChildProc *cp = (ChildProc *) pr;
7955 if (appData.noJoin || !appData.useInternalWrap)
7956 outCount = fwrite(message, 1, count, stdout);
7959 int width = get_term_width();
7960 int len = wrap(NULL, message, count, width, &line);
7961 char *msg = malloc(len);
7965 outCount = fwrite(message, 1, count, stdout);
7968 dbgchk = wrap(msg, message, count, width, &line);
7969 if (dbgchk != len && appData.debugMode)
7970 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
7971 outCount = fwrite(msg, 1, dbgchk, stdout);
7977 outCount = write(cp->fdTo, message, count);
7987 /* Output message to process, with "ms" milliseconds of delay
7988 between each character. This is needed when sending the logon
7989 script to ICC, which for some reason doesn't like the
7990 instantaneous send. */
7991 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
7998 ChildProc *cp = (ChildProc *) pr;
8003 r = write(cp->fdTo, message++, 1);
8016 /**** Animation code by Hugh Fisher, DCS, ANU.
8018 Known problem: if a window overlapping the board is
8019 moved away while a piece is being animated underneath,
8020 the newly exposed area won't be updated properly.
8021 I can live with this.
8023 Known problem: if you look carefully at the animation
8024 of pieces in mono mode, they are being drawn as solid
8025 shapes without interior detail while moving. Fixing
8026 this would be a major complication for minimal return.
8029 /* Masks for XPM pieces. Black and white pieces can have
8030 different shapes, but in the interest of retaining my
8031 sanity pieces must have the same outline on both light
8032 and dark squares, and all pieces must use the same
8033 background square colors/images. */
8035 static int xpmDone = 0;
8038 CreateAnimMasks (pieceDepth)
8045 unsigned long plane;
8048 /* Need a bitmap just to get a GC with right depth */
8049 buf = XCreatePixmap(xDisplay, xBoardWindow,
8051 values.foreground = 1;
8052 values.background = 0;
8053 /* Don't use XtGetGC, not read only */
8054 maskGC = XCreateGC(xDisplay, buf,
8055 GCForeground | GCBackground, &values);
8056 XFreePixmap(xDisplay, buf);
8058 buf = XCreatePixmap(xDisplay, xBoardWindow,
8059 squareSize, squareSize, pieceDepth);
8060 values.foreground = XBlackPixel(xDisplay, xScreen);
8061 values.background = XWhitePixel(xDisplay, xScreen);
8062 bufGC = XCreateGC(xDisplay, buf,
8063 GCForeground | GCBackground, &values);
8065 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8066 /* Begin with empty mask */
8067 if(!xpmDone) // [HGM] pieces: keep using existing
8068 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8069 squareSize, squareSize, 1);
8070 XSetFunction(xDisplay, maskGC, GXclear);
8071 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8072 0, 0, squareSize, squareSize);
8074 /* Take a copy of the piece */
8079 XSetFunction(xDisplay, bufGC, GXcopy);
8080 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8082 0, 0, squareSize, squareSize, 0, 0);
8084 /* XOR the background (light) over the piece */
8085 XSetFunction(xDisplay, bufGC, GXxor);
8087 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8088 0, 0, squareSize, squareSize, 0, 0);
8090 XSetForeground(xDisplay, bufGC, lightSquareColor);
8091 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8094 /* We now have an inverted piece image with the background
8095 erased. Construct mask by just selecting all the non-zero
8096 pixels - no need to reconstruct the original image. */
8097 XSetFunction(xDisplay, maskGC, GXor);
8099 /* Might be quicker to download an XImage and create bitmap
8100 data from it rather than this N copies per piece, but it
8101 only takes a fraction of a second and there is a much
8102 longer delay for loading the pieces. */
8103 for (n = 0; n < pieceDepth; n ++) {
8104 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8105 0, 0, squareSize, squareSize,
8111 XFreePixmap(xDisplay, buf);
8112 XFreeGC(xDisplay, bufGC);
8113 XFreeGC(xDisplay, maskGC);
8117 InitAnimState (anim, info)
8119 XWindowAttributes * info;
8124 /* Each buffer is square size, same depth as window */
8125 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8126 squareSize, squareSize, info->depth);
8127 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8128 squareSize, squareSize, info->depth);
8130 /* Create a plain GC for blitting */
8131 mask = GCForeground | GCBackground | GCFunction |
8132 GCPlaneMask | GCGraphicsExposures;
8133 values.foreground = XBlackPixel(xDisplay, xScreen);
8134 values.background = XWhitePixel(xDisplay, xScreen);
8135 values.function = GXcopy;
8136 values.plane_mask = AllPlanes;
8137 values.graphics_exposures = False;
8138 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8140 /* Piece will be copied from an existing context at
8141 the start of each new animation/drag. */
8142 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8144 /* Outline will be a read-only copy of an existing */
8145 anim->outlineGC = None;
8151 XWindowAttributes info;
8153 if (xpmDone && gameInfo.variant == oldVariant) return;
8154 if(xpmDone) oldVariant = gameInfo.variant; // first time pieces might not be created yet
8155 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8157 InitAnimState(&game, &info);
8158 InitAnimState(&player, &info);
8160 /* For XPM pieces, we need bitmaps to use as masks. */
8162 CreateAnimMasks(info.depth), xpmDone = 1;
8167 static Boolean frameWaiting;
8169 static RETSIGTYPE FrameAlarm (sig)
8172 frameWaiting = False;
8173 /* In case System-V style signals. Needed?? */
8174 signal(SIGALRM, FrameAlarm);
8181 struct itimerval delay;
8183 XSync(xDisplay, False);
8186 frameWaiting = True;
8187 signal(SIGALRM, FrameAlarm);
8188 delay.it_interval.tv_sec =
8189 delay.it_value.tv_sec = time / 1000;
8190 delay.it_interval.tv_usec =
8191 delay.it_value.tv_usec = (time % 1000) * 1000;
8192 setitimer(ITIMER_REAL, &delay, NULL);
8193 while (frameWaiting) pause();
8194 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8195 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8196 setitimer(ITIMER_REAL, &delay, NULL);
8206 XSync(xDisplay, False);
8208 usleep(time * 1000);
8213 /* Convert board position to corner of screen rect and color */
8216 ScreenSquare(column, row, pt, color)
8217 int column; int row; XPoint * pt; int * color;
8220 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8221 pt->y = lineGap + row * (squareSize + lineGap);
8223 pt->x = lineGap + column * (squareSize + lineGap);
8224 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8226 *color = SquareColor(row, column);
8229 /* Convert window coords to square */
8232 BoardSquare(x, y, column, row)
8233 int x; int y; int * column; int * row;
8235 *column = EventToSquare(x, BOARD_WIDTH);
8236 if (flipView && *column >= 0)
8237 *column = BOARD_WIDTH - 1 - *column;
8238 *row = EventToSquare(y, BOARD_HEIGHT);
8239 if (!flipView && *row >= 0)
8240 *row = BOARD_HEIGHT - 1 - *row;
8245 #undef Max /* just in case */
8247 #define Max(a, b) ((a) > (b) ? (a) : (b))
8248 #define Min(a, b) ((a) < (b) ? (a) : (b))
8251 SetRect(rect, x, y, width, height)
8252 XRectangle * rect; int x; int y; int width; int height;
8256 rect->width = width;
8257 rect->height = height;
8260 /* Test if two frames overlap. If they do, return
8261 intersection rect within old and location of
8262 that rect within new. */
8265 Intersect(old, new, size, area, pt)
8266 XPoint * old; XPoint * new;
8267 int size; XRectangle * area; XPoint * pt;
8269 if (old->x > new->x + size || new->x > old->x + size ||
8270 old->y > new->y + size || new->y > old->y + size) {
8273 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8274 size - abs(old->x - new->x), size - abs(old->y - new->y));
8275 pt->x = Max(old->x - new->x, 0);
8276 pt->y = Max(old->y - new->y, 0);
8281 /* For two overlapping frames, return the rect(s)
8282 in the old that do not intersect with the new. */
8285 CalcUpdateRects(old, new, size, update, nUpdates)
8286 XPoint * old; XPoint * new; int size;
8287 XRectangle update[]; int * nUpdates;
8291 /* If old = new (shouldn't happen) then nothing to draw */
8292 if (old->x == new->x && old->y == new->y) {
8296 /* Work out what bits overlap. Since we know the rects
8297 are the same size we don't need a full intersect calc. */
8299 /* Top or bottom edge? */
8300 if (new->y > old->y) {
8301 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8303 } else if (old->y > new->y) {
8304 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8305 size, old->y - new->y);
8308 /* Left or right edge - don't overlap any update calculated above. */
8309 if (new->x > old->x) {
8310 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8311 new->x - old->x, size - abs(new->y - old->y));
8313 } else if (old->x > new->x) {
8314 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8315 old->x - new->x, size - abs(new->y - old->y));
8322 /* Generate a series of frame coords from start->mid->finish.
8323 The movement rate doubles until the half way point is
8324 reached, then halves back down to the final destination,
8325 which gives a nice slow in/out effect. The algorithmn
8326 may seem to generate too many intermediates for short
8327 moves, but remember that the purpose is to attract the
8328 viewers attention to the piece about to be moved and
8329 then to where it ends up. Too few frames would be less
8333 Tween(start, mid, finish, factor, frames, nFrames)
8334 XPoint * start; XPoint * mid;
8335 XPoint * finish; int factor;
8336 XPoint frames[]; int * nFrames;
8338 int fraction, n, count;
8342 /* Slow in, stepping 1/16th, then 1/8th, ... */
8344 for (n = 0; n < factor; n++)
8346 for (n = 0; n < factor; n++) {
8347 frames[count].x = start->x + (mid->x - start->x) / fraction;
8348 frames[count].y = start->y + (mid->y - start->y) / fraction;
8350 fraction = fraction / 2;
8354 frames[count] = *mid;
8357 /* Slow out, stepping 1/2, then 1/4, ... */
8359 for (n = 0; n < factor; n++) {
8360 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8361 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8363 fraction = fraction * 2;
8368 /* Draw a piece on the screen without disturbing what's there */
8371 SelectGCMask(piece, clip, outline, mask)
8372 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8376 /* Bitmap for piece being moved. */
8377 if (appData.monoMode) {
8378 *mask = *pieceToSolid(piece);
8379 } else if (useImages) {
8381 *mask = xpmMask[piece];
8383 *mask = ximMaskPm[piece];
8386 *mask = *pieceToSolid(piece);
8389 /* GC for piece being moved. Square color doesn't matter, but
8390 since it gets modified we make a copy of the original. */
8392 if (appData.monoMode)
8397 if (appData.monoMode)
8402 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8404 /* Outline only used in mono mode and is not modified */
8406 *outline = bwPieceGC;
8408 *outline = wbPieceGC;
8412 OverlayPiece(piece, clip, outline, dest)
8413 ChessSquare piece; GC clip; GC outline; Drawable dest;
8418 /* Draw solid rectangle which will be clipped to shape of piece */
8419 XFillRectangle(xDisplay, dest, clip,
8420 0, 0, squareSize, squareSize);
8421 if (appData.monoMode)
8422 /* Also draw outline in contrasting color for black
8423 on black / white on white cases */
8424 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8425 0, 0, squareSize, squareSize, 0, 0, 1);
8427 /* Copy the piece */
8432 if(appData.upsideDown && flipView) kind ^= 2;
8433 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8435 0, 0, squareSize, squareSize,
8440 /* Animate the movement of a single piece */
8443 BeginAnimation(anim, piece, startColor, start)
8451 if(appData.upsideDown && flipView) piece += piece < BlackPawn ? BlackPawn : -BlackPawn;
8452 /* The old buffer is initialised with the start square (empty) */
8453 BlankSquare(start->x, start->y, startColor, EmptySquare, anim->saveBuf, 0);
8454 anim->prevFrame = *start;
8456 /* The piece will be drawn using its own bitmap as a matte */
8457 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8458 XSetClipMask(xDisplay, anim->pieceGC, mask);
8462 AnimationFrame(anim, frame, piece)
8467 XRectangle updates[4];
8472 /* Save what we are about to draw into the new buffer */
8473 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8474 frame->x, frame->y, squareSize, squareSize,
8477 /* Erase bits of the previous frame */
8478 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8479 /* Where the new frame overlapped the previous,
8480 the contents in newBuf are wrong. */
8481 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8482 overlap.x, overlap.y,
8483 overlap.width, overlap.height,
8485 /* Repaint the areas in the old that don't overlap new */
8486 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8487 for (i = 0; i < count; i++)
8488 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8489 updates[i].x - anim->prevFrame.x,
8490 updates[i].y - anim->prevFrame.y,
8491 updates[i].width, updates[i].height,
8492 updates[i].x, updates[i].y);
8494 /* Easy when no overlap */
8495 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8496 0, 0, squareSize, squareSize,
8497 anim->prevFrame.x, anim->prevFrame.y);
8500 /* Save this frame for next time round */
8501 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8502 0, 0, squareSize, squareSize,
8504 anim->prevFrame = *frame;
8506 /* Draw piece over original screen contents, not current,
8507 and copy entire rect. Wipes out overlapping piece images. */
8508 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8509 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8510 0, 0, squareSize, squareSize,
8511 frame->x, frame->y);
8515 EndAnimation (anim, finish)
8519 XRectangle updates[4];
8524 /* The main code will redraw the final square, so we
8525 only need to erase the bits that don't overlap. */
8526 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8527 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8528 for (i = 0; i < count; i++)
8529 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8530 updates[i].x - anim->prevFrame.x,
8531 updates[i].y - anim->prevFrame.y,
8532 updates[i].width, updates[i].height,
8533 updates[i].x, updates[i].y);
8535 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8536 0, 0, squareSize, squareSize,
8537 anim->prevFrame.x, anim->prevFrame.y);
8542 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8544 ChessSquare piece; int startColor;
8545 XPoint * start; XPoint * finish;
8546 XPoint frames[]; int nFrames;
8550 BeginAnimation(anim, piece, startColor, start);
8551 for (n = 0; n < nFrames; n++) {
8552 AnimationFrame(anim, &(frames[n]), piece);
8553 FrameDelay(appData.animSpeed);
8555 EndAnimation(anim, finish);
8559 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
8562 ChessSquare piece = board[fromY][toY];
8563 board[fromY][toY] = EmptySquare;
8564 DrawPosition(FALSE, board);
8566 x = lineGap + ((BOARD_WIDTH-1)-toX) * (squareSize + lineGap);
8567 y = lineGap + toY * (squareSize + lineGap);
8569 x = lineGap + toX * (squareSize + lineGap);
8570 y = lineGap + ((BOARD_HEIGHT-1)-toY) * (squareSize + lineGap);
8572 for(i=1; i<4*kFactor; i++) {
8573 int r = squareSize * 9 * i/(20*kFactor - 5);
8574 XFillArc(xDisplay, xBoardWindow, highlineGC,
8575 x + squareSize/2 - r, y+squareSize/2 - r, 2*r, 2*r, 0, 64*360);
8576 FrameDelay(appData.animSpeed);
8578 board[fromY][toY] = piece;
8581 /* Main control logic for deciding what to animate and how */
8584 AnimateMove(board, fromX, fromY, toX, toY)
8593 XPoint start, finish, mid;
8594 XPoint frames[kFactor * 2 + 1];
8595 int nFrames, startColor, endColor;
8597 /* Are we animating? */
8598 if (!appData.animate || appData.blindfold)
8601 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8602 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8603 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8605 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8606 piece = board[fromY][fromX];
8607 if (piece >= EmptySquare) return;
8612 hop = abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1;
8615 if (appData.debugMode) {
8616 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8617 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8618 piece, fromX, fromY, toX, toY); }
8620 ScreenSquare(fromX, fromY, &start, &startColor);
8621 ScreenSquare(toX, toY, &finish, &endColor);
8624 /* Knight: make straight movement then diagonal */
8625 if (abs(toY - fromY) < abs(toX - fromX)) {
8626 mid.x = start.x + (finish.x - start.x) / 2;
8630 mid.y = start.y + (finish.y - start.y) / 2;
8633 mid.x = start.x + (finish.x - start.x) / 2;
8634 mid.y = start.y + (finish.y - start.y) / 2;
8637 /* Don't use as many frames for very short moves */
8638 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8639 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8641 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8642 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8643 if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged
8645 for(i=0; i<BOARD_WIDTH; i++) for(j=0; j<BOARD_HEIGHT; j++)
8646 if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] = True;
8649 /* Be sure end square is redrawn */
8650 damage[0][toY][toX] = True;
8654 DragPieceBegin(x, y, instantly)
8655 int x; int y; Boolean instantly;
8657 int boardX, boardY, color;
8660 /* Are we animating? */
8661 if (!appData.animateDragging || appData.blindfold)
8664 /* Figure out which square we start in and the
8665 mouse position relative to top left corner. */
8666 BoardSquare(x, y, &boardX, &boardY);
8667 player.startBoardX = boardX;
8668 player.startBoardY = boardY;
8669 ScreenSquare(boardX, boardY, &corner, &color);
8670 player.startSquare = corner;
8671 player.startColor = color;
8672 /* As soon as we start dragging, the piece will jump slightly to
8673 be centered over the mouse pointer. */
8674 player.mouseDelta.x = squareSize/2;
8675 player.mouseDelta.y = squareSize/2;
8676 /* Initialise animation */
8677 player.dragPiece = PieceForSquare(boardX, boardY);
8679 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8680 player.dragActive = True;
8681 BeginAnimation(&player, player.dragPiece, color, &corner);
8682 /* Mark this square as needing to be redrawn. Note that
8683 we don't remove the piece though, since logically (ie
8684 as seen by opponent) the move hasn't been made yet. */
8685 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8686 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8687 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8688 corner.x, corner.y, squareSize, squareSize,
8689 0, 0); // [HGM] zh: unstack in stead of grab
8690 if(gatingPiece != EmptySquare) {
8691 /* Kludge alert: When gating we want the introduced
8692 piece to appear on the from square. To generate an
8693 image of it, we draw it on the board, copy the image,
8694 and draw the original piece again. */
8695 ChessSquare piece = boards[currentMove][boardY][boardX];
8696 DrawSquare(boardY, boardX, gatingPiece, 0);
8697 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8698 corner.x, corner.y, squareSize, squareSize, 0, 0);
8699 DrawSquare(boardY, boardX, piece, 0);
8701 damage[0][boardY][boardX] = True;
8703 player.dragActive = False;
8708 ChangeDragPiece(ChessSquare piece)
8711 player.dragPiece = piece;
8712 /* The piece will be drawn using its own bitmap as a matte */
8713 SelectGCMask(piece, &player.pieceGC, &player.outlineGC, &mask);
8714 XSetClipMask(xDisplay, player.pieceGC, mask);
8723 /* Are we animating? */
8724 if (!appData.animateDragging || appData.blindfold)
8728 if (! player.dragActive)
8730 /* Move piece, maintaining same relative position
8731 of mouse within square */
8732 corner.x = x - player.mouseDelta.x;
8733 corner.y = y - player.mouseDelta.y;
8734 AnimationFrame(&player, &corner, player.dragPiece);
8736 if (appData.highlightDragging) {
8738 BoardSquare(x, y, &boardX, &boardY);
8739 SetHighlights(fromX, fromY, boardX, boardY);
8748 int boardX, boardY, color;
8751 /* Are we animating? */
8752 if (!appData.animateDragging || appData.blindfold)
8756 if (! player.dragActive)
8758 /* Last frame in sequence is square piece is
8759 placed on, which may not match mouse exactly. */
8760 BoardSquare(x, y, &boardX, &boardY);
8761 ScreenSquare(boardX, boardY, &corner, &color);
8762 EndAnimation(&player, &corner);
8764 /* Be sure end square is redrawn */
8765 damage[0][boardY][boardX] = True;
8767 /* This prevents weird things happening with fast successive
8768 clicks which on my Sun at least can cause motion events
8769 without corresponding press/release. */
8770 player.dragActive = False;
8773 /* Handle expose event while piece being dragged */
8778 if (!player.dragActive || appData.blindfold)
8781 /* What we're doing: logically, the move hasn't been made yet,
8782 so the piece is still in it's original square. But visually
8783 it's being dragged around the board. So we erase the square
8784 that the piece is on and draw it at the last known drag point. */
8785 BlankSquare(player.startSquare.x, player.startSquare.y,
8786 player.startColor, EmptySquare, xBoardWindow, 1);
8787 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8788 damage[0][player.startBoardY][player.startBoardX] = TRUE;
8791 #include <sys/ioctl.h>
8792 int get_term_width()
8794 int fd, default_width;
8797 default_width = 79; // this is FICS default anyway...
8799 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8801 if (!ioctl(fd, TIOCGSIZE, &win))
8802 default_width = win.ts_cols;
8803 #elif defined(TIOCGWINSZ)
8805 if (!ioctl(fd, TIOCGWINSZ, &win))
8806 default_width = win.ws_col;
8808 return default_width;
8814 static int old_width = 0;
8815 int new_width = get_term_width();
8817 if (old_width != new_width)
8818 ics_printf("set width %d\n", new_width);
8819 old_width = new_width;
8822 void NotifyFrontendLogin()
8827 /* [AS] Arrow highlighting support */
8829 static double A_WIDTH = 5; /* Width of arrow body */
8831 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
8832 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
8834 static double Sqr( double x )
8839 static int Round( double x )
8841 return (int) (x + 0.5);
8844 void SquareToPos(int rank, int file, int *x, int *y)
8847 *x = lineGap + ((BOARD_WIDTH-1)-file) * (squareSize + lineGap);
8848 *y = lineGap + rank * (squareSize + lineGap);
8850 *x = lineGap + file * (squareSize + lineGap);
8851 *y = lineGap + ((BOARD_HEIGHT-1)-rank) * (squareSize + lineGap);
8855 /* Draw an arrow between two points using current settings */
8856 void DrawArrowBetweenPoints( int s_x, int s_y, int d_x, int d_y )
8859 double dx, dy, j, k, x, y;
8862 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
8864 arrow[0].x = s_x + A_WIDTH + 0.5;
8867 arrow[1].x = s_x + A_WIDTH + 0.5;
8868 arrow[1].y = d_y - h;
8870 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8871 arrow[2].y = d_y - h;
8876 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
8877 arrow[5].y = d_y - h;
8879 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8880 arrow[4].y = d_y - h;
8882 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
8885 else if( d_y == s_y ) {
8886 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
8889 arrow[0].y = s_y + A_WIDTH + 0.5;
8891 arrow[1].x = d_x - w;
8892 arrow[1].y = s_y + A_WIDTH + 0.5;
8894 arrow[2].x = d_x - w;
8895 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8900 arrow[5].x = d_x - w;
8901 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
8903 arrow[4].x = d_x - w;
8904 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8907 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
8910 /* [AS] Needed a lot of paper for this! :-) */
8911 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
8912 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
8914 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
8916 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
8921 arrow[0].x = Round(x - j);
8922 arrow[0].y = Round(y + j*dx);
8924 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
8925 arrow[1].y = Round(arrow[0].y - 2*j*dx);
8928 x = (double) d_x - k;
8929 y = (double) d_y - k*dy;
8932 x = (double) d_x + k;
8933 y = (double) d_y + k*dy;
8936 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
8938 arrow[6].x = Round(x - j);
8939 arrow[6].y = Round(y + j*dx);
8941 arrow[2].x = Round(arrow[6].x + 2*j);
8942 arrow[2].y = Round(arrow[6].y - 2*j*dx);
8944 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
8945 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
8950 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
8951 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
8954 XFillPolygon(xDisplay, xBoardWindow, highlineGC, arrow, 7, Nonconvex, CoordModeOrigin);
8955 // Polygon( hdc, arrow, 7 );
8958 /* [AS] Draw an arrow between two squares */
8959 void DrawArrowBetweenSquares( int s_col, int s_row, int d_col, int d_row )
8961 int s_x, s_y, d_x, d_y, hor, vert, i;
8963 if( s_col == d_col && s_row == d_row ) {
8967 /* Get source and destination points */
8968 SquareToPos( s_row, s_col, &s_x, &s_y);
8969 SquareToPos( d_row, d_col, &d_x, &d_y);
8972 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
8974 else if( d_y < s_y ) {
8975 d_y += squareSize / 2 + squareSize / 4;
8978 d_y += squareSize / 2;
8982 d_x += squareSize / 2 - squareSize / 4;
8984 else if( d_x < s_x ) {
8985 d_x += squareSize / 2 + squareSize / 4;
8988 d_x += squareSize / 2;
8991 s_x += squareSize / 2;
8992 s_y += squareSize / 2;
8995 A_WIDTH = squareSize / 14.; //[HGM] make float
8997 DrawArrowBetweenPoints( s_x, s_y, d_x, d_y );
8999 hor = 64*s_col + 32; vert = 64*s_row + 32;
9000 for(i=0; i<= 64; i++) {
9001 damage[0][vert+6>>6][hor+6>>6] = True;
9002 damage[0][vert-6>>6][hor+6>>6] = True;
9003 damage[0][vert+6>>6][hor-6>>6] = True;
9004 damage[0][vert-6>>6][hor-6>>6] = True;
9005 hor += d_col - s_col; vert += d_row - s_row;
9009 Boolean IsDrawArrowEnabled()
9011 return appData.highlightMoveWithArrow && squareSize >= 32;
9014 void DrawArrowHighlight(int fromX, int fromY, int toX,int toY)
9016 if( IsDrawArrowEnabled() && fromX >= 0 && fromY >= 0 && toX >= 0 && toY >= 0)
9017 DrawArrowBetweenSquares(fromX, fromY, toX, toY);
9020 void UpdateLogos(int displ)
9022 return; // no logos in XBoard yet