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>Home: RevertProc() \n \
1091 :<Key>End: TruncateGameProc() \n \
1092 :Ctrl<Key>m: MoveNowProc() \n \
1093 :Ctrl<Key>x: RetractMoveProc() \n \
1094 :Meta<Key>J: EngineMenuProc() \n \
1095 :Meta<Key>U: UciMenuProc() \n \
1096 :Meta<Key>T: TimeControlProc() \n \
1097 :Ctrl<Key>P: PonderNextMoveProc() \n "
1098 #ifndef OPTIONSDIALOG
1100 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1101 :Ctrl<Key>F: AutoflagProc() \n \
1102 :Ctrl<Key>A: AnimateMovingProc() \n \
1103 :Ctrl<Key>L: TestLegalityProc() \n \
1104 :Ctrl<Key>H: HideThinkingProc() \n "
1107 :<Key>-: Iconify() \n \
1108 :<Key>F1: ManProc() \n \
1109 :<Key>F2: FlipViewProc() \n \
1110 <KeyDown>.: BackwardProc() \n \
1111 <KeyUp>.: ForwardProc() \n \
1112 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1113 \"Send to chess program:\",,1) \n \
1114 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1115 \"Send to second chess program:\",,2) \n";
1117 char boardTranslations[] =
1118 "<Btn1Down>: HandleUserMove(0) \n \
1119 Shift<Btn1Up>: HandleUserMove(1) \n \
1120 <Btn1Up>: HandleUserMove(0) \n \
1121 <Btn1Motion>: AnimateUserMove() \n \
1122 <Btn3Motion>: HandlePV() \n \
1123 <Btn3Up>: PieceMenuPopup(menuB) \n \
1124 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1125 PieceMenuPopup(menuB) \n \
1126 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1127 PieceMenuPopup(menuW) \n \
1128 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1129 PieceMenuPopup(menuW) \n \
1130 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1131 PieceMenuPopup(menuB) \n";
1133 char whiteTranslations[] =
1134 "Shift<BtnDown>: WhiteClock(1)\n \
1135 <BtnDown>: WhiteClock(0)\n";
1136 char blackTranslations[] =
1137 "Shift<BtnDown>: BlackClock(1)\n \
1138 <BtnDown>: BlackClock(0)\n";
1140 char ICSInputTranslations[] =
1141 "<Key>Up: UpKeyProc() \n "
1142 "<Key>Down: DownKeyProc() \n "
1143 "<Key>Return: EnterKeyProc() \n";
1145 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1146 // as the widget is destroyed before the up-click can call extend-end
1147 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1149 String xboardResources[] = {
1150 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1151 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1152 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1157 /* Max possible square size */
1158 #define MAXSQSIZE 256
1160 static int xpm_avail[MAXSQSIZE];
1162 #ifdef HAVE_DIR_STRUCT
1164 /* Extract piece size from filename */
1166 xpm_getsize(name, len, ext)
1177 if ((p=strchr(name, '.')) == NULL ||
1178 StrCaseCmp(p+1, ext) != 0)
1184 while (*p && isdigit(*p))
1191 /* Setup xpm_avail */
1193 xpm_getavail(dirname, ext)
1201 for (i=0; i<MAXSQSIZE; ++i)
1204 if (appData.debugMode)
1205 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1207 dir = opendir(dirname);
1210 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1211 programName, dirname);
1215 while ((ent=readdir(dir)) != NULL) {
1216 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1217 if (i > 0 && i < MAXSQSIZE)
1227 xpm_print_avail(fp, ext)
1233 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1234 for (i=1; i<MAXSQSIZE; ++i) {
1240 /* Return XPM piecesize closest to size */
1242 xpm_closest_to(dirname, size, ext)
1248 int sm_diff = MAXSQSIZE;
1252 xpm_getavail(dirname, ext);
1254 if (appData.debugMode)
1255 xpm_print_avail(stderr, ext);
1257 for (i=1; i<MAXSQSIZE; ++i) {
1260 diff = (diff<0) ? -diff : diff;
1261 if (diff < sm_diff) {
1269 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1275 #else /* !HAVE_DIR_STRUCT */
1276 /* If we are on a system without a DIR struct, we can't
1277 read the directory, so we can't collect a list of
1278 filenames, etc., so we can't do any size-fitting. */
1280 xpm_closest_to(dirname, size, ext)
1285 fprintf(stderr, _("\
1286 Warning: No DIR structure found on this system --\n\
1287 Unable to autosize for XPM/XIM pieces.\n\
1288 Please report this error to %s.\n\
1289 Include system type & operating system in message.\n"), PACKAGE_BUGREPORT););
1292 #endif /* HAVE_DIR_STRUCT */
1294 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1295 "magenta", "cyan", "white" };
1299 TextColors textColors[(int)NColorClasses];
1301 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1303 parse_color(str, which)
1307 char *p, buf[100], *d;
1310 if (strlen(str) > 99) /* watch bounds on buf */
1315 for (i=0; i<which; ++i) {
1322 /* Could be looking at something like:
1324 .. in which case we want to stop on a comma also */
1325 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1329 return -1; /* Use default for empty field */
1332 if (which == 2 || isdigit(*p))
1335 while (*p && isalpha(*p))
1340 for (i=0; i<8; ++i) {
1341 if (!StrCaseCmp(buf, cnames[i]))
1342 return which? (i+40) : (i+30);
1344 if (!StrCaseCmp(buf, "default")) return -1;
1346 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1351 parse_cpair(cc, str)
1355 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1356 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1361 /* bg and attr are optional */
1362 textColors[(int)cc].bg = parse_color(str, 1);
1363 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1364 textColors[(int)cc].attr = 0;
1370 /* Arrange to catch delete-window events */
1371 Atom wm_delete_window;
1373 CatchDeleteWindow(Widget w, String procname)
1376 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1377 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1378 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1385 XtSetArg(args[0], XtNiconic, False);
1386 XtSetValues(shellWidget, args, 1);
1388 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1391 //---------------------------------------------------------------------------------------------------------
1392 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1395 #define CW_USEDEFAULT (1<<31)
1396 #define ICS_TEXT_MENU_SIZE 90
1397 #define DEBUG_FILE "xboard.debug"
1398 #define SetCurrentDirectory chdir
1399 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1403 // these two must some day move to frontend.h, when they are implemented
1404 Boolean GameListIsUp();
1406 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1409 // front-end part of option handling
1411 // [HGM] This platform-dependent table provides the location for storing the color info
1412 extern char *crWhite, * crBlack;
1416 &appData.whitePieceColor,
1417 &appData.blackPieceColor,
1418 &appData.lightSquareColor,
1419 &appData.darkSquareColor,
1420 &appData.highlightSquareColor,
1421 &appData.premoveHighlightColor,
1422 &appData.lowTimeWarningColor,
1433 // [HGM] font: keep a font for each square size, even non-stndard ones
1434 #define NUM_SIZES 18
1435 #define MAX_SIZE 130
1436 Boolean fontIsSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1437 char *fontTable[NUM_FONTS][MAX_SIZE];
1440 ParseFont(char *name, int number)
1441 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1443 if(sscanf(name, "size%d:", &size)) {
1444 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1445 // defer processing it until we know if it matches our board size
1446 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1447 fontTable[number][size] = strdup(strchr(name, ':')+1);
1448 fontValid[number][size] = True;
1453 case 0: // CLOCK_FONT
1454 appData.clockFont = strdup(name);
1456 case 1: // MESSAGE_FONT
1457 appData.font = strdup(name);
1459 case 2: // COORD_FONT
1460 appData.coordFont = strdup(name);
1465 fontIsSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1470 { // only 2 fonts currently
1471 appData.clockFont = CLOCK_FONT_NAME;
1472 appData.coordFont = COORD_FONT_NAME;
1473 appData.font = DEFAULT_FONT_NAME;
1478 { // no-op, until we identify the code for this already in XBoard and move it here
1482 ParseColor(int n, char *name)
1483 { // in XBoard, just copy the color-name string
1484 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1488 ParseTextAttribs(ColorClass cc, char *s)
1490 (&appData.colorShout)[cc] = strdup(s);
1494 ParseBoardSize(void *addr, char *name)
1496 appData.boardSize = strdup(name);
1501 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1505 SetCommPortDefaults()
1506 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1509 // [HGM] args: these three cases taken out to stay in front-end
1511 SaveFontArg(FILE *f, ArgDescriptor *ad)
1514 int i, n = (int)(intptr_t)ad->argLoc;
1516 case 0: // CLOCK_FONT
1517 name = appData.clockFont;
1519 case 1: // MESSAGE_FONT
1520 name = appData.font;
1522 case 2: // COORD_FONT
1523 name = appData.coordFont;
1528 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1529 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1530 fontTable[n][squareSize] = strdup(name);
1531 fontValid[n][squareSize] = True;
1534 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1535 fprintf(f, OPTCHAR "%s" SEPCHAR "\"size%d:%s\"\n", ad->argName, i, fontTable[n][i]);
1540 { // nothing to do, as the sounds are at all times represented by their text-string names already
1544 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1545 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1546 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
1550 SaveColor(FILE *f, ArgDescriptor *ad)
1551 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1552 if(colorVariable[(int)(intptr_t)ad->argLoc])
1553 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
1557 SaveBoardSize(FILE *f, char *name, void *addr)
1558 { // wrapper to shield back-end from BoardSize & sizeInfo
1559 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1563 ParseCommPortSettings(char *s)
1564 { // no such option in XBoard (yet)
1567 extern Widget engineOutputShell;
1570 GetActualPlacement(Widget wg, WindowPlacement *wp)
1580 XtSetArg(args[i], XtNx, &x); i++;
1581 XtSetArg(args[i], XtNy, &y); i++;
1582 XtSetArg(args[i], XtNwidth, &w); i++;
1583 XtSetArg(args[i], XtNheight, &h); i++;
1584 XtGetValues(wg, args, i);
1593 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1594 // In XBoard this will have to wait until awareness of window parameters is implemented
1595 GetActualPlacement(shellWidget, &wpMain);
1596 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput);
1597 if(MoveHistoryIsUp()) GetActualPlacement(shells[7], &wpMoveHistory);
1598 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1599 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1600 if(shellUp[1]) GetActualPlacement(shells[1], &wpComment);
1601 if(shellUp[2]) GetActualPlacement(shells[2], &wpTags);
1605 PrintCommPortSettings(FILE *f, char *name)
1606 { // This option does not exist in XBoard
1610 MySearchPath(char *installDir, char *name, char *fullname)
1611 { // just append installDir and name. Perhaps ExpandPath should be used here?
1612 name = ExpandPathName(name);
1613 if(name && name[0] == '/')
1614 safeStrCpy(fullname, name, MSG_SIZ );
1616 sprintf(fullname, "%s%c%s", installDir, '/', name);
1622 MyGetFullPathName(char *name, char *fullname)
1623 { // should use ExpandPath?
1624 name = ExpandPathName(name);
1625 safeStrCpy(fullname, name, MSG_SIZ );
1630 EnsureOnScreen(int *x, int *y, int minX, int minY)
1637 { // [HGM] args: allows testing if main window is realized from back-end
1638 return xBoardWindow != 0;
1642 PopUpStartupDialog()
1643 { // start menu not implemented in XBoard
1647 ConvertToLine(int argc, char **argv)
1649 static char line[128*1024], buf[1024];
1653 for(i=1; i<argc; i++)
1655 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') || argv[i][0] == NULLCHAR)
1656 && argv[i][0] != '{' )
1657 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1659 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1660 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1663 line[strlen(line)-1] = NULLCHAR;
1667 //--------------------------------------------------------------------------------------------
1669 extern Boolean twoBoards, partnerUp;
1672 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1674 #define BoardSize int
1675 void InitDrawingSizes(BoardSize boardSize, int flags)
1676 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1677 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1679 XtGeometryResult gres;
1682 if(!formWidget) return;
1685 * Enable shell resizing.
1687 shellArgs[0].value = (XtArgVal) &w;
1688 shellArgs[1].value = (XtArgVal) &h;
1689 XtGetValues(shellWidget, shellArgs, 2);
1691 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1692 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1693 XtSetValues(shellWidget, &shellArgs[2], 4);
1695 XtSetArg(args[0], XtNdefaultDistance, &sep);
1696 XtGetValues(formWidget, args, 1);
1698 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1699 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1700 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1702 hOffset = boardWidth + 10;
1703 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1704 secondSegments[i] = gridSegments[i];
1705 secondSegments[i].x1 += hOffset;
1706 secondSegments[i].x2 += hOffset;
1709 XtSetArg(args[0], XtNwidth, boardWidth);
1710 XtSetArg(args[1], XtNheight, boardHeight);
1711 XtSetValues(boardWidget, args, 2);
1713 timerWidth = (boardWidth - sep) / 2;
1714 XtSetArg(args[0], XtNwidth, timerWidth);
1715 XtSetValues(whiteTimerWidget, args, 1);
1716 XtSetValues(blackTimerWidget, args, 1);
1718 XawFormDoLayout(formWidget, False);
1720 if (appData.titleInWindow) {
1722 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1723 XtSetArg(args[i], XtNheight, &h); i++;
1724 XtGetValues(titleWidget, args, i);
1726 w = boardWidth - 2*bor;
1728 XtSetArg(args[0], XtNwidth, &w);
1729 XtGetValues(menuBarWidget, args, 1);
1730 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1733 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1734 if (gres != XtGeometryYes && appData.debugMode) {
1736 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1737 programName, gres, w, h, wr, hr);
1741 XawFormDoLayout(formWidget, True);
1744 * Inhibit shell resizing.
1746 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1747 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1748 shellArgs[4].value = shellArgs[2].value = w;
1749 shellArgs[5].value = shellArgs[3].value = h;
1750 XtSetValues(shellWidget, &shellArgs[0], 6);
1752 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1755 for(i=0; i<4; i++) {
1757 for(p=0; p<=(int)WhiteKing; p++)
1758 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1759 if(gameInfo.variant == VariantShogi) {
1760 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1761 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1762 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1763 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1764 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1767 if(gameInfo.variant == VariantGothic) {
1768 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1771 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1772 xpmPieceBitmap[i][(int)WhiteAngel] = xpmPieceBitmap2[i][(int)WhiteFalcon];
1773 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1776 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1777 for(p=0; p<=(int)WhiteKing; p++)
1778 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1779 if(gameInfo.variant == VariantShogi) {
1780 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1781 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1782 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1783 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1784 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1787 if(gameInfo.variant == VariantGothic) {
1788 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1791 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1792 ximMaskPm[(int)WhiteAngel] = ximMaskPm2[(int)WhiteFalcon];
1793 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1798 for(i=0; i<2; i++) {
1800 for(p=0; p<=(int)WhiteKing; p++)
1801 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1802 if(gameInfo.variant == VariantShogi) {
1803 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1804 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1805 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1806 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1807 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1810 if(gameInfo.variant == VariantGothic) {
1811 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1814 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1815 pieceBitmap[i][(int)WhiteAngel] = pieceBitmap2[i][(int)WhiteFalcon];
1816 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1826 void ParseIcsTextColors()
1827 { // [HGM] tken out of main(), so it can be called from ICS-Options dialog
1828 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1829 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1830 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1831 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1832 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1833 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1834 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1835 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1836 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1837 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1839 if (appData.colorize) {
1841 _("%s: can't parse color names; disabling colorization\n"),
1844 appData.colorize = FALSE;
1849 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
1850 XrmValue vFrom, vTo;
1851 int forceMono = False;
1853 if (!appData.monoMode) {
1854 vFrom.addr = (caddr_t) appData.lightSquareColor;
1855 vFrom.size = strlen(appData.lightSquareColor);
1856 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1857 if (vTo.addr == NULL) {
1858 appData.monoMode = True;
1861 lightSquareColor = *(Pixel *) vTo.addr;
1864 if (!appData.monoMode) {
1865 vFrom.addr = (caddr_t) appData.darkSquareColor;
1866 vFrom.size = strlen(appData.darkSquareColor);
1867 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1868 if (vTo.addr == NULL) {
1869 appData.monoMode = True;
1872 darkSquareColor = *(Pixel *) vTo.addr;
1875 if (!appData.monoMode) {
1876 vFrom.addr = (caddr_t) appData.whitePieceColor;
1877 vFrom.size = strlen(appData.whitePieceColor);
1878 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1879 if (vTo.addr == NULL) {
1880 appData.monoMode = True;
1883 whitePieceColor = *(Pixel *) vTo.addr;
1886 if (!appData.monoMode) {
1887 vFrom.addr = (caddr_t) appData.blackPieceColor;
1888 vFrom.size = strlen(appData.blackPieceColor);
1889 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1890 if (vTo.addr == NULL) {
1891 appData.monoMode = True;
1894 blackPieceColor = *(Pixel *) vTo.addr;
1898 if (!appData.monoMode) {
1899 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1900 vFrom.size = strlen(appData.highlightSquareColor);
1901 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1902 if (vTo.addr == NULL) {
1903 appData.monoMode = True;
1906 highlightSquareColor = *(Pixel *) vTo.addr;
1910 if (!appData.monoMode) {
1911 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1912 vFrom.size = strlen(appData.premoveHighlightColor);
1913 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1914 if (vTo.addr == NULL) {
1915 appData.monoMode = True;
1918 premoveHighlightColor = *(Pixel *) vTo.addr;
1926 { // [HGM] taken out of main
1928 if (appData.monoMode && // [HGM] no sense to go on to certain doom
1929 (appData.bitmapDirectory == NULL || appData.bitmapDirectory[0] == NULLCHAR))
1930 appData.bitmapDirectory = DEF_BITMAP_DIR;
1932 if (appData.bitmapDirectory[0] != NULLCHAR) {
1936 CreateXPMBoard(appData.liteBackTextureFile, 1);
1937 CreateXPMBoard(appData.darkBackTextureFile, 0);
1941 /* Create regular pieces */
1942 if (!useImages) CreatePieces();
1951 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1952 XSetWindowAttributes window_attributes;
1954 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1955 XrmValue vFrom, vTo;
1956 XtGeometryResult gres;
1959 int forceMono = False;
1961 srandom(time(0)); // [HGM] book: make random truly random
1963 setbuf(stdout, NULL);
1964 setbuf(stderr, NULL);
1967 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1968 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1972 programName = strrchr(argv[0], '/');
1973 if (programName == NULL)
1974 programName = argv[0];
1979 XtSetLanguageProc(NULL, NULL, NULL);
1980 bindtextdomain(PACKAGE, LOCALEDIR);
1981 textdomain(PACKAGE);
1985 XtAppInitialize(&appContext, "XBoard", shellOptions,
1986 XtNumber(shellOptions),
1987 &argc, argv, xboardResources, NULL, 0);
1988 appData.boardSize = "";
1989 InitAppData(ConvertToLine(argc, argv));
1991 if (p == NULL) p = "/tmp";
1992 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1993 gameCopyFilename = (char*) malloc(i);
1994 gamePasteFilename = (char*) malloc(i);
1995 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1996 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1998 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1999 clientResources, XtNumber(clientResources),
2002 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
2003 static char buf[MSG_SIZ];
2004 EscapeExpand(buf, appData.firstInitString);
2005 appData.firstInitString = strdup(buf);
2006 EscapeExpand(buf, appData.secondInitString);
2007 appData.secondInitString = strdup(buf);
2008 EscapeExpand(buf, appData.firstComputerString);
2009 appData.firstComputerString = strdup(buf);
2010 EscapeExpand(buf, appData.secondComputerString);
2011 appData.secondComputerString = strdup(buf);
2014 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
2017 if (chdir(chessDir) != 0) {
2018 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
2024 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
2025 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
2026 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
2027 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
2030 setbuf(debugFP, NULL);
2034 if (appData.debugMode) {
2035 fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
2039 /* [HGM,HR] make sure board size is acceptable */
2040 if(appData.NrFiles > BOARD_FILES ||
2041 appData.NrRanks > BOARD_RANKS )
2042 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
2045 /* This feature does not work; animation needs a rewrite */
2046 appData.highlightDragging = FALSE;
2050 xDisplay = XtDisplay(shellWidget);
2051 xScreen = DefaultScreen(xDisplay);
2052 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
2054 gameInfo.variant = StringToVariant(appData.variant);
2055 InitPosition(FALSE);
2058 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
2060 if (isdigit(appData.boardSize[0])) {
2061 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
2062 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
2063 &fontPxlSize, &smallLayout, &tinyLayout);
2065 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
2066 programName, appData.boardSize);
2070 /* Find some defaults; use the nearest known size */
2071 SizeDefaults *szd, *nearest;
2072 int distance = 99999;
2073 nearest = szd = sizeDefaults;
2074 while (szd->name != NULL) {
2075 if (abs(szd->squareSize - squareSize) < distance) {
2077 distance = abs(szd->squareSize - squareSize);
2078 if (distance == 0) break;
2082 if (i < 2) lineGap = nearest->lineGap;
2083 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
2084 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
2085 if (i < 5) fontPxlSize = nearest->fontPxlSize;
2086 if (i < 6) smallLayout = nearest->smallLayout;
2087 if (i < 7) tinyLayout = nearest->tinyLayout;
2090 SizeDefaults *szd = sizeDefaults;
2091 if (*appData.boardSize == NULLCHAR) {
2092 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
2093 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
2096 if (szd->name == NULL) szd--;
2097 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
2099 while (szd->name != NULL &&
2100 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
2101 if (szd->name == NULL) {
2102 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
2103 programName, appData.boardSize);
2107 squareSize = szd->squareSize;
2108 lineGap = szd->lineGap;
2109 clockFontPxlSize = szd->clockFontPxlSize;
2110 coordFontPxlSize = szd->coordFontPxlSize;
2111 fontPxlSize = szd->fontPxlSize;
2112 smallLayout = szd->smallLayout;
2113 tinyLayout = szd->tinyLayout;
2114 // [HGM] font: use defaults from settings file if available and not overruled
2116 if(!fontIsSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
2117 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
2118 if(!fontIsSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
2119 appData.font = fontTable[MESSAGE_FONT][squareSize];
2120 if(!fontIsSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
2121 appData.coordFont = fontTable[COORD_FONT][squareSize];
2123 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
2124 if (strlen(appData.pixmapDirectory) > 0) {
2125 p = ExpandPathName(appData.pixmapDirectory);
2127 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
2128 appData.pixmapDirectory);
2131 if (appData.debugMode) {
2132 fprintf(stderr, _("\
2133 XBoard square size (hint): %d\n\
2134 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
2136 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
2137 if (appData.debugMode) {
2138 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
2141 defaultLineGap = lineGap;
2142 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
2144 /* [HR] height treated separately (hacked) */
2145 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
2146 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
2147 if (appData.showJail == 1) {
2148 /* Jail on top and bottom */
2149 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2150 XtSetArg(boardArgs[2], XtNheight,
2151 boardHeight + 2*(lineGap + squareSize));
2152 } else if (appData.showJail == 2) {
2154 XtSetArg(boardArgs[1], XtNwidth,
2155 boardWidth + 2*(lineGap + squareSize));
2156 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2159 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2160 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2164 * Determine what fonts to use.
2167 appData.font = InsertPxlSize(appData.font, fontPxlSize);
2168 appData.clockFont = InsertPxlSize(appData.clockFont, clockFontPxlSize);
2169 appData.coordFont = InsertPxlSize(appData.coordFont, coordFontPxlSize);
2170 fontSet = CreateFontSet(appData.font);
2171 clockFontSet = CreateFontSet(appData.clockFont);
2173 /* For the coordFont, use the 0th font of the fontset. */
2174 XFontSet coordFontSet = CreateFontSet(appData.coordFont);
2175 XFontStruct **font_struct_list;
2176 char **font_name_list;
2177 XFontsOfFontSet(coordFontSet, &font_struct_list, &font_name_list);
2178 coordFontID = XLoadFont(xDisplay, font_name_list[0]);
2179 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2182 appData.font = FindFont(appData.font, fontPxlSize);
2183 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2184 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2185 clockFontID = XLoadFont(xDisplay, appData.clockFont);
2186 clockFontStruct = XQueryFont(xDisplay, clockFontID);
2187 coordFontID = XLoadFont(xDisplay, appData.coordFont);
2188 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2190 countFontID = coordFontID; // [HGM] holdings
2191 countFontStruct = coordFontStruct;
2193 xdb = XtDatabase(xDisplay);
2195 XrmPutLineResource(&xdb, "*international: True");
2196 vTo.size = sizeof(XFontSet);
2197 vTo.addr = (XtPointer) &fontSet;
2198 XrmPutResource(&xdb, "*fontSet", XtRFontSet, &vTo);
2200 XrmPutStringResource(&xdb, "*font", appData.font);
2204 * Detect if there are not enough colors available and adapt.
2206 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2207 appData.monoMode = True;
2210 forceMono = MakeColors();
2213 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2215 appData.monoMode = True;
2218 if (appData.lowTimeWarning && !appData.monoMode) {
2219 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2220 vFrom.size = strlen(appData.lowTimeWarningColor);
2221 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2222 if (vTo.addr == NULL)
2223 appData.monoMode = True;
2225 lowTimeWarningColor = *(Pixel *) vTo.addr;
2228 if (appData.monoMode && appData.debugMode) {
2229 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2230 (unsigned long) XWhitePixel(xDisplay, xScreen),
2231 (unsigned long) XBlackPixel(xDisplay, xScreen));
2234 ParseIcsTextColors();
2235 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2236 textColors[ColorNone].attr = 0;
2238 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2244 layoutName = "tinyLayout";
2245 } else if (smallLayout) {
2246 layoutName = "smallLayout";
2248 layoutName = "normalLayout";
2250 /* Outer layoutWidget is there only to provide a name for use in
2251 resources that depend on the layout style */
2253 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2254 layoutArgs, XtNumber(layoutArgs));
2256 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2257 formArgs, XtNumber(formArgs));
2258 XtSetArg(args[0], XtNdefaultDistance, &sep);
2259 XtGetValues(formWidget, args, 1);
2262 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2263 XtSetArg(args[0], XtNtop, XtChainTop);
2264 XtSetArg(args[1], XtNbottom, XtChainTop);
2265 XtSetArg(args[2], XtNright, XtChainLeft);
2266 XtSetValues(menuBarWidget, args, 3);
2268 widgetList[j++] = whiteTimerWidget =
2269 XtCreateWidget("whiteTime", labelWidgetClass,
2270 formWidget, timerArgs, XtNumber(timerArgs));
2272 XtSetArg(args[0], XtNfontSet, clockFontSet);
2274 XtSetArg(args[0], XtNfont, clockFontStruct);
2276 XtSetArg(args[1], XtNtop, XtChainTop);
2277 XtSetArg(args[2], XtNbottom, XtChainTop);
2278 XtSetValues(whiteTimerWidget, args, 3);
2280 widgetList[j++] = blackTimerWidget =
2281 XtCreateWidget("blackTime", labelWidgetClass,
2282 formWidget, timerArgs, XtNumber(timerArgs));
2284 XtSetArg(args[0], XtNfontSet, clockFontSet);
2286 XtSetArg(args[0], XtNfont, clockFontStruct);
2288 XtSetArg(args[1], XtNtop, XtChainTop);
2289 XtSetArg(args[2], XtNbottom, XtChainTop);
2290 XtSetValues(blackTimerWidget, args, 3);
2292 if (appData.titleInWindow) {
2293 widgetList[j++] = titleWidget =
2294 XtCreateWidget("title", labelWidgetClass, formWidget,
2295 titleArgs, XtNumber(titleArgs));
2296 XtSetArg(args[0], XtNtop, XtChainTop);
2297 XtSetArg(args[1], XtNbottom, XtChainTop);
2298 XtSetValues(titleWidget, args, 2);
2301 if (appData.showButtonBar) {
2302 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2303 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2304 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2305 XtSetArg(args[2], XtNtop, XtChainTop);
2306 XtSetArg(args[3], XtNbottom, XtChainTop);
2307 XtSetValues(buttonBarWidget, args, 4);
2310 widgetList[j++] = messageWidget =
2311 XtCreateWidget("message", labelWidgetClass, formWidget,
2312 messageArgs, XtNumber(messageArgs));
2313 XtSetArg(args[0], XtNtop, XtChainTop);
2314 XtSetArg(args[1], XtNbottom, XtChainTop);
2315 XtSetValues(messageWidget, args, 2);
2317 widgetList[j++] = boardWidget =
2318 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2319 XtNumber(boardArgs));
2321 XtManageChildren(widgetList, j);
2323 timerWidth = (boardWidth - sep) / 2;
2324 XtSetArg(args[0], XtNwidth, timerWidth);
2325 XtSetValues(whiteTimerWidget, args, 1);
2326 XtSetValues(blackTimerWidget, args, 1);
2328 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2329 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2330 XtGetValues(whiteTimerWidget, args, 2);
2332 if (appData.showButtonBar) {
2333 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2334 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2335 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2339 * formWidget uses these constraints but they are stored
2343 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2344 XtSetValues(menuBarWidget, args, i);
2345 if (appData.titleInWindow) {
2348 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2349 XtSetValues(whiteTimerWidget, args, i);
2351 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2352 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2353 XtSetValues(blackTimerWidget, args, i);
2355 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2356 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2357 XtSetValues(titleWidget, args, i);
2359 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2360 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2361 XtSetValues(messageWidget, args, i);
2362 if (appData.showButtonBar) {
2364 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2365 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2366 XtSetValues(buttonBarWidget, args, i);
2370 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2371 XtSetValues(whiteTimerWidget, args, i);
2373 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2374 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2375 XtSetValues(blackTimerWidget, args, i);
2377 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2378 XtSetValues(titleWidget, args, i);
2380 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2381 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2382 XtSetValues(messageWidget, args, i);
2383 if (appData.showButtonBar) {
2385 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2386 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2387 XtSetValues(buttonBarWidget, args, i);
2392 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2393 XtSetValues(whiteTimerWidget, args, i);
2395 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2396 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2397 XtSetValues(blackTimerWidget, args, i);
2399 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2400 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2401 XtSetValues(messageWidget, args, i);
2402 if (appData.showButtonBar) {
2404 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2405 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2406 XtSetValues(buttonBarWidget, args, i);
2410 XtSetArg(args[0], XtNfromVert, messageWidget);
2411 XtSetArg(args[1], XtNtop, XtChainTop);
2412 XtSetArg(args[2], XtNbottom, XtChainBottom);
2413 XtSetArg(args[3], XtNleft, XtChainLeft);
2414 XtSetArg(args[4], XtNright, XtChainRight);
2415 XtSetValues(boardWidget, args, 5);
2417 XtRealizeWidget(shellWidget);
2420 XtSetArg(args[0], XtNx, wpMain.x);
2421 XtSetArg(args[1], XtNy, wpMain.y);
2422 XtSetValues(shellWidget, args, 2);
2426 * Correct the width of the message and title widgets.
2427 * It is not known why some systems need the extra fudge term.
2428 * The value "2" is probably larger than needed.
2430 XawFormDoLayout(formWidget, False);
2432 #define WIDTH_FUDGE 2
2434 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2435 XtSetArg(args[i], XtNheight, &h); i++;
2436 XtGetValues(messageWidget, args, i);
2437 if (appData.showButtonBar) {
2439 XtSetArg(args[i], XtNwidth, &w); i++;
2440 XtGetValues(buttonBarWidget, args, i);
2441 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2443 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2446 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2447 if (gres != XtGeometryYes && appData.debugMode) {
2448 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2449 programName, gres, w, h, wr, hr);
2452 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2453 /* The size used for the child widget in layout lags one resize behind
2454 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2456 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2457 if (gres != XtGeometryYes && appData.debugMode) {
2458 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2459 programName, gres, w, h, wr, hr);
2462 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2463 XtSetArg(args[1], XtNright, XtChainRight);
2464 XtSetValues(messageWidget, args, 2);
2466 if (appData.titleInWindow) {
2468 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2469 XtSetArg(args[i], XtNheight, &h); i++;
2470 XtGetValues(titleWidget, args, i);
2472 w = boardWidth - 2*bor;
2474 XtSetArg(args[0], XtNwidth, &w);
2475 XtGetValues(menuBarWidget, args, 1);
2476 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2479 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2480 if (gres != XtGeometryYes && appData.debugMode) {
2482 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2483 programName, gres, w, h, wr, hr);
2486 XawFormDoLayout(formWidget, True);
2488 xBoardWindow = XtWindow(boardWidget);
2490 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2491 // not need to go into InitDrawingSizes().
2495 * Create X checkmark bitmap and initialize option menu checks.
2497 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2498 checkmark_bits, checkmark_width, checkmark_height);
2499 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2500 #ifndef OPTIONSDIALOG
2501 if (appData.alwaysPromoteToQueen) {
2502 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2505 if (appData.animateDragging) {
2506 XtSetValues(XtNameToWidget(menuBarWidget,
2507 "menuOptions.Animate Dragging"),
2510 if (appData.animate) {
2511 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2514 if (appData.autoCallFlag) {
2515 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2518 if (appData.autoFlipView) {
2519 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2522 if (appData.blindfold) {
2523 XtSetValues(XtNameToWidget(menuBarWidget,
2524 "menuOptions.Blindfold"), args, 1);
2526 if (appData.flashCount > 0) {
2527 XtSetValues(XtNameToWidget(menuBarWidget,
2528 "menuOptions.Flash Moves"),
2532 if (appData.highlightDragging) {
2533 XtSetValues(XtNameToWidget(menuBarWidget,
2534 "menuOptions.Highlight Dragging"),
2538 if (appData.highlightLastMove) {
2539 XtSetValues(XtNameToWidget(menuBarWidget,
2540 "menuOptions.Highlight Last Move"),
2543 if (appData.highlightMoveWithArrow) {
2544 XtSetValues(XtNameToWidget(menuBarWidget,
2545 "menuOptions.Arrow"),
2548 // if (appData.icsAlarm) {
2549 // XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2552 if (appData.ringBellAfterMoves) {
2553 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2556 if (appData.oneClick) {
2557 XtSetValues(XtNameToWidget(menuBarWidget,
2558 "menuOptions.OneClick"), args, 1);
2560 if (appData.periodicUpdates) {
2561 XtSetValues(XtNameToWidget(menuBarWidget,
2562 "menuOptions.Periodic Updates"), args, 1);
2564 if (appData.ponderNextMove) {
2565 XtSetValues(XtNameToWidget(menuBarWidget,
2566 "menuOptions.Ponder Next Move"), args, 1);
2568 if (appData.popupExitMessage) {
2569 XtSetValues(XtNameToWidget(menuBarWidget,
2570 "menuOptions.Popup Exit Message"), args, 1);
2572 if (appData.popupMoveErrors) {
2573 XtSetValues(XtNameToWidget(menuBarWidget,
2574 "menuOptions.Popup Move Errors"), args, 1);
2576 // if (appData.premove) {
2577 // XtSetValues(XtNameToWidget(menuBarWidget,
2578 // "menuOptions.Premove"), args, 1);
2580 if (appData.showCoords) {
2581 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2584 if (appData.hideThinkingFromHuman) {
2585 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2588 if (appData.testLegality) {
2589 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2593 if (saveSettingsOnExit) {
2594 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2601 ReadBitmap(&wIconPixmap, "icon_white.bm",
2602 icon_white_bits, icon_white_width, icon_white_height);
2603 ReadBitmap(&bIconPixmap, "icon_black.bm",
2604 icon_black_bits, icon_black_width, icon_black_height);
2605 iconPixmap = wIconPixmap;
2607 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2608 XtSetValues(shellWidget, args, i);
2611 * Create a cursor for the board widget.
2613 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2614 XChangeWindowAttributes(xDisplay, xBoardWindow,
2615 CWCursor, &window_attributes);
2618 * Inhibit shell resizing.
2620 shellArgs[0].value = (XtArgVal) &w;
2621 shellArgs[1].value = (XtArgVal) &h;
2622 XtGetValues(shellWidget, shellArgs, 2);
2623 shellArgs[4].value = shellArgs[2].value = w;
2624 shellArgs[5].value = shellArgs[3].value = h;
2625 XtSetValues(shellWidget, &shellArgs[2], 4);
2626 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2627 marginH = h - boardHeight;
2629 CatchDeleteWindow(shellWidget, "QuitProc");
2637 if (appData.animate || appData.animateDragging)
2640 XtAugmentTranslations(formWidget,
2641 XtParseTranslationTable(globalTranslations));
2642 XtAugmentTranslations(boardWidget,
2643 XtParseTranslationTable(boardTranslations));
2644 XtAugmentTranslations(whiteTimerWidget,
2645 XtParseTranslationTable(whiteTranslations));
2646 XtAugmentTranslations(blackTimerWidget,
2647 XtParseTranslationTable(blackTranslations));
2649 /* Why is the following needed on some versions of X instead
2650 * of a translation? */
2651 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2652 (XtEventHandler) EventProc, NULL);
2654 XtAddEventHandler(formWidget, KeyPressMask, False,
2655 (XtEventHandler) MoveTypeInProc, NULL);
2657 /* [AS] Restore layout */
2658 if( wpMoveHistory.visible ) {
2662 if( wpEvalGraph.visible )
2667 if( wpEngineOutput.visible ) {
2668 EngineOutputPopUp();
2673 if (errorExitStatus == -1) {
2674 if (appData.icsActive) {
2675 /* We now wait until we see "login:" from the ICS before
2676 sending the logon script (problems with timestamp otherwise) */
2677 /*ICSInitScript();*/
2678 if (appData.icsInputBox) ICSInputBoxPopUp();
2682 signal(SIGWINCH, TermSizeSigHandler);
2684 signal(SIGINT, IntSigHandler);
2685 signal(SIGTERM, IntSigHandler);
2686 if (*appData.cmailGameName != NULLCHAR) {
2687 signal(SIGUSR1, CmailSigHandler);
2690 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2692 // XtSetKeyboardFocus(shellWidget, formWidget);
2693 XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
2695 XtAppMainLoop(appContext);
2696 if (appData.debugMode) fclose(debugFP); // [DM] debug
2700 static Boolean noEcho;
2705 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2706 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2708 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2709 unlink(gameCopyFilename);
2710 unlink(gamePasteFilename);
2711 if(noEcho) EchoOn();
2714 RETSIGTYPE TermSizeSigHandler(int sig)
2727 CmailSigHandler(sig)
2733 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2735 /* Activate call-back function CmailSigHandlerCallBack() */
2736 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2738 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2742 CmailSigHandlerCallBack(isr, closure, message, count, error)
2750 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2752 /**** end signal code ****/
2758 /* try to open the icsLogon script, either in the location given
2759 * or in the users HOME directory
2766 f = fopen(appData.icsLogon, "r");
2769 homedir = getenv("HOME");
2770 if (homedir != NULL)
2772 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2773 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2774 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2775 f = fopen(buf, "r");
2780 ProcessICSInitScript(f);
2782 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2805 if (!menuBarWidget) return;
2806 w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2808 DisplayError("menuEdit.Revert", 0);
2810 XtSetSensitive(w, !grey);
2812 w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2814 DisplayError("menuEdit.Annotate", 0);
2816 XtSetSensitive(w, !grey);
2821 SetMenuEnables(enab)
2825 if (!menuBarWidget) return;
2826 while (enab->name != NULL) {
2827 w = XtNameToWidget(menuBarWidget, enab->name);
2829 DisplayError(enab->name, 0);
2831 XtSetSensitive(w, enab->value);
2837 Enables icsEnables[] = {
2838 { "menuFile.Mail Move", False },
2839 { "menuFile.Reload CMail Message", False },
2840 { "menuMode.Machine Black", False },
2841 { "menuMode.Machine White", False },
2842 { "menuMode.Analysis Mode", False },
2843 { "menuMode.Analyze File", False },
2844 { "menuMode.Two Machines", False },
2845 { "menuMode.Machine Match", False },
2847 { "menuEngine.Hint", False },
2848 { "menuEngine.Book", False },
2849 { "menuEngine.Move Now", False },
2850 #ifndef OPTIONSDIALOG
2851 { "menuOptions.Periodic Updates", False },
2852 { "menuOptions.Hide Thinking", False },
2853 { "menuOptions.Ponder Next Move", False },
2856 { "menuEngine.Engine #1 Settings", False },
2857 { "menuEngine.Engine #2 Settings", False },
2858 { "menuEngine.Load Engine", False },
2859 { "menuEdit.Annotate", False },
2860 { "menuOptions.Match", False },
2864 Enables ncpEnables[] = {
2865 { "menuFile.Mail Move", False },
2866 { "menuFile.Reload CMail Message", False },
2867 { "menuMode.Machine White", False },
2868 { "menuMode.Machine Black", False },
2869 { "menuMode.Analysis Mode", False },
2870 { "menuMode.Analyze File", False },
2871 { "menuMode.Two Machines", False },
2872 { "menuMode.Machine Match", False },
2873 { "menuMode.ICS Client", False },
2874 { "menuView.ICStex", False },
2875 { "menuView.ICS Input Box", False },
2876 { "Action", False },
2877 { "menuEdit.Revert", False },
2878 { "menuEdit.Annotate", False },
2879 { "menuEngine.Engine #1 Settings", False },
2880 { "menuEngine.Engine #2 Settings", False },
2881 { "menuEngine.Move Now", False },
2882 { "menuEngine.Retract Move", False },
2883 { "menuOptions.ICS", False },
2884 #ifndef OPTIONSDIALOG
2885 { "menuOptions.Auto Flag", False },
2886 { "menuOptions.Auto Flip View", False },
2887 // { "menuOptions.ICS Alarm", False },
2888 { "menuOptions.Move Sound", False },
2889 { "menuOptions.Hide Thinking", False },
2890 { "menuOptions.Periodic Updates", False },
2891 { "menuOptions.Ponder Next Move", False },
2893 { "menuEngine.Hint", False },
2894 { "menuEngine.Book", False },
2898 Enables gnuEnables[] = {
2899 { "menuMode.ICS Client", False },
2900 { "menuView.ICStex", False },
2901 { "menuView.ICS Input Box", False },
2902 { "menuAction.Accept", False },
2903 { "menuAction.Decline", False },
2904 { "menuAction.Rematch", False },
2905 { "menuAction.Adjourn", False },
2906 { "menuAction.Stop Examining", False },
2907 { "menuAction.Stop Observing", False },
2908 { "menuAction.Upload to Examine", False },
2909 { "menuEdit.Revert", False },
2910 { "menuEdit.Annotate", False },
2911 { "menuOptions.ICS", False },
2913 /* The next two options rely on SetCmailMode being called *after* */
2914 /* SetGNUMode so that when GNU is being used to give hints these */
2915 /* menu options are still available */
2917 { "menuFile.Mail Move", False },
2918 { "menuFile.Reload CMail Message", False },
2919 // [HGM] The following have been added to make a switch from ncp to GNU mode possible
2920 { "menuMode.Machine White", True },
2921 { "menuMode.Machine Black", True },
2922 { "menuMode.Analysis Mode", True },
2923 { "menuMode.Analyze File", True },
2924 { "menuMode.Two Machines", True },
2925 { "menuMode.Machine Match", True },
2926 { "menuEngine.Engine #1 Settings", True },
2927 { "menuEngine.Engine #2 Settings", True },
2928 { "menuEngine.Hint", True },
2929 { "menuEngine.Book", True },
2930 { "menuEngine.Move Now", True },
2931 { "menuEngine.Retract Move", True },
2936 Enables cmailEnables[] = {
2938 { "menuAction.Call Flag", False },
2939 { "menuAction.Draw", True },
2940 { "menuAction.Adjourn", False },
2941 { "menuAction.Abort", False },
2942 { "menuAction.Stop Observing", False },
2943 { "menuAction.Stop Examining", False },
2944 { "menuFile.Mail Move", True },
2945 { "menuFile.Reload CMail Message", True },
2949 Enables trainingOnEnables[] = {
2950 { "menuMode.Edit Comment", False },
2951 { "menuMode.Pause", False },
2952 { "menuEdit.Forward", False },
2953 { "menuEdit.Backward", False },
2954 { "menuEdit.Forward to End", False },
2955 { "menuEdit.Back to Start", False },
2956 { "menuEngine.Move Now", False },
2957 { "menuEdit.Truncate Game", False },
2961 Enables trainingOffEnables[] = {
2962 { "menuMode.Edit Comment", True },
2963 { "menuMode.Pause", True },
2964 { "menuEdit.Forward", True },
2965 { "menuEdit.Backward", True },
2966 { "menuEdit.Forward to End", True },
2967 { "menuEdit.Back to Start", True },
2968 { "menuEngine.Move Now", True },
2969 { "menuEdit.Truncate Game", True },
2973 Enables machineThinkingEnables[] = {
2974 { "menuFile.Load Game", False },
2975 // { "menuFile.Load Next Game", False },
2976 // { "menuFile.Load Previous Game", False },
2977 // { "menuFile.Reload Same Game", False },
2978 { "menuEdit.Paste Game", False },
2979 { "menuFile.Load Position", False },
2980 // { "menuFile.Load Next Position", False },
2981 // { "menuFile.Load Previous Position", False },
2982 // { "menuFile.Reload Same Position", False },
2983 { "menuEdit.Paste Position", False },
2984 { "menuMode.Machine White", False },
2985 { "menuMode.Machine Black", False },
2986 { "menuMode.Two Machines", False },
2987 // { "menuMode.Machine Match", False },
2988 { "menuEngine.Retract Move", False },
2992 Enables userThinkingEnables[] = {
2993 { "menuFile.Load Game", True },
2994 // { "menuFile.Load Next Game", True },
2995 // { "menuFile.Load Previous Game", True },
2996 // { "menuFile.Reload Same Game", True },
2997 { "menuEdit.Paste Game", True },
2998 { "menuFile.Load Position", True },
2999 // { "menuFile.Load Next Position", True },
3000 // { "menuFile.Load Previous Position", True },
3001 // { "menuFile.Reload Same Position", True },
3002 { "menuEdit.Paste Position", True },
3003 { "menuMode.Machine White", True },
3004 { "menuMode.Machine Black", True },
3005 { "menuMode.Two Machines", True },
3006 // { "menuMode.Machine Match", True },
3007 { "menuEngine.Retract Move", True },
3013 SetMenuEnables(icsEnables);
3016 if (appData.zippyPlay && !appData.noChessProgram) { /* [DM] icsEngineAnalyze */
3017 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
3018 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuEngine.Engine #1 Settings"), True);
3026 SetMenuEnables(ncpEnables);
3032 SetMenuEnables(gnuEnables);
3038 SetMenuEnables(cmailEnables);
3044 SetMenuEnables(trainingOnEnables);
3045 if (appData.showButtonBar) {
3046 XtSetSensitive(buttonBarWidget, False);
3052 SetTrainingModeOff()
3054 SetMenuEnables(trainingOffEnables);
3055 if (appData.showButtonBar) {
3056 XtSetSensitive(buttonBarWidget, True);
3061 SetUserThinkingEnables()
3063 if (appData.noChessProgram) return;
3064 SetMenuEnables(userThinkingEnables);
3068 SetMachineThinkingEnables()
3070 if (appData.noChessProgram) return;
3071 SetMenuEnables(machineThinkingEnables);
3073 case MachinePlaysBlack:
3074 case MachinePlaysWhite:
3075 case TwoMachinesPlay:
3076 XtSetSensitive(XtNameToWidget(menuBarWidget,
3077 ModeToWidgetName(gameMode)), True);
3084 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
3085 #define HISTORY_SIZE 64
3086 static char *history[HISTORY_SIZE];
3087 int histIn = 0, histP = 0;
3090 SaveInHistory(char *cmd)
3092 if (history[histIn] != NULL) {
3093 free(history[histIn]);
3094 history[histIn] = NULL;
3096 if (*cmd == NULLCHAR) return;
3097 history[histIn] = StrSave(cmd);
3098 histIn = (histIn + 1) % HISTORY_SIZE;
3099 if (history[histIn] != NULL) {
3100 free(history[histIn]);
3101 history[histIn] = NULL;
3107 PrevInHistory(char *cmd)
3110 if (histP == histIn) {
3111 if (history[histIn] != NULL) free(history[histIn]);
3112 history[histIn] = StrSave(cmd);
3114 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
3115 if (newhp == histIn || history[newhp] == NULL) return NULL;
3117 return history[histP];
3123 if (histP == histIn) return NULL;
3124 histP = (histP + 1) % HISTORY_SIZE;
3125 return history[histP];
3127 // end of borrowed code
3129 #define Abs(n) ((n)<0 ? -(n) : (n))
3133 InsertPxlSize(pattern, targetPxlSize)
3137 char *base_fnt_lst, strInt[12], *p, *q;
3138 int alternatives, i, len, strIntLen;
3141 * Replace the "*" (if present) in the pixel-size slot of each
3142 * alternative with the targetPxlSize.
3146 while ((p = strchr(p, ',')) != NULL) {
3150 snprintf(strInt, sizeof(strInt), "%d", targetPxlSize);
3151 strIntLen = strlen(strInt);
3152 base_fnt_lst = calloc(1, strlen(pattern) + strIntLen * alternatives + 1);
3156 while (alternatives--) {
3157 char *comma = strchr(p, ',');
3158 for (i=0; i<14; i++) {
3159 char *hyphen = strchr(p, '-');
3161 if (comma && hyphen > comma) break;
3162 len = hyphen + 1 - p;
3163 if (i == 7 && *p == '*' && len == 2) {
3165 memcpy(q, strInt, strIntLen);
3175 len = comma + 1 - p;
3182 return base_fnt_lst;
3186 CreateFontSet(base_fnt_lst)
3190 char **missing_list;
3194 fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
3195 &missing_list, &missing_count, &def_string);
3196 if (appData.debugMode) {
3198 XFontStruct **font_struct_list;
3199 char **font_name_list;
3200 fprintf(debugFP, "Requested font set for list %s\n", base_fnt_lst);
3202 fprintf(debugFP, " got list %s, locale %s\n",
3203 XBaseFontNameListOfFontSet(fntSet),
3204 XLocaleOfFontSet(fntSet));
3205 count = XFontsOfFontSet(fntSet, &font_struct_list, &font_name_list);
3206 for (i = 0; i < count; i++) {
3207 fprintf(debugFP, " got charset %s\n", font_name_list[i]);
3210 for (i = 0; i < missing_count; i++) {
3211 fprintf(debugFP, " missing charset %s\n", missing_list[i]);
3214 if (fntSet == NULL) {
3215 fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
3220 #else // not ENABLE_NLS
3222 * Find a font that matches "pattern" that is as close as
3223 * possible to the targetPxlSize. Prefer fonts that are k
3224 * pixels smaller to fonts that are k pixels larger. The
3225 * pattern must be in the X Consortium standard format,
3226 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3227 * The return value should be freed with XtFree when no
3231 FindFont(pattern, targetPxlSize)
3235 char **fonts, *p, *best, *scalable, *scalableTail;
3236 int i, j, nfonts, minerr, err, pxlSize;
3238 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3240 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3241 programName, pattern);
3248 for (i=0; i<nfonts; i++) {
3251 if (*p != '-') continue;
3253 if (*p == NULLCHAR) break;
3254 if (*p++ == '-') j++;
3256 if (j < 7) continue;
3259 scalable = fonts[i];
3262 err = pxlSize - targetPxlSize;
3263 if (Abs(err) < Abs(minerr) ||
3264 (minerr > 0 && err < 0 && -err == minerr)) {
3270 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3271 /* If the error is too big and there is a scalable font,
3272 use the scalable font. */
3273 int headlen = scalableTail - scalable;
3274 p = (char *) XtMalloc(strlen(scalable) + 10);
3275 while (isdigit(*scalableTail)) scalableTail++;
3276 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3278 p = (char *) XtMalloc(strlen(best) + 2);
3279 safeStrCpy(p, best, strlen(best)+1 );
3281 if (appData.debugMode) {
3282 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3283 pattern, targetPxlSize, p);
3285 XFreeFontNames(fonts);
3291 { // [HGM] deletes GCs that are to be remade, to prevent resource leak;
3292 // must be called before all non-first callse to CreateGCs()
3293 XtReleaseGC(shellWidget, highlineGC);
3294 XtReleaseGC(shellWidget, lightSquareGC);
3295 XtReleaseGC(shellWidget, darkSquareGC);
3296 XtReleaseGC(shellWidget, lineGC);
3297 if (appData.monoMode) {
3298 if (DefaultDepth(xDisplay, xScreen) == 1) {
3299 XtReleaseGC(shellWidget, wbPieceGC);
3301 XtReleaseGC(shellWidget, bwPieceGC);
3304 XtReleaseGC(shellWidget, prelineGC);
3305 XtReleaseGC(shellWidget, jailSquareGC);
3306 XtReleaseGC(shellWidget, wdPieceGC);
3307 XtReleaseGC(shellWidget, wlPieceGC);
3308 XtReleaseGC(shellWidget, wjPieceGC);
3309 XtReleaseGC(shellWidget, bdPieceGC);
3310 XtReleaseGC(shellWidget, blPieceGC);
3311 XtReleaseGC(shellWidget, bjPieceGC);
3315 void CreateGCs(int redo)
3317 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3318 | GCBackground | GCFunction | GCPlaneMask;
3319 XGCValues gc_values;
3322 gc_values.plane_mask = AllPlanes;
3323 gc_values.line_width = lineGap;
3324 gc_values.line_style = LineSolid;
3325 gc_values.function = GXcopy;
3328 DeleteGCs(); // called a second time; clean up old GCs first
3329 } else { // [HGM] grid and font GCs created on first call only
3330 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3331 gc_values.background = XWhitePixel(xDisplay, xScreen);
3332 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3333 XSetFont(xDisplay, coordGC, coordFontID);
3335 // [HGM] make font for holdings counts (white on black)
3336 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3337 gc_values.background = XBlackPixel(xDisplay, xScreen);
3338 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3339 XSetFont(xDisplay, countGC, countFontID);
3341 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3342 gc_values.background = XBlackPixel(xDisplay, xScreen);
3343 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3345 if (appData.monoMode) {
3346 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3347 gc_values.background = XWhitePixel(xDisplay, xScreen);
3348 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3350 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3351 gc_values.background = XBlackPixel(xDisplay, xScreen);
3352 lightSquareGC = wbPieceGC
3353 = XtGetGC(shellWidget, value_mask, &gc_values);
3355 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3356 gc_values.background = XWhitePixel(xDisplay, xScreen);
3357 darkSquareGC = bwPieceGC
3358 = XtGetGC(shellWidget, value_mask, &gc_values);
3360 if (DefaultDepth(xDisplay, xScreen) == 1) {
3361 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3362 gc_values.function = GXcopyInverted;
3363 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3364 gc_values.function = GXcopy;
3365 if (XBlackPixel(xDisplay, xScreen) == 1) {
3366 bwPieceGC = darkSquareGC;
3367 wbPieceGC = copyInvertedGC;
3369 bwPieceGC = copyInvertedGC;
3370 wbPieceGC = lightSquareGC;
3374 gc_values.foreground = highlightSquareColor;
3375 gc_values.background = highlightSquareColor;
3376 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3378 gc_values.foreground = premoveHighlightColor;
3379 gc_values.background = premoveHighlightColor;
3380 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3382 gc_values.foreground = lightSquareColor;
3383 gc_values.background = darkSquareColor;
3384 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3386 gc_values.foreground = darkSquareColor;
3387 gc_values.background = lightSquareColor;
3388 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3390 gc_values.foreground = jailSquareColor;
3391 gc_values.background = jailSquareColor;
3392 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3394 gc_values.foreground = whitePieceColor;
3395 gc_values.background = darkSquareColor;
3396 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3398 gc_values.foreground = whitePieceColor;
3399 gc_values.background = lightSquareColor;
3400 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3402 gc_values.foreground = whitePieceColor;
3403 gc_values.background = jailSquareColor;
3404 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3406 gc_values.foreground = blackPieceColor;
3407 gc_values.background = darkSquareColor;
3408 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3410 gc_values.foreground = blackPieceColor;
3411 gc_values.background = lightSquareColor;
3412 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3414 gc_values.foreground = blackPieceColor;
3415 gc_values.background = jailSquareColor;
3416 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3420 void loadXIM(xim, xmask, filename, dest, mask)
3433 fp = fopen(filename, "rb");
3435 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3442 for (y=0; y<h; ++y) {
3443 for (x=0; x<h; ++x) {
3448 XPutPixel(xim, x, y, blackPieceColor);
3450 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3453 XPutPixel(xim, x, y, darkSquareColor);
3455 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3458 XPutPixel(xim, x, y, whitePieceColor);
3460 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3463 XPutPixel(xim, x, y, lightSquareColor);
3465 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3473 /* create Pixmap of piece */
3474 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3476 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3479 /* create Pixmap of clipmask
3480 Note: We assume the white/black pieces have the same
3481 outline, so we make only 6 masks. This is okay
3482 since the XPM clipmask routines do the same. */
3484 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3486 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3489 /* now create the 1-bit version */
3490 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3493 values.foreground = 1;
3494 values.background = 0;
3496 /* Don't use XtGetGC, not read only */
3497 maskGC = XCreateGC(xDisplay, *mask,
3498 GCForeground | GCBackground, &values);
3499 XCopyPlane(xDisplay, temp, *mask, maskGC,
3500 0, 0, squareSize, squareSize, 0, 0, 1);
3501 XFreePixmap(xDisplay, temp);
3506 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3508 void CreateXIMPieces()
3513 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3518 /* The XSynchronize calls were copied from CreatePieces.
3519 Not sure if needed, but can't hurt */
3520 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3523 /* temp needed by loadXIM() */
3524 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3525 0, 0, ss, ss, AllPlanes, XYPixmap);
3527 if (strlen(appData.pixmapDirectory) == 0) {
3531 if (appData.monoMode) {
3532 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3536 fprintf(stderr, _("\nLoading XIMs...\n"));
3538 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3539 fprintf(stderr, "%d", piece+1);
3540 for (kind=0; kind<4; kind++) {
3541 fprintf(stderr, ".");
3542 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3543 ExpandPathName(appData.pixmapDirectory),
3544 piece <= (int) WhiteKing ? "" : "w",
3545 pieceBitmapNames[piece],
3547 ximPieceBitmap[kind][piece] =
3548 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3549 0, 0, ss, ss, AllPlanes, XYPixmap);
3550 if (appData.debugMode)
3551 fprintf(stderr, _("(File:%s:) "), buf);
3552 loadXIM(ximPieceBitmap[kind][piece],
3554 &(xpmPieceBitmap2[kind][piece]),
3555 &(ximMaskPm2[piece]));
3556 if(piece <= (int)WhiteKing)
3557 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3559 fprintf(stderr," ");
3561 /* Load light and dark squares */
3562 /* If the LSQ and DSQ pieces don't exist, we will
3563 draw them with solid squares. */
3564 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3565 if (access(buf, 0) != 0) {
3569 fprintf(stderr, _("light square "));
3571 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3572 0, 0, ss, ss, AllPlanes, XYPixmap);
3573 if (appData.debugMode)
3574 fprintf(stderr, _("(File:%s:) "), buf);
3576 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3577 fprintf(stderr, _("dark square "));
3578 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3579 ExpandPathName(appData.pixmapDirectory), ss);
3580 if (appData.debugMode)
3581 fprintf(stderr, _("(File:%s:) "), buf);
3583 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3584 0, 0, ss, ss, AllPlanes, XYPixmap);
3585 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3586 xpmJailSquare = xpmLightSquare;
3588 fprintf(stderr, _("Done.\n"));
3590 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3593 static VariantClass oldVariant = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
3596 void CreateXPMBoard(char *s, int kind)
3600 if(s == NULL || *s == 0 || *s == '*') { useTexture &= ~(kind+1); return; }
3601 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3602 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3606 void FreeXPMPieces()
3607 { // [HGM] to prevent resoucre leak on calling CreaeXPMPieces() a second time,
3608 // thisroutine has to be called t free the old piece pixmaps
3610 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++)
3611 for (kind=0; kind<4; kind++) XFreePixmap(xDisplay, xpmPieceBitmap2[kind][piece]);
3613 XFreePixmap(xDisplay, xpmLightSquare);
3614 XFreePixmap(xDisplay, xpmDarkSquare);
3618 void CreateXPMPieces()
3622 u_int ss = squareSize;
3624 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3625 XpmColorSymbol symbols[4];
3626 static int redo = False;
3628 if(redo) FreeXPMPieces(); else redo = 1;
3630 /* The XSynchronize calls were copied from CreatePieces.
3631 Not sure if needed, but can't hurt */
3632 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3634 /* Setup translations so piece colors match square colors */
3635 symbols[0].name = "light_piece";
3636 symbols[0].value = appData.whitePieceColor;
3637 symbols[1].name = "dark_piece";
3638 symbols[1].value = appData.blackPieceColor;
3639 symbols[2].name = "light_square";
3640 symbols[2].value = appData.lightSquareColor;
3641 symbols[3].name = "dark_square";
3642 symbols[3].value = appData.darkSquareColor;
3644 attr.valuemask = XpmColorSymbols;
3645 attr.colorsymbols = symbols;
3646 attr.numsymbols = 4;
3648 if (appData.monoMode) {
3649 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3653 if (strlen(appData.pixmapDirectory) == 0) {
3654 XpmPieces* pieces = builtInXpms;
3657 while (pieces->size != squareSize && pieces->size) pieces++;
3658 if (!pieces->size) {
3659 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3662 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3663 for (kind=0; kind<4; kind++) {
3665 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3666 pieces->xpm[piece][kind],
3667 &(xpmPieceBitmap2[kind][piece]),
3668 NULL, &attr)) != 0) {
3669 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3673 if(piece <= (int) WhiteKing)
3674 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3678 xpmJailSquare = xpmLightSquare;
3682 fprintf(stderr, _("\nLoading XPMs...\n"));
3685 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3686 fprintf(stderr, "%d ", piece+1);
3687 for (kind=0; kind<4; kind++) {
3688 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3689 ExpandPathName(appData.pixmapDirectory),
3690 piece > (int) WhiteKing ? "w" : "",
3691 pieceBitmapNames[piece],
3693 if (appData.debugMode) {
3694 fprintf(stderr, _("(File:%s:) "), buf);
3696 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3697 &(xpmPieceBitmap2[kind][piece]),
3698 NULL, &attr)) != 0) {
3699 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3700 // [HGM] missing: read of unorthodox piece failed; substitute King.
3701 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3702 ExpandPathName(appData.pixmapDirectory),
3704 if (appData.debugMode) {
3705 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3707 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3708 &(xpmPieceBitmap2[kind][piece]),
3712 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3717 if(piece <= (int) WhiteKing)
3718 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3721 /* Load light and dark squares */
3722 /* If the LSQ and DSQ pieces don't exist, we will
3723 draw them with solid squares. */
3724 fprintf(stderr, _("light square "));
3725 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3726 if (access(buf, 0) != 0) {
3730 if (appData.debugMode)
3731 fprintf(stderr, _("(File:%s:) "), buf);
3733 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3734 &xpmLightSquare, NULL, &attr)) != 0) {
3735 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3738 fprintf(stderr, _("dark square "));
3739 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3740 ExpandPathName(appData.pixmapDirectory), ss);
3741 if (appData.debugMode) {
3742 fprintf(stderr, _("(File:%s:) "), buf);
3744 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3745 &xpmDarkSquare, NULL, &attr)) != 0) {
3746 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3750 xpmJailSquare = xpmLightSquare;
3751 fprintf(stderr, _("Done.\n"));
3753 oldVariant = -1; // kludge to force re-makig of animation masks
3754 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3757 #endif /* HAVE_LIBXPM */
3760 /* No built-in bitmaps */
3765 u_int ss = squareSize;
3767 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3770 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3771 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3772 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3773 pieceBitmapNames[piece],
3774 ss, kind == SOLID ? 's' : 'o');
3775 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3776 if(piece <= (int)WhiteKing)
3777 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3781 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3785 /* With built-in bitmaps */
3788 BuiltInBits* bib = builtInBits;
3791 u_int ss = squareSize;
3793 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3796 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3798 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3799 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3800 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3801 pieceBitmapNames[piece],
3802 ss, kind == SOLID ? 's' : 'o');
3803 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3804 bib->bits[kind][piece], ss, ss);
3805 if(piece <= (int)WhiteKing)
3806 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3810 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3815 void ReadBitmap(pm, name, bits, wreq, hreq)
3818 unsigned char bits[];
3824 char msg[MSG_SIZ], fullname[MSG_SIZ];
3826 if (*appData.bitmapDirectory != NULLCHAR) {
3827 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3828 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3829 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3830 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3831 &w, &h, pm, &x_hot, &y_hot);
3832 fprintf(stderr, "load %s\n", name);
3833 if (errcode != BitmapSuccess) {
3835 case BitmapOpenFailed:
3836 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3838 case BitmapFileInvalid:
3839 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3841 case BitmapNoMemory:
3842 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3846 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3850 fprintf(stderr, _("%s: %s...using built-in\n"),
3852 } else if (w != wreq || h != hreq) {
3854 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3855 programName, fullname, w, h, wreq, hreq);
3861 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3870 if (lineGap == 0) return;
3872 /* [HR] Split this into 2 loops for non-square boards. */
3874 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3875 gridSegments[i].x1 = 0;
3876 gridSegments[i].x2 =
3877 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3878 gridSegments[i].y1 = gridSegments[i].y2
3879 = lineGap / 2 + (i * (squareSize + lineGap));
3882 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3883 gridSegments[j + i].y1 = 0;
3884 gridSegments[j + i].y2 =
3885 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3886 gridSegments[j + i].x1 = gridSegments[j + i].x2
3887 = lineGap / 2 + (j * (squareSize + lineGap));
3891 static void MenuBarSelect(w, addr, index)
3896 XtActionProc proc = (XtActionProc) addr;
3898 (proc)(NULL, NULL, NULL, NULL);
3901 void CreateMenuBarPopup(parent, name, mb)
3911 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3914 XtSetArg(args[j], XtNleftMargin, 20); j++;
3915 XtSetArg(args[j], XtNrightMargin, 20); j++;
3917 while (mi->string != NULL) {
3918 if (strcmp(mi->string, "----") == 0) {
3919 entry = XtCreateManagedWidget(_(mi->string), smeLineObjectClass,
3922 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3923 entry = XtCreateManagedWidget(mi->ref, smeBSBObjectClass,
3925 XtAddCallback(entry, XtNcallback,
3926 (XtCallbackProc) MenuBarSelect,
3927 (caddr_t) mi->proc);
3933 Widget CreateMenuBar(mb)
3937 Widget anchor, menuBar;
3939 char menuName[MSG_SIZ];
3942 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3943 XtSetArg(args[j], XtNvSpace, 0); j++;
3944 XtSetArg(args[j], XtNborderWidth, 0); j++;
3945 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3946 formWidget, args, j);
3948 while (mb->name != NULL) {
3949 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3950 strncat(menuName, mb->ref, MSG_SIZ - strlen(menuName) - 1);
3952 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3955 shortName[0] = mb->name[0];
3956 shortName[1] = NULLCHAR;
3957 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3960 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3963 XtSetArg(args[j], XtNborderWidth, 0); j++;
3964 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3966 CreateMenuBarPopup(menuBar, menuName, mb);
3972 Widget CreateButtonBar(mi)
3976 Widget button, buttonBar;
3980 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3982 XtSetArg(args[j], XtNhSpace, 0); j++;
3984 XtSetArg(args[j], XtNborderWidth, 0); j++;
3985 XtSetArg(args[j], XtNvSpace, 0); j++;
3986 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3987 formWidget, args, j);
3989 while (mi->string != NULL) {
3992 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3993 XtSetArg(args[j], XtNborderWidth, 0); j++;
3995 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3996 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3997 buttonBar, args, j);
3998 XtAddCallback(button, XtNcallback,
3999 (XtCallbackProc) MenuBarSelect,
4000 (caddr_t) mi->proc);
4007 CreatePieceMenu(name, color)
4014 ChessSquare selection;
4016 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
4017 boardWidget, args, 0);
4019 for (i = 0; i < PIECE_MENU_SIZE; i++) {
4020 String item = pieceMenuStrings[color][i];
4022 if (strcmp(item, "----") == 0) {
4023 entry = XtCreateManagedWidget(item, smeLineObjectClass,
4026 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
4027 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
4029 selection = pieceMenuTranslation[color][i];
4030 XtAddCallback(entry, XtNcallback,
4031 (XtCallbackProc) PieceMenuSelect,
4032 (caddr_t) selection);
4033 if (selection == WhitePawn || selection == BlackPawn) {
4034 XtSetArg(args[0], XtNpopupOnEntry, entry);
4035 XtSetValues(menu, args, 1);
4048 ChessSquare selection;
4050 whitePieceMenu = CreatePieceMenu("menuW", 0);
4051 blackPieceMenu = CreatePieceMenu("menuB", 1);
4053 XtRegisterGrabAction(PieceMenuPopup, True,
4054 (unsigned)(ButtonPressMask|ButtonReleaseMask),
4055 GrabModeAsync, GrabModeAsync);
4057 XtSetArg(args[0], XtNlabel, _("Drop"));
4058 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
4059 boardWidget, args, 1);
4060 for (i = 0; i < DROP_MENU_SIZE; i++) {
4061 String item = dropMenuStrings[i];
4063 if (strcmp(item, "----") == 0) {
4064 entry = XtCreateManagedWidget(item, smeLineObjectClass,
4067 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
4068 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
4070 selection = dropMenuTranslation[i];
4071 XtAddCallback(entry, XtNcallback,
4072 (XtCallbackProc) DropMenuSelect,
4073 (caddr_t) selection);
4078 void SetupDropMenu()
4086 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
4087 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
4088 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
4089 dmEnables[i].piece);
4090 XtSetSensitive(entry, p != NULL || !appData.testLegality
4091 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
4092 && !appData.icsActive));
4094 while (p && *p++ == dmEnables[i].piece) count++;
4095 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
4097 XtSetArg(args[j], XtNlabel, label); j++;
4098 XtSetValues(entry, args, j);
4102 void PieceMenuPopup(w, event, params, num_params)
4106 Cardinal *num_params;
4108 String whichMenu; int menuNr = -2;
4109 shiftKey = strcmp(params[0], "menuW"); // used to indicate black
4110 if (event->type == ButtonRelease)
4111 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
4112 else if (event->type == ButtonPress)
4113 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
4115 case 0: whichMenu = params[0]; break;
4116 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
4118 case -1: if (errorUp) ErrorPopDown();
4121 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
4124 static void PieceMenuSelect(w, piece, junk)
4129 if (pmFromX < 0 || pmFromY < 0) return;
4130 EditPositionMenuEvent(piece, pmFromX, pmFromY);
4133 static void DropMenuSelect(w, piece, junk)
4138 if (pmFromX < 0 || pmFromY < 0) return;
4139 DropMenuEvent(piece, pmFromX, pmFromY);
4142 void WhiteClock(w, event, prms, nprms)
4148 shiftKey = prms[0][0] & 1;
4152 void BlackClock(w, event, prms, nprms)
4158 shiftKey = prms[0][0] & 1;
4164 * If the user selects on a border boundary, return -1; if off the board,
4165 * return -2. Otherwise map the event coordinate to the square.
4167 int EventToSquare(x, limit)
4175 if ((x % (squareSize + lineGap)) >= squareSize)
4177 x /= (squareSize + lineGap);
4183 static void do_flash_delay(msec)
4189 static void drawHighlight(file, rank, gc)
4195 if (lineGap == 0) return;
4198 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
4199 (squareSize + lineGap);
4200 y = lineGap/2 + rank * (squareSize + lineGap);
4202 x = lineGap/2 + file * (squareSize + lineGap);
4203 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
4204 (squareSize + lineGap);
4207 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
4208 squareSize+lineGap, squareSize+lineGap);
4211 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
4212 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4215 SetHighlights(fromX, fromY, toX, toY)
4216 int fromX, fromY, toX, toY;
4218 if (hi1X != fromX || hi1Y != fromY) {
4219 if (hi1X >= 0 && hi1Y >= 0) {
4220 drawHighlight(hi1X, hi1Y, lineGC);
4222 } // [HGM] first erase both, then draw new!
4223 if (hi2X != toX || hi2Y != toY) {
4224 if (hi2X >= 0 && hi2Y >= 0) {
4225 drawHighlight(hi2X, hi2Y, lineGC);
4228 if (hi1X != fromX || hi1Y != fromY) {
4229 if (fromX >= 0 && fromY >= 0) {
4230 drawHighlight(fromX, fromY, highlineGC);
4233 if (hi2X != toX || hi2Y != toY) {
4234 if (toX >= 0 && toY >= 0) {
4235 drawHighlight(toX, toY, highlineGC);
4247 SetHighlights(-1, -1, -1, -1);
4252 SetPremoveHighlights(fromX, fromY, toX, toY)
4253 int fromX, fromY, toX, toY;
4255 if (pm1X != fromX || pm1Y != fromY) {
4256 if (pm1X >= 0 && pm1Y >= 0) {
4257 drawHighlight(pm1X, pm1Y, lineGC);
4259 if (fromX >= 0 && fromY >= 0) {
4260 drawHighlight(fromX, fromY, prelineGC);
4263 if (pm2X != toX || pm2Y != toY) {
4264 if (pm2X >= 0 && pm2Y >= 0) {
4265 drawHighlight(pm2X, pm2Y, lineGC);
4267 if (toX >= 0 && toY >= 0) {
4268 drawHighlight(toX, toY, prelineGC);
4278 ClearPremoveHighlights()
4280 SetPremoveHighlights(-1, -1, -1, -1);
4283 static int CutOutSquare(x, y, x0, y0, kind)
4284 int x, y, *x0, *y0, kind;
4286 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
4287 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
4289 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
4290 if(textureW[kind] < W*squareSize)
4291 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
4293 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
4294 if(textureH[kind] < H*squareSize)
4295 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
4297 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
4301 static void BlankSquare(x, y, color, piece, dest, fac)
4302 int x, y, color, fac;
4305 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
4307 if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
4308 XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
4309 squareSize, squareSize, x*fac, y*fac);
4311 if (useImages && useImageSqs) {
4315 pm = xpmLightSquare;
4320 case 2: /* neutral */
4325 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4326 squareSize, squareSize, x*fac, y*fac);
4336 case 2: /* neutral */
4341 XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
4346 I split out the routines to draw a piece so that I could
4347 make a generic flash routine.
4349 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4351 int square_color, x, y;
4354 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4355 switch (square_color) {
4357 case 2: /* neutral */
4359 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4360 ? *pieceToOutline(piece)
4361 : *pieceToSolid(piece),
4362 dest, bwPieceGC, 0, 0,
4363 squareSize, squareSize, x, y);
4366 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4367 ? *pieceToSolid(piece)
4368 : *pieceToOutline(piece),
4369 dest, wbPieceGC, 0, 0,
4370 squareSize, squareSize, x, y);
4375 static void monoDrawPiece(piece, square_color, x, y, dest)
4377 int square_color, x, y;
4380 switch (square_color) {
4382 case 2: /* neutral */
4384 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4385 ? *pieceToOutline(piece)
4386 : *pieceToSolid(piece),
4387 dest, bwPieceGC, 0, 0,
4388 squareSize, squareSize, x, y, 1);
4391 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4392 ? *pieceToSolid(piece)
4393 : *pieceToOutline(piece),
4394 dest, wbPieceGC, 0, 0,
4395 squareSize, squareSize, x, y, 1);
4400 static void colorDrawPiece(piece, square_color, x, y, dest)
4402 int square_color, x, y;
4405 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4406 switch (square_color) {
4408 XCopyPlane(xDisplay, *pieceToSolid(piece),
4409 dest, (int) piece < (int) BlackPawn
4410 ? wlPieceGC : blPieceGC, 0, 0,
4411 squareSize, squareSize, x, y, 1);
4414 XCopyPlane(xDisplay, *pieceToSolid(piece),
4415 dest, (int) piece < (int) BlackPawn
4416 ? wdPieceGC : bdPieceGC, 0, 0,
4417 squareSize, squareSize, x, y, 1);
4419 case 2: /* neutral */
4421 XCopyPlane(xDisplay, *pieceToSolid(piece),
4422 dest, (int) piece < (int) BlackPawn
4423 ? wjPieceGC : bjPieceGC, 0, 0,
4424 squareSize, squareSize, x, y, 1);
4429 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4431 int square_color, x, y;
4434 int kind, p = piece;
4436 switch (square_color) {
4438 case 2: /* neutral */
4440 if ((int)piece < (int) BlackPawn) {
4448 if ((int)piece < (int) BlackPawn) {
4456 if(appData.upsideDown && flipView) { kind ^= 2; p += p < BlackPawn ? BlackPawn : -BlackPawn; }// swap white and black pieces
4457 if(useTexture & square_color+1) {
4458 BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background
4459 XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]);
4460 XSetClipOrigin(xDisplay, wlPieceGC, x, y);
4461 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y);
4462 XSetClipMask(xDisplay, wlPieceGC, None);
4463 XSetClipOrigin(xDisplay, wlPieceGC, 0, 0);
4465 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4466 dest, wlPieceGC, 0, 0,
4467 squareSize, squareSize, x, y);
4470 typedef void (*DrawFunc)();
4472 DrawFunc ChooseDrawFunc()
4474 if (appData.monoMode) {
4475 if (DefaultDepth(xDisplay, xScreen) == 1) {
4476 return monoDrawPiece_1bit;
4478 return monoDrawPiece;
4482 return colorDrawPieceImage;
4484 return colorDrawPiece;
4488 /* [HR] determine square color depending on chess variant. */
4489 static int SquareColor(row, column)
4494 if (gameInfo.variant == VariantXiangqi) {
4495 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4497 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4499 } else if (row <= 4) {
4505 square_color = ((column + row) % 2) == 1;
4508 /* [hgm] holdings: next line makes all holdings squares light */
4509 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4511 return square_color;
4514 void DrawSquare(row, column, piece, do_flash)
4515 int row, column, do_flash;
4518 int square_color, x, y, direction, font_ascent, font_descent;
4521 XCharStruct overall;
4525 /* Calculate delay in milliseconds (2-delays per complete flash) */
4526 flash_delay = 500 / appData.flashRate;
4529 x = lineGap + ((BOARD_WIDTH-1)-column) *
4530 (squareSize + lineGap);
4531 y = lineGap + row * (squareSize + lineGap);
4533 x = lineGap + column * (squareSize + lineGap);
4534 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4535 (squareSize + lineGap);
4538 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4540 square_color = SquareColor(row, column);
4542 if ( // [HGM] holdings: blank out area between board and holdings
4543 column == BOARD_LEFT-1 || column == BOARD_RGHT
4544 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4545 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4546 BlankSquare(x, y, 2, EmptySquare, xBoardWindow, 1);
4548 // [HGM] print piece counts next to holdings
4549 string[1] = NULLCHAR;
4550 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4551 string[0] = '0' + piece;
4552 XTextExtents(countFontStruct, string, 1, &direction,
4553 &font_ascent, &font_descent, &overall);
4554 if (appData.monoMode) {
4555 XDrawImageString(xDisplay, xBoardWindow, countGC,
4556 x + squareSize - overall.width - 2,
4557 y + font_ascent + 1, string, 1);
4559 XDrawString(xDisplay, xBoardWindow, countGC,
4560 x + squareSize - overall.width - 2,
4561 y + font_ascent + 1, string, 1);
4564 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4565 string[0] = '0' + piece;
4566 XTextExtents(countFontStruct, string, 1, &direction,
4567 &font_ascent, &font_descent, &overall);
4568 if (appData.monoMode) {
4569 XDrawImageString(xDisplay, xBoardWindow, countGC,
4570 x + 2, y + font_ascent + 1, string, 1);
4572 XDrawString(xDisplay, xBoardWindow, countGC,
4573 x + 2, y + font_ascent + 1, string, 1);
4577 if (piece == EmptySquare || appData.blindfold) {
4578 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4580 drawfunc = ChooseDrawFunc();
4582 if (do_flash && appData.flashCount > 0) {
4583 for (i=0; i<appData.flashCount; ++i) {
4584 drawfunc(piece, square_color, x, y, xBoardWindow);
4585 XSync(xDisplay, False);
4586 do_flash_delay(flash_delay);
4588 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4589 XSync(xDisplay, False);
4590 do_flash_delay(flash_delay);
4593 drawfunc(piece, square_color, x, y, xBoardWindow);
4597 string[1] = NULLCHAR;
4598 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4599 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4600 string[0] = 'a' + column - BOARD_LEFT;
4601 XTextExtents(coordFontStruct, string, 1, &direction,
4602 &font_ascent, &font_descent, &overall);
4603 if (appData.monoMode) {
4604 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4605 x + squareSize - overall.width - 2,
4606 y + squareSize - font_descent - 1, string, 1);
4608 XDrawString(xDisplay, xBoardWindow, coordGC,
4609 x + squareSize - overall.width - 2,
4610 y + squareSize - font_descent - 1, string, 1);
4613 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4614 string[0] = ONE + row;
4615 XTextExtents(coordFontStruct, string, 1, &direction,
4616 &font_ascent, &font_descent, &overall);
4617 if (appData.monoMode) {
4618 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4619 x + 2, y + font_ascent + 1, string, 1);
4621 XDrawString(xDisplay, xBoardWindow, coordGC,
4622 x + 2, y + font_ascent + 1, string, 1);
4625 if(!partnerUp && marker[row][column]) {
4626 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4627 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4632 /* Why is this needed on some versions of X? */
4633 void EventProc(widget, unused, event)
4638 if (!XtIsRealized(widget))
4641 switch (event->type) {
4643 if (event->xexpose.count > 0) return; /* no clipping is done */
4644 XDrawPosition(widget, True, NULL);
4645 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4646 flipView = !flipView; partnerUp = !partnerUp;
4647 XDrawPosition(widget, True, NULL);
4648 flipView = !flipView; partnerUp = !partnerUp;
4652 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
4659 void DrawPosition(fullRedraw, board)
4660 /*Boolean*/int fullRedraw;
4663 XDrawPosition(boardWidget, fullRedraw, board);
4666 /* Returns 1 if there are "too many" differences between b1 and b2
4667 (i.e. more than 1 move was made) */
4668 static int too_many_diffs(b1, b2)
4674 for (i=0; i<BOARD_HEIGHT; ++i) {
4675 for (j=0; j<BOARD_WIDTH; ++j) {
4676 if (b1[i][j] != b2[i][j]) {
4677 if (++c > 4) /* Castling causes 4 diffs */
4685 /* Matrix describing castling maneuvers */
4686 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4687 static int castling_matrix[4][5] = {
4688 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4689 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4690 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4691 { 7, 7, 4, 5, 6 } /* 0-0, black */
4694 /* Checks whether castling occurred. If it did, *rrow and *rcol
4695 are set to the destination (row,col) of the rook that moved.
4697 Returns 1 if castling occurred, 0 if not.
4699 Note: Only handles a max of 1 castling move, so be sure
4700 to call too_many_diffs() first.
4702 static int check_castle_draw(newb, oldb, rrow, rcol)
4709 /* For each type of castling... */
4710 for (i=0; i<4; ++i) {
4711 r = castling_matrix[i];
4713 /* Check the 4 squares involved in the castling move */
4715 for (j=1; j<=4; ++j) {
4716 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4723 /* All 4 changed, so it must be a castling move */
4732 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4733 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4735 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4738 void DrawSeekBackground( int left, int top, int right, int bottom )
4740 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4743 void DrawSeekText(char *buf, int x, int y)
4745 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4748 void DrawSeekDot(int x, int y, int colorNr)
4750 int square = colorNr & 0x80;
4753 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4755 XFillRectangle(xDisplay, xBoardWindow, color,
4756 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4758 XFillArc(xDisplay, xBoardWindow, color,
4759 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4762 static int damage[2][BOARD_RANKS][BOARD_FILES];
4765 * event handler for redrawing the board
4767 void XDrawPosition(w, repaint, board)
4769 /*Boolean*/int repaint;
4773 static int lastFlipView = 0;
4774 static int lastBoardValid[2] = {0, 0};
4775 static Board lastBoard[2];
4778 int nr = twoBoards*partnerUp;
4780 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4782 if (board == NULL) {
4783 if (!lastBoardValid[nr]) return;
4784 board = lastBoard[nr];
4786 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4787 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4788 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Flip View"),
4793 * It would be simpler to clear the window with XClearWindow()
4794 * but this causes a very distracting flicker.
4797 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4799 if ( lineGap && IsDrawArrowEnabled())
4800 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4801 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4803 /* If too much changes (begin observing new game, etc.), don't
4805 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4807 /* Special check for castling so we don't flash both the king
4808 and the rook (just flash the king). */
4810 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4811 /* Draw rook with NO flashing. King will be drawn flashing later */
4812 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4813 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4817 /* First pass -- Draw (newly) empty squares and repair damage.
4818 This prevents you from having a piece show up twice while it
4819 is flashing on its new square */
4820 for (i = 0; i < BOARD_HEIGHT; i++)
4821 for (j = 0; j < BOARD_WIDTH; j++)
4822 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4823 || damage[nr][i][j]) {
4824 DrawSquare(i, j, board[i][j], 0);
4825 damage[nr][i][j] = False;
4828 /* Second pass -- Draw piece(s) in new position and flash them */
4829 for (i = 0; i < BOARD_HEIGHT; i++)
4830 for (j = 0; j < BOARD_WIDTH; j++)
4831 if (board[i][j] != lastBoard[nr][i][j]) {
4832 DrawSquare(i, j, board[i][j], do_flash);
4836 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4837 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4838 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4840 for (i = 0; i < BOARD_HEIGHT; i++)
4841 for (j = 0; j < BOARD_WIDTH; j++) {
4842 DrawSquare(i, j, board[i][j], 0);
4843 damage[nr][i][j] = False;
4847 CopyBoard(lastBoard[nr], board);
4848 lastBoardValid[nr] = 1;
4849 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4850 lastFlipView = flipView;
4852 /* Draw highlights */
4853 if (pm1X >= 0 && pm1Y >= 0) {
4854 drawHighlight(pm1X, pm1Y, prelineGC);
4856 if (pm2X >= 0 && pm2Y >= 0) {
4857 drawHighlight(pm2X, pm2Y, prelineGC);
4859 if (hi1X >= 0 && hi1Y >= 0) {
4860 drawHighlight(hi1X, hi1Y, highlineGC);
4862 if (hi2X >= 0 && hi2Y >= 0) {
4863 drawHighlight(hi2X, hi2Y, highlineGC);
4865 DrawArrowHighlight(hi1X, hi1Y, hi2X, hi2Y);
4867 /* If piece being dragged around board, must redraw that too */
4870 XSync(xDisplay, False);
4875 * event handler for redrawing the board
4877 void DrawPositionProc(w, event, prms, nprms)
4883 XDrawPosition(w, True, NULL);
4888 * event handler for parsing user moves
4890 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4891 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4892 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4893 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4894 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4895 // and at the end FinishMove() to perform the move after optional promotion popups.
4896 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4897 void HandleUserMove(w, event, prms, nprms)
4903 if (w != boardWidget || errorExitStatus != -1) return;
4904 if(nprms) shiftKey = !strcmp(prms[0], "1");
4907 if (event->type == ButtonPress) {
4908 XtPopdown(promotionShell);
4909 XtDestroyWidget(promotionShell);
4910 promotionUp = False;
4918 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4919 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4920 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4923 void AnimateUserMove (Widget w, XEvent * event,
4924 String * params, Cardinal * nParams)
4926 if(!PromoScroll(event->xmotion.x, event->xmotion.y))
4927 DragPieceMove(event->xmotion.x, event->xmotion.y);
4930 void HandlePV (Widget w, XEvent * event,
4931 String * params, Cardinal * nParams)
4932 { // [HGM] pv: walk PV
4933 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4936 static int savedIndex; /* gross that this is global */
4938 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
4941 XawTextPosition index, dummy;
4944 XawTextGetSelectionPos(w, &index, &dummy);
4945 XtSetArg(arg, XtNstring, &val);
4946 XtGetValues(w, &arg, 1);
4947 ReplaceComment(savedIndex, val);
4948 if(savedIndex != currentMove) ToNrEvent(savedIndex);
4949 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
4952 void EditCommentPopUp(index, title, text)
4957 if (text == NULL) text = "";
4958 NewCommentPopup(title, text, index);
4961 void ICSInputBoxPopUp()
4966 extern Option boxOptions[];
4968 void ICSInputSendText()
4975 edit = boxOptions[0].handle;
4977 XtSetArg(args[j], XtNstring, &val); j++;
4978 XtGetValues(edit, args, j);
4980 SendMultiLineToICS(val);
4981 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4982 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4985 void ICSInputBoxPopDown()
4990 void CommentPopUp(title, text)
4993 savedIndex = currentMove; // [HGM] vari
4994 NewCommentPopup(title, text, currentMove);
4997 void CommentPopDown()
5002 void FileNamePopUp(label, def, filter, proc, openMode)
5009 fileProc = proc; /* I can't see a way not */
5010 fileOpenMode = openMode; /* to use globals here */
5011 { // [HGM] use file-selector dialog stolen from Ghostview
5013 int index; // this is not supported yet
5015 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5016 (def[0] ? def : NULL), filter, openMode, NULL, &name))
5017 (void) (*fileProc)(f, index=0, name);
5021 void FileNamePopDown()
5023 if (!filenameUp) return;
5024 XtPopdown(fileNameShell);
5025 XtDestroyWidget(fileNameShell);
5030 void FileNameCallback(w, client_data, call_data)
5032 XtPointer client_data, call_data;
5037 XtSetArg(args[0], XtNlabel, &name);
5038 XtGetValues(w, args, 1);
5040 if (strcmp(name, _("cancel")) == 0) {
5045 FileNameAction(w, NULL, NULL, NULL);
5048 void FileNameAction(w, event, prms, nprms)
5060 name = XawDialogGetValueString(w = XtParent(w));
5062 if ((name != NULL) && (*name != NULLCHAR)) {
5063 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
5064 XtPopdown(w = XtParent(XtParent(w)));
5068 p = strrchr(buf, ' ');
5075 fullname = ExpandPathName(buf);
5077 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5080 f = fopen(fullname, fileOpenMode);
5082 DisplayError(_("Failed to open file"), errno);
5084 (void) (*fileProc)(f, index, buf);
5091 XtPopdown(w = XtParent(XtParent(w)));
5097 void PromotionPopUp()
5100 Widget dialog, layout;
5102 Dimension bw_width, pw_width;
5106 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5107 XtGetValues(boardWidget, args, j);
5110 XtSetArg(args[j], XtNresizable, True); j++;
5111 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5113 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5114 shellWidget, args, j);
5116 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5117 layoutArgs, XtNumber(layoutArgs));
5120 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5121 XtSetArg(args[j], XtNborderWidth, 0); j++;
5122 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5125 if(gameInfo.variant != VariantShogi) {
5126 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) {
5127 XawDialogAddButton(dialog, _("Warlord"), PromotionCallback,
5128 (XtPointer) dialog);
5129 XawDialogAddButton(dialog, _("General"), PromotionCallback,
5130 (XtPointer) dialog);
5131 XawDialogAddButton(dialog, _("Lieutenant"), PromotionCallback,
5132 (XtPointer) dialog);
5133 XawDialogAddButton(dialog, _("Captain"), PromotionCallback,
5134 (XtPointer) dialog);
5136 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5137 (XtPointer) dialog);
5138 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5139 (XtPointer) dialog);
5140 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5141 (XtPointer) dialog);
5142 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5143 (XtPointer) dialog);
5145 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5146 gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
5147 gameInfo.variant == VariantGiveaway) {
5148 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5149 (XtPointer) dialog);
5151 if(gameInfo.variant == VariantCapablanca ||
5152 gameInfo.variant == VariantGothic ||
5153 gameInfo.variant == VariantCapaRandom) {
5154 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5155 (XtPointer) dialog);
5156 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5157 (XtPointer) dialog);
5159 } else // [HGM] shogi
5161 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5162 (XtPointer) dialog);
5163 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5164 (XtPointer) dialog);
5166 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5167 (XtPointer) dialog);
5169 XtRealizeWidget(promotionShell);
5170 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5173 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5174 XtGetValues(promotionShell, args, j);
5176 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5177 lineGap + squareSize/3 +
5178 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5179 0 : 6*(squareSize + lineGap)), &x, &y);
5182 XtSetArg(args[j], XtNx, x); j++;
5183 XtSetArg(args[j], XtNy, y); j++;
5184 XtSetValues(promotionShell, args, j);
5186 XtPopup(promotionShell, XtGrabNone);
5191 void PromotionPopDown()
5193 if (!promotionUp) return;
5194 XtPopdown(promotionShell);
5195 XtDestroyWidget(promotionShell);
5196 promotionUp = False;
5199 void PromotionCallback(w, client_data, call_data)
5201 XtPointer client_data, call_data;
5207 XtSetArg(args[0], XtNlabel, &name);
5208 XtGetValues(w, args, 1);
5212 if (fromX == -1) return;
5214 if (strcmp(name, _("cancel")) == 0) {
5218 } else if (strcmp(name, _("Knight")) == 0) {
5220 } else if (strcmp(name, _("Promote")) == 0) {
5222 } else if (strcmp(name, _("Defer")) == 0) {
5225 promoChar = ToLower(name[0]);
5228 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5230 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5231 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5236 void ErrorCallback(w, client_data, call_data)
5238 XtPointer client_data, call_data;
5241 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5243 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5249 if (!errorUp) return;
5251 XtPopdown(errorShell);
5252 XtDestroyWidget(errorShell);
5253 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5256 void ErrorPopUp(title, label, modal)
5257 char *title, *label;
5261 Widget dialog, layout;
5265 Dimension bw_width, pw_width;
5266 Dimension pw_height;
5270 XtSetArg(args[i], XtNresizable, True); i++;
5271 XtSetArg(args[i], XtNtitle, title); i++;
5273 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5274 shellWidget, args, i);
5276 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5277 layoutArgs, XtNumber(layoutArgs));
5280 XtSetArg(args[i], XtNlabel, label); i++;
5281 XtSetArg(args[i], XtNborderWidth, 0); i++;
5282 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5285 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5287 XtRealizeWidget(errorShell);
5288 CatchDeleteWindow(errorShell, "ErrorPopDown");
5291 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5292 XtGetValues(boardWidget, args, i);
5294 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5295 XtSetArg(args[i], XtNheight, &pw_height); i++;
5296 XtGetValues(errorShell, args, i);
5299 /* This code seems to tickle an X bug if it is executed too soon
5300 after xboard starts up. The coordinates get transformed as if
5301 the main window was positioned at (0, 0).
5303 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5304 0 - pw_height + squareSize / 3, &x, &y);
5306 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5307 RootWindowOfScreen(XtScreen(boardWidget)),
5308 (bw_width - pw_width) / 2,
5309 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5313 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5316 XtSetArg(args[i], XtNx, x); i++;
5317 XtSetArg(args[i], XtNy, y); i++;
5318 XtSetValues(errorShell, args, i);
5321 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5324 /* Disable all user input other than deleting the window */
5325 static int frozen = 0;
5329 /* Grab by a widget that doesn't accept input */
5330 XtAddGrab(messageWidget, TRUE, FALSE);
5334 /* Undo a FreezeUI */
5337 if (!frozen) return;
5338 XtRemoveGrab(messageWidget);
5342 char *ModeToWidgetName(mode)
5346 case BeginningOfGame:
5347 if (appData.icsActive)
5348 return "menuMode.ICS Client";
5349 else if (appData.noChessProgram ||
5350 *appData.cmailGameName != NULLCHAR)
5351 return "menuMode.Edit Game";
5353 return "menuMode.Machine Black";
5354 case MachinePlaysBlack:
5355 return "menuMode.Machine Black";
5356 case MachinePlaysWhite:
5357 return "menuMode.Machine White";
5359 return "menuMode.Analysis Mode";
5361 return "menuMode.Analyze File";
5362 case TwoMachinesPlay:
5363 return "menuMode.Two Machines";
5365 return "menuMode.Edit Game";
5366 case PlayFromGameFile:
5367 return "menuFile.Load Game";
5369 return "menuMode.Edit Position";
5371 return "menuMode.Training";
5372 case IcsPlayingWhite:
5373 case IcsPlayingBlack:
5377 return "menuMode.ICS Client";
5384 void ModeHighlight()
5387 static int oldPausing = FALSE;
5388 static GameMode oldmode = (GameMode) -1;
5391 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5393 if (pausing != oldPausing) {
5394 oldPausing = pausing;
5396 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5398 XtSetArg(args[0], XtNleftBitmap, None);
5400 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5403 if (appData.showButtonBar) {
5404 /* Always toggle, don't set. Previous code messes up when
5405 invoked while the button is pressed, as releasing it
5406 toggles the state again. */
5409 XtSetArg(args[0], XtNbackground, &oldbg);
5410 XtSetArg(args[1], XtNforeground, &oldfg);
5411 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5413 XtSetArg(args[0], XtNbackground, oldfg);
5414 XtSetArg(args[1], XtNforeground, oldbg);
5416 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5420 wname = ModeToWidgetName(oldmode);
5421 if (wname != NULL) {
5422 XtSetArg(args[0], XtNleftBitmap, None);
5423 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5425 wname = ModeToWidgetName(gameMode);
5426 if (wname != NULL) {
5427 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5428 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5431 XtSetArg(args[0], XtNleftBitmap, matchMode && matchGame < appData.matchGames ? xMarkPixmap : None);
5432 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Machine Match"), args, 1);
5434 /* Maybe all the enables should be handled here, not just this one */
5435 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5436 gameMode == Training || gameMode == PlayFromGameFile);
5441 * Button/menu procedures
5443 void ResetProc(w, event, prms, nprms)
5452 int LoadGamePopUp(f, gameNumber, title)
5457 cmailMsgLoaded = FALSE;
5458 if (gameNumber == 0) {
5459 int error = GameListBuild(f);
5461 DisplayError(_("Cannot build game list"), error);
5462 } else if (!ListEmpty(&gameList) &&
5463 ((ListGame *) gameList.tailPred)->number > 1) {
5464 GameListPopUp(f, title);
5470 return LoadGame(f, gameNumber, title, FALSE);
5473 void LoadGameProc(w, event, prms, nprms)
5479 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5482 FileNamePopUp(_("Load game file name?"), "", ".pgn .game", LoadGamePopUp, "rb");
5485 void LoadNextGameProc(w, event, prms, nprms)
5494 void LoadPrevGameProc(w, event, prms, nprms)
5503 void ReloadGameProc(w, event, prms, nprms)
5512 void LoadNextPositionProc(w, event, prms, nprms)
5521 void LoadPrevPositionProc(w, event, prms, nprms)
5530 void ReloadPositionProc(w, event, prms, nprms)
5539 void LoadPositionProc(w, event, prms, nprms)
5545 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5548 FileNamePopUp(_("Load position file name?"), "", ".fen .epd .pos", LoadPosition, "rb");
5551 void SaveGameProc(w, event, prms, nprms)
5557 FileNamePopUp(_("Save game file name?"),
5558 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5559 appData.oldSaveStyle ? ".game" : ".pgn",
5563 void SavePositionProc(w, event, prms, nprms)
5569 FileNamePopUp(_("Save position file name?"),
5570 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5571 appData.oldSaveStyle ? ".pos" : ".fen",
5575 void ReloadCmailMsgProc(w, event, prms, nprms)
5581 ReloadCmailMsgEvent(FALSE);
5584 void MailMoveProc(w, event, prms, nprms)
5593 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5594 char *selected_fen_position=NULL;
5597 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5598 Atom *type_return, XtPointer *value_return,
5599 unsigned long *length_return, int *format_return)
5601 char *selection_tmp;
5603 if (!selected_fen_position) return False; /* should never happen */
5604 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5605 /* note: since no XtSelectionDoneProc was registered, Xt will
5606 * automatically call XtFree on the value returned. So have to
5607 * make a copy of it allocated with XtMalloc */
5608 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5609 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
5611 *value_return=selection_tmp;
5612 *length_return=strlen(selection_tmp);
5613 *type_return=*target;
5614 *format_return = 8; /* bits per byte */
5616 } else if (*target == XA_TARGETS(xDisplay)) {
5617 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5618 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5619 targets_tmp[1] = XA_STRING;
5620 *value_return = targets_tmp;
5621 *type_return = XA_ATOM;
5623 *format_return = 8 * sizeof(Atom);
5624 if (*format_return > 32) {
5625 *length_return *= *format_return / 32;
5626 *format_return = 32;
5634 /* note: when called from menu all parameters are NULL, so no clue what the
5635 * Widget which was clicked on was, or what the click event was
5637 void CopyPositionProc(w, event, prms, nprms)
5644 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5645 * have a notion of a position that is selected but not copied.
5646 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5648 if(gameMode == EditPosition) EditPositionDone(TRUE);
5649 if (selected_fen_position) free(selected_fen_position);
5650 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5651 if (!selected_fen_position) return;
5652 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5654 SendPositionSelection,
5655 NULL/* lose_ownership_proc */ ,
5656 NULL/* transfer_done_proc */);
5657 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5659 SendPositionSelection,
5660 NULL/* lose_ownership_proc */ ,
5661 NULL/* transfer_done_proc */);
5664 /* function called when the data to Paste is ready */
5666 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5667 Atom *type, XtPointer value, unsigned long *len, int *format)
5670 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5671 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5672 EditPositionPasteFEN(fenstr);
5676 /* called when Paste Position button is pressed,
5677 * all parameters will be NULL */
5678 void PastePositionProc(w, event, prms, nprms)
5684 XtGetSelectionValue(menuBarWidget,
5685 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5686 /* (XtSelectionCallbackProc) */ PastePositionCB,
5687 NULL, /* client_data passed to PastePositionCB */
5689 /* better to use the time field from the event that triggered the
5690 * call to this function, but that isn't trivial to get
5698 SendGameSelection(Widget w, Atom *selection, Atom *target,
5699 Atom *type_return, XtPointer *value_return,
5700 unsigned long *length_return, int *format_return)
5702 char *selection_tmp;
5704 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5705 FILE* f = fopen(gameCopyFilename, "r");
5708 if (f == NULL) return False;
5712 selection_tmp = XtMalloc(len + 1);
5713 count = fread(selection_tmp, 1, len, f);
5716 XtFree(selection_tmp);
5719 selection_tmp[len] = NULLCHAR;
5720 *value_return = selection_tmp;
5721 *length_return = len;
5722 *type_return = *target;
5723 *format_return = 8; /* bits per byte */
5725 } else if (*target == XA_TARGETS(xDisplay)) {
5726 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5727 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5728 targets_tmp[1] = XA_STRING;
5729 *value_return = targets_tmp;
5730 *type_return = XA_ATOM;
5732 *format_return = 8 * sizeof(Atom);
5733 if (*format_return > 32) {
5734 *length_return *= *format_return / 32;
5735 *format_return = 32;
5743 void CopySomething()
5746 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5747 * have a notion of a game that is selected but not copied.
5748 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5750 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5753 NULL/* lose_ownership_proc */ ,
5754 NULL/* transfer_done_proc */);
5755 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5758 NULL/* lose_ownership_proc */ ,
5759 NULL/* transfer_done_proc */);
5762 /* note: when called from menu all parameters are NULL, so no clue what the
5763 * Widget which was clicked on was, or what the click event was
5765 void CopyGameProc(w, event, prms, nprms)
5773 ret = SaveGameToFile(gameCopyFilename, FALSE);
5779 void CopyGameListProc(w, event, prms, nprms)
5785 if(!SaveGameListAsText(fopen(gameCopyFilename, "w"))) return;
5789 /* function called when the data to Paste is ready */
5791 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5792 Atom *type, XtPointer value, unsigned long *len, int *format)
5795 if (value == NULL || *len == 0) {
5796 return; /* nothing had been selected to copy */
5798 f = fopen(gamePasteFilename, "w");
5800 DisplayError(_("Can't open temp file"), errno);
5803 fwrite(value, 1, *len, f);
5806 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5809 /* called when Paste Game button is pressed,
5810 * all parameters will be NULL */
5811 void PasteGameProc(w, event, prms, nprms)
5817 XtGetSelectionValue(menuBarWidget,
5818 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5819 /* (XtSelectionCallbackProc) */ PasteGameCB,
5820 NULL, /* client_data passed to PasteGameCB */
5822 /* better to use the time field from the event that triggered the
5823 * call to this function, but that isn't trivial to get
5833 SaveGameProc(NULL, NULL, NULL, NULL);
5837 void QuitProc(w, event, prms, nprms)
5846 void PauseProc(w, event, prms, nprms)
5856 void MachineBlackProc(w, event, prms, nprms)
5862 MachineBlackEvent();
5865 void MachineWhiteProc(w, event, prms, nprms)
5871 MachineWhiteEvent();
5874 void AnalyzeModeProc(w, event, prms, nprms)
5882 if (!first.analysisSupport) {
5883 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5884 DisplayError(buf, 0);
5887 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5888 if (appData.icsActive) {
5889 if (gameMode != IcsObserving) {
5890 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
5891 DisplayError(buf, 0);
5893 if (appData.icsEngineAnalyze) {
5894 if (appData.debugMode)
5895 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5901 /* if enable, use want disable icsEngineAnalyze */
5902 if (appData.icsEngineAnalyze) {
5907 appData.icsEngineAnalyze = TRUE;
5908 if (appData.debugMode)
5909 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5911 #ifndef OPTIONSDIALOG
5912 if (!appData.showThinking)
5913 ShowThinkingProc(w,event,prms,nprms);
5919 void AnalyzeFileProc(w, event, prms, nprms)
5925 if (!first.analysisSupport) {
5927 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5928 DisplayError(buf, 0);
5932 #ifndef OPTIONSDIALOG
5933 if (!appData.showThinking)
5934 ShowThinkingProc(w,event,prms,nprms);
5937 FileNamePopUp(_("File to analyze"), "", ".pgn .game", LoadGamePopUp, "rb");
5938 AnalysisPeriodicEvent(1);
5941 void TwoMachinesProc(w, event, prms, nprms)
5950 void MatchProc(w, event, prms, nprms)
5959 void IcsClientProc(w, event, prms, nprms)
5968 void EditGameProc(w, event, prms, nprms)
5977 void EditPositionProc(w, event, prms, nprms)
5983 EditPositionEvent();
5986 void TrainingProc(w, event, prms, nprms)
5995 void EditCommentProc(w, event, prms, nprms)
6003 if (PopDown(1)) { // popdown succesful
6005 XtSetArg(args[j], XtNleftBitmap, None); j++;
6006 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"), args, j);
6007 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"), args, j);
6008 } else // was not up
6012 void IcsInputBoxProc(w, event, prms, nprms)
6018 if (!PopDown(4)) ICSInputBoxPopUp();
6021 void AcceptProc(w, event, prms, nprms)
6030 void DeclineProc(w, event, prms, nprms)
6039 void RematchProc(w, event, prms, nprms)
6048 void CallFlagProc(w, event, prms, nprms)
6057 void DrawProc(w, event, prms, nprms)
6066 void AbortProc(w, event, prms, nprms)
6075 void AdjournProc(w, event, prms, nprms)
6084 void ResignProc(w, event, prms, nprms)
6093 void AdjuWhiteProc(w, event, prms, nprms)
6099 UserAdjudicationEvent(+1);
6102 void AdjuBlackProc(w, event, prms, nprms)
6108 UserAdjudicationEvent(-1);
6111 void AdjuDrawProc(w, event, prms, nprms)
6117 UserAdjudicationEvent(0);
6120 void EnterKeyProc(w, event, prms, nprms)
6126 if (shellUp[4] == True)
6130 void UpKeyProc(w, event, prms, nprms)
6135 { // [HGM] input: let up-arrow recall previous line from history
6142 if (!shellUp[4]) return;
6143 edit = boxOptions[0].handle;
6145 XtSetArg(args[j], XtNstring, &val); j++;
6146 XtGetValues(edit, args, j);
6147 val = PrevInHistory(val);
6148 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6149 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6151 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6152 XawTextReplace(edit, 0, 0, &t);
6153 XawTextSetInsertionPoint(edit, 9999);
6157 void DownKeyProc(w, event, prms, nprms)
6162 { // [HGM] input: let down-arrow recall next line from history
6167 if (!shellUp[4]) return;
6168 edit = boxOptions[0].handle;
6169 val = NextInHistory();
6170 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6171 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6173 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6174 XawTextReplace(edit, 0, 0, &t);
6175 XawTextSetInsertionPoint(edit, 9999);
6179 void StopObservingProc(w, event, prms, nprms)
6185 StopObservingEvent();
6188 void StopExaminingProc(w, event, prms, nprms)
6194 StopExaminingEvent();
6197 void UploadProc(w, event, prms, nprms)
6207 void ForwardProc(w, event, prms, nprms)
6217 void BackwardProc(w, event, prms, nprms)
6226 void ToStartProc(w, event, prms, nprms)
6235 void ToEndProc(w, event, prms, nprms)
6244 void RevertProc(w, event, prms, nprms)
6253 void AnnotateProc(w, event, prms, nprms)
6262 void TruncateGameProc(w, event, prms, nprms)
6268 TruncateGameEvent();
6270 void RetractMoveProc(w, event, prms, nprms)
6279 void MoveNowProc(w, event, prms, nprms)
6288 void FlipViewProc(w, event, prms, nprms)
6294 flipView = !flipView;
6295 DrawPosition(True, NULL);
6298 void PonderNextMoveProc(w, event, prms, nprms)
6306 PonderNextMoveEvent(!appData.ponderNextMove);
6307 #ifndef OPTIONSDIALOG
6308 if (appData.ponderNextMove) {
6309 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6311 XtSetArg(args[0], XtNleftBitmap, None);
6313 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6318 #ifndef OPTIONSDIALOG
6319 void AlwaysQueenProc(w, event, prms, nprms)
6327 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6329 if (appData.alwaysPromoteToQueen) {
6330 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6332 XtSetArg(args[0], XtNleftBitmap, None);
6334 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6338 void AnimateDraggingProc(w, event, prms, nprms)
6346 appData.animateDragging = !appData.animateDragging;
6348 if (appData.animateDragging) {
6349 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6352 XtSetArg(args[0], XtNleftBitmap, None);
6354 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6358 void AnimateMovingProc(w, event, prms, nprms)
6366 appData.animate = !appData.animate;
6368 if (appData.animate) {
6369 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6372 XtSetArg(args[0], XtNleftBitmap, None);
6374 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6378 void AutoflagProc(w, event, prms, nprms)
6386 appData.autoCallFlag = !appData.autoCallFlag;
6388 if (appData.autoCallFlag) {
6389 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6391 XtSetArg(args[0], XtNleftBitmap, None);
6393 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6397 void AutoflipProc(w, event, prms, nprms)
6405 appData.autoFlipView = !appData.autoFlipView;
6407 if (appData.autoFlipView) {
6408 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6410 XtSetArg(args[0], XtNleftBitmap, None);
6412 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6416 void BlindfoldProc(w, event, prms, nprms)
6424 appData.blindfold = !appData.blindfold;
6426 if (appData.blindfold) {
6427 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6429 XtSetArg(args[0], XtNleftBitmap, None);
6431 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6434 DrawPosition(True, NULL);
6437 void TestLegalityProc(w, event, prms, nprms)
6445 appData.testLegality = !appData.testLegality;
6447 if (appData.testLegality) {
6448 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6450 XtSetArg(args[0], XtNleftBitmap, None);
6452 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6457 void FlashMovesProc(w, event, prms, nprms)
6465 if (appData.flashCount == 0) {
6466 appData.flashCount = 3;
6468 appData.flashCount = -appData.flashCount;
6471 if (appData.flashCount > 0) {
6472 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6474 XtSetArg(args[0], XtNleftBitmap, None);
6476 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6481 void HighlightDraggingProc(w, event, prms, nprms)
6489 appData.highlightDragging = !appData.highlightDragging;
6491 if (appData.highlightDragging) {
6492 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6494 XtSetArg(args[0], XtNleftBitmap, None);
6496 XtSetValues(XtNameToWidget(menuBarWidget,
6497 "menuOptions.Highlight Dragging"), args, 1);
6501 void HighlightLastMoveProc(w, event, prms, nprms)
6509 appData.highlightLastMove = !appData.highlightLastMove;
6511 if (appData.highlightLastMove) {
6512 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6514 XtSetArg(args[0], XtNleftBitmap, None);
6516 XtSetValues(XtNameToWidget(menuBarWidget,
6517 "menuOptions.Highlight Last Move"), args, 1);
6520 void HighlightArrowProc(w, event, prms, nprms)
6528 appData.highlightMoveWithArrow = !appData.highlightMoveWithArrow;
6530 if (appData.highlightMoveWithArrow) {
6531 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6533 XtSetArg(args[0], XtNleftBitmap, None);
6535 XtSetValues(XtNameToWidget(menuBarWidget,
6536 "menuOptions.Arrow"), args, 1);
6540 void IcsAlarmProc(w, event, prms, nprms)
6548 appData.icsAlarm = !appData.icsAlarm;
6550 if (appData.icsAlarm) {
6551 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6553 XtSetArg(args[0], XtNleftBitmap, None);
6555 XtSetValues(XtNameToWidget(menuBarWidget,
6556 "menuOptions.ICS Alarm"), args, 1);
6560 void MoveSoundProc(w, event, prms, nprms)
6568 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6570 if (appData.ringBellAfterMoves) {
6571 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6573 XtSetArg(args[0], XtNleftBitmap, None);
6575 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6579 void OneClickProc(w, event, prms, nprms)
6587 appData.oneClick = !appData.oneClick;
6589 if (appData.oneClick) {
6590 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6592 XtSetArg(args[0], XtNleftBitmap, None);
6594 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.OneClick"),
6598 void PeriodicUpdatesProc(w, event, prms, nprms)
6606 PeriodicUpdatesEvent(!appData.periodicUpdates);
6608 if (appData.periodicUpdates) {
6609 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6611 XtSetArg(args[0], XtNleftBitmap, None);
6613 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6617 void PopupExitMessageProc(w, event, prms, nprms)
6625 appData.popupExitMessage = !appData.popupExitMessage;
6627 if (appData.popupExitMessage) {
6628 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6630 XtSetArg(args[0], XtNleftBitmap, None);
6632 XtSetValues(XtNameToWidget(menuBarWidget,
6633 "menuOptions.Popup Exit Message"), args, 1);
6636 void PopupMoveErrorsProc(w, event, prms, nprms)
6644 appData.popupMoveErrors = !appData.popupMoveErrors;
6646 if (appData.popupMoveErrors) {
6647 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6649 XtSetArg(args[0], XtNleftBitmap, None);
6651 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6656 void PremoveProc(w, event, prms, nprms)
6664 appData.premove = !appData.premove;
6666 if (appData.premove) {
6667 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6669 XtSetArg(args[0], XtNleftBitmap, None);
6671 XtSetValues(XtNameToWidget(menuBarWidget,
6672 "menuOptions.Premove"), args, 1);
6676 void ShowCoordsProc(w, event, prms, nprms)
6684 appData.showCoords = !appData.showCoords;
6686 if (appData.showCoords) {
6687 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6689 XtSetArg(args[0], XtNleftBitmap, None);
6691 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6694 DrawPosition(True, NULL);
6697 void ShowThinkingProc(w, event, prms, nprms)
6703 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6704 ShowThinkingEvent();
6707 void HideThinkingProc(w, event, prms, nprms)
6715 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6716 ShowThinkingEvent();
6718 if (appData.hideThinkingFromHuman) {
6719 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6721 XtSetArg(args[0], XtNleftBitmap, None);
6723 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6728 void SaveOnExitProc(w, event, prms, nprms)
6736 saveSettingsOnExit = !saveSettingsOnExit;
6738 if (saveSettingsOnExit) {
6739 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6741 XtSetArg(args[0], XtNleftBitmap, None);
6743 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6747 void SaveSettingsProc(w, event, prms, nprms)
6753 SaveSettings(settingsFileName);
6756 void InfoProc(w, event, prms, nprms)
6763 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6768 void ManProc(w, event, prms, nprms)
6776 if (nprms && *nprms > 0)
6780 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6784 void HintProc(w, event, prms, nprms)
6793 void BookProc(w, event, prms, nprms)
6802 void AboutProc(w, event, prms, nprms)
6810 char *zippy = " (with Zippy code)";
6814 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6815 programVersion, zippy,
6816 "Copyright 1991 Digital Equipment Corporation",
6817 "Enhancements Copyright 1992-2009 Free Software Foundation",
6818 "Enhancements Copyright 2005 Alessandro Scotti",
6819 PACKAGE, " is free software and carries NO WARRANTY;",
6820 "see the file COPYING for more information.");
6821 ErrorPopUp(_("About XBoard"), buf, FALSE);
6824 void DebugProc(w, event, prms, nprms)
6830 appData.debugMode = !appData.debugMode;
6833 void AboutGameProc(w, event, prms, nprms)
6842 void NothingProc(w, event, prms, nprms)
6851 void Iconify(w, event, prms, nprms)
6860 XtSetArg(args[0], XtNiconic, True);
6861 XtSetValues(shellWidget, args, 1);
6864 void DisplayMessage(message, extMessage)
6865 char *message, *extMessage;
6867 /* display a message in the message widget */
6876 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
6881 message = extMessage;
6885 safeStrCpy(lastMsg, message, MSG_SIZ); // [HGM] make available
6887 /* need to test if messageWidget already exists, since this function
6888 can also be called during the startup, if for example a Xresource
6889 is not set up correctly */
6892 XtSetArg(arg, XtNlabel, message);
6893 XtSetValues(messageWidget, &arg, 1);
6899 void DisplayTitle(text)
6904 char title[MSG_SIZ];
6907 if (text == NULL) text = "";
6909 if (appData.titleInWindow) {
6911 XtSetArg(args[i], XtNlabel, text); i++;
6912 XtSetValues(titleWidget, args, i);
6915 if (*text != NULLCHAR) {
6916 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
6917 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
6918 } else if (appData.icsActive) {
6919 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
6920 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
6921 } else if (appData.cmailGameName[0] != NULLCHAR) {
6922 snprintf(icon, sizeof(icon), "%s", "CMail");
6923 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
6925 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
6926 } else if (gameInfo.variant == VariantGothic) {
6927 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6928 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
6931 } else if (gameInfo.variant == VariantFalcon) {
6932 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6933 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
6935 } else if (appData.noChessProgram) {
6936 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6937 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
6939 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
6940 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
6943 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
6944 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
6945 XtSetValues(shellWidget, args, i);
6946 XSync(xDisplay, False);
6951 DisplayError(message, error)
6958 if (appData.debugMode || appData.matchMode) {
6959 fprintf(stderr, "%s: %s\n", programName, message);
6962 if (appData.debugMode || appData.matchMode) {
6963 fprintf(stderr, "%s: %s: %s\n",
6964 programName, message, strerror(error));
6966 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6969 ErrorPopUp(_("Error"), message, FALSE);
6973 void DisplayMoveError(message)
6978 DrawPosition(FALSE, NULL);
6979 if (appData.debugMode || appData.matchMode) {
6980 fprintf(stderr, "%s: %s\n", programName, message);
6982 if (appData.popupMoveErrors) {
6983 ErrorPopUp(_("Error"), message, FALSE);
6985 DisplayMessage(message, "");
6990 void DisplayFatalError(message, error, status)
6996 errorExitStatus = status;
6998 fprintf(stderr, "%s: %s\n", programName, message);
7000 fprintf(stderr, "%s: %s: %s\n",
7001 programName, message, strerror(error));
7002 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7005 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7006 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7012 void DisplayInformation(message)
7016 ErrorPopUp(_("Information"), message, TRUE);
7019 void DisplayNote(message)
7023 ErrorPopUp(_("Note"), message, FALSE);
7027 NullXErrorCheck(dpy, error_event)
7029 XErrorEvent *error_event;
7034 void DisplayIcsInteractionTitle(message)
7037 if (oldICSInteractionTitle == NULL) {
7038 /* Magic to find the old window title, adapted from vim */
7039 char *wina = getenv("WINDOWID");
7041 Window win = (Window) atoi(wina);
7042 Window root, parent, *children;
7043 unsigned int nchildren;
7044 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7046 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7047 if (!XQueryTree(xDisplay, win, &root, &parent,
7048 &children, &nchildren)) break;
7049 if (children) XFree((void *)children);
7050 if (parent == root || parent == 0) break;
7053 XSetErrorHandler(oldHandler);
7055 if (oldICSInteractionTitle == NULL) {
7056 oldICSInteractionTitle = "xterm";
7059 printf("\033]0;%s\007", message);
7063 char pendingReplyPrefix[MSG_SIZ];
7064 ProcRef pendingReplyPR;
7066 void AskQuestionProc(w, event, prms, nprms)
7073 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7077 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7080 void AskQuestionPopDown()
7082 if (!askQuestionUp) return;
7083 XtPopdown(askQuestionShell);
7084 XtDestroyWidget(askQuestionShell);
7085 askQuestionUp = False;
7088 void AskQuestionReplyAction(w, event, prms, nprms)
7098 reply = XawDialogGetValueString(w = XtParent(w));
7099 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
7100 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
7101 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
7102 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
7103 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7104 AskQuestionPopDown();
7106 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7109 void AskQuestionCallback(w, client_data, call_data)
7111 XtPointer client_data, call_data;
7116 XtSetArg(args[0], XtNlabel, &name);
7117 XtGetValues(w, args, 1);
7119 if (strcmp(name, _("cancel")) == 0) {
7120 AskQuestionPopDown();
7122 AskQuestionReplyAction(w, NULL, NULL, NULL);
7126 void AskQuestion(title, question, replyPrefix, pr)
7127 char *title, *question, *replyPrefix;
7131 Widget popup, layout, dialog, edit;
7137 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
7138 pendingReplyPR = pr;
7141 XtSetArg(args[i], XtNresizable, True); i++;
7142 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7143 askQuestionShell = popup =
7144 XtCreatePopupShell(title, transientShellWidgetClass,
7145 shellWidget, args, i);
7148 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7149 layoutArgs, XtNumber(layoutArgs));
7152 XtSetArg(args[i], XtNlabel, question); i++;
7153 XtSetArg(args[i], XtNvalue, ""); i++;
7154 XtSetArg(args[i], XtNborderWidth, 0); i++;
7155 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7158 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7159 (XtPointer) dialog);
7160 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7161 (XtPointer) dialog);
7163 XtRealizeWidget(popup);
7164 CatchDeleteWindow(popup, "AskQuestionPopDown");
7166 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7167 &x, &y, &win_x, &win_y, &mask);
7169 XtSetArg(args[0], XtNx, x - 10);
7170 XtSetArg(args[1], XtNy, y - 30);
7171 XtSetValues(popup, args, 2);
7173 XtPopup(popup, XtGrabExclusive);
7174 askQuestionUp = True;
7176 edit = XtNameToWidget(dialog, "*value");
7177 XtSetKeyboardFocus(popup, edit);
7185 if (*name == NULLCHAR) {
7187 } else if (strcmp(name, "$") == 0) {
7188 putc(BELLCHAR, stderr);
7191 char *prefix = "", *sep = "";
7192 if(!strchr(name, '/')) { prefix = appData.soundDirectory; sep = "/"; }
7193 snprintf(buf, sizeof(buf), "%s '%s%s%s' &", appData.soundProgram, prefix, sep, name);
7201 PlaySound(appData.soundMove);
7207 PlaySound(appData.soundIcsWin);
7213 PlaySound(appData.soundIcsLoss);
7219 PlaySound(appData.soundIcsDraw);
7223 PlayIcsUnfinishedSound()
7225 PlaySound(appData.soundIcsUnfinished);
7231 PlaySound(appData.soundIcsAlarm);
7237 PlaySound(appData.soundTell);
7243 system("stty echo");
7250 system("stty -echo");
7255 Colorize(cc, continuation)
7260 int count, outCount, error;
7262 if (textColors[(int)cc].bg > 0) {
7263 if (textColors[(int)cc].fg > 0) {
7264 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7265 textColors[(int)cc].fg, textColors[(int)cc].bg);
7267 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7268 textColors[(int)cc].bg);
7271 if (textColors[(int)cc].fg > 0) {
7272 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7273 textColors[(int)cc].fg);
7275 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7278 count = strlen(buf);
7279 outCount = OutputToProcess(NoProc, buf, count, &error);
7280 if (outCount < count) {
7281 DisplayFatalError(_("Error writing to display"), error, 1);
7284 if (continuation) return;
7287 PlaySound(appData.soundShout);
7290 PlaySound(appData.soundSShout);
7293 PlaySound(appData.soundChannel1);
7296 PlaySound(appData.soundChannel);
7299 PlaySound(appData.soundKibitz);
7302 PlaySound(appData.soundTell);
7304 case ColorChallenge:
7305 PlaySound(appData.soundChallenge);
7308 PlaySound(appData.soundRequest);
7311 PlaySound(appData.soundSeek);
7322 return getpwuid(getuid())->pw_name;
7326 ExpandPathName(path)
7329 static char static_buf[4*MSG_SIZ];
7330 char *d, *s, buf[4*MSG_SIZ];
7336 while (*s && isspace(*s))
7345 if (*(s+1) == '/') {
7346 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7350 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7351 { char *p; if(p = strchr(buf, '/')) *p = 0; }
7352 pwd = getpwnam(buf);
7355 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7359 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7360 strcat(d, strchr(s+1, '/'));
7364 safeStrCpy(d, s, 4*MSG_SIZ );
7371 static char host_name[MSG_SIZ];
7373 #if HAVE_GETHOSTNAME
7374 gethostname(host_name, MSG_SIZ);
7376 #else /* not HAVE_GETHOSTNAME */
7377 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7378 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7380 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7382 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7383 #endif /* not HAVE_GETHOSTNAME */
7386 XtIntervalId delayedEventTimerXID = 0;
7387 DelayedEventCallback delayedEventCallback = 0;
7392 delayedEventTimerXID = 0;
7393 delayedEventCallback();
7397 ScheduleDelayedEvent(cb, millisec)
7398 DelayedEventCallback cb; long millisec;
7400 if(delayedEventTimerXID && delayedEventCallback == cb)
7401 // [HGM] alive: replace, rather than add or flush identical event
7402 XtRemoveTimeOut(delayedEventTimerXID);
7403 delayedEventCallback = cb;
7404 delayedEventTimerXID =
7405 XtAppAddTimeOut(appContext, millisec,
7406 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7409 DelayedEventCallback
7412 if (delayedEventTimerXID) {
7413 return delayedEventCallback;
7420 CancelDelayedEvent()
7422 if (delayedEventTimerXID) {
7423 XtRemoveTimeOut(delayedEventTimerXID);
7424 delayedEventTimerXID = 0;
7428 XtIntervalId loadGameTimerXID = 0;
7430 int LoadGameTimerRunning()
7432 return loadGameTimerXID != 0;
7435 int StopLoadGameTimer()
7437 if (loadGameTimerXID != 0) {
7438 XtRemoveTimeOut(loadGameTimerXID);
7439 loadGameTimerXID = 0;
7447 LoadGameTimerCallback(arg, id)
7451 loadGameTimerXID = 0;
7456 StartLoadGameTimer(millisec)
7460 XtAppAddTimeOut(appContext, millisec,
7461 (XtTimerCallbackProc) LoadGameTimerCallback,
7465 XtIntervalId analysisClockXID = 0;
7468 AnalysisClockCallback(arg, id)
7472 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7473 || appData.icsEngineAnalyze) { // [DM]
7474 AnalysisPeriodicEvent(0);
7475 StartAnalysisClock();
7480 StartAnalysisClock()
7483 XtAppAddTimeOut(appContext, 2000,
7484 (XtTimerCallbackProc) AnalysisClockCallback,
7488 XtIntervalId clockTimerXID = 0;
7490 int ClockTimerRunning()
7492 return clockTimerXID != 0;
7495 int StopClockTimer()
7497 if (clockTimerXID != 0) {
7498 XtRemoveTimeOut(clockTimerXID);
7507 ClockTimerCallback(arg, id)
7516 StartClockTimer(millisec)
7520 XtAppAddTimeOut(appContext, millisec,
7521 (XtTimerCallbackProc) ClockTimerCallback,
7526 DisplayTimerLabel(w, color, timer, highlight)
7535 /* check for low time warning */
7536 Pixel foregroundOrWarningColor = timerForegroundPixel;
7539 appData.lowTimeWarning &&
7540 (timer / 1000) < appData.icsAlarmTime)
7541 foregroundOrWarningColor = lowTimeWarningColor;
7543 if (appData.clockMode) {
7544 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7545 XtSetArg(args[0], XtNlabel, buf);
7547 snprintf(buf, MSG_SIZ, "%s ", color);
7548 XtSetArg(args[0], XtNlabel, buf);
7553 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7554 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7556 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7557 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7560 XtSetValues(w, args, 3);
7564 DisplayWhiteClock(timeRemaining, highlight)
7570 if(appData.noGUI) return;
7571 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7572 if (highlight && iconPixmap == bIconPixmap) {
7573 iconPixmap = wIconPixmap;
7574 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7575 XtSetValues(shellWidget, args, 1);
7580 DisplayBlackClock(timeRemaining, highlight)
7586 if(appData.noGUI) return;
7587 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7588 if (highlight && iconPixmap == wIconPixmap) {
7589 iconPixmap = bIconPixmap;
7590 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7591 XtSetValues(shellWidget, args, 1);
7609 int StartChildProcess(cmdLine, dir, pr)
7616 int to_prog[2], from_prog[2];
7620 if (appData.debugMode) {
7621 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7624 /* We do NOT feed the cmdLine to the shell; we just
7625 parse it into blank-separated arguments in the
7626 most simple-minded way possible.
7629 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7632 while(*p == ' ') p++;
7634 if(*p == '"' || *p == '\'')
7635 p = strchr(++argv[i-1], *p);
7636 else p = strchr(p, ' ');
7637 if (p == NULL) break;
7642 SetUpChildIO(to_prog, from_prog);
7644 if ((pid = fork()) == 0) {
7646 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7647 close(to_prog[1]); // first close the unused pipe ends
7648 close(from_prog[0]);
7649 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7650 dup2(from_prog[1], 1);
7651 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7652 close(from_prog[1]); // and closing again loses one of the pipes!
7653 if(fileno(stderr) >= 2) // better safe than sorry...
7654 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7656 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7661 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7663 execvp(argv[0], argv);
7665 /* If we get here, exec failed */
7670 /* Parent process */
7672 close(from_prog[1]);
7674 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7677 cp->fdFrom = from_prog[0];
7678 cp->fdTo = to_prog[1];
7683 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7684 static RETSIGTYPE AlarmCallBack(int n)
7690 DestroyChildProcess(pr, signalType)
7694 ChildProc *cp = (ChildProc *) pr;
7696 if (cp->kind != CPReal) return;
7698 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7699 signal(SIGALRM, AlarmCallBack);
7701 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7702 kill(cp->pid, SIGKILL); // kill it forcefully
7703 wait((int *) 0); // and wait again
7707 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7709 /* Process is exiting either because of the kill or because of
7710 a quit command sent by the backend; either way, wait for it to die.
7719 InterruptChildProcess(pr)
7722 ChildProc *cp = (ChildProc *) pr;
7724 if (cp->kind != CPReal) return;
7725 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7728 int OpenTelnet(host, port, pr)
7733 char cmdLine[MSG_SIZ];
7735 if (port[0] == NULLCHAR) {
7736 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7738 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7740 return StartChildProcess(cmdLine, "", pr);
7743 int OpenTCP(host, port, pr)
7749 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7750 #else /* !OMIT_SOCKETS */
7751 struct addrinfo hints;
7752 struct addrinfo *ais, *ai;
7757 memset(&hints, 0, sizeof(hints));
7758 hints.ai_family = AF_UNSPEC;
7759 hints.ai_socktype = SOCK_STREAM;
7761 error = getaddrinfo(host, port, &hints, &ais);
7763 /* a getaddrinfo error is not an errno, so can't return it */
7764 fprintf(debugFP, "getaddrinfo(%s, %s): %s\n",
7765 host, port, gai_strerror(error));
7769 for (ai = ais; ai != NULL; ai = ai->ai_next) {
7770 if ((s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) < 0) {
7774 if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0) {
7787 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7793 #endif /* !OMIT_SOCKETS */
7798 int OpenCommPort(name, pr)
7805 fd = open(name, 2, 0);
7806 if (fd < 0) return errno;
7808 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7818 int OpenLoopback(pr)
7824 SetUpChildIO(to, from);
7826 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7829 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7836 int OpenRcmd(host, user, cmd, pr)
7837 char *host, *user, *cmd;
7840 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7844 #define INPUT_SOURCE_BUF_SIZE 8192
7853 char buf[INPUT_SOURCE_BUF_SIZE];
7858 DoInputCallback(closure, source, xid)
7863 InputSource *is = (InputSource *) closure;
7868 if (is->lineByLine) {
7869 count = read(is->fd, is->unused,
7870 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7872 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7875 is->unused += count;
7877 while (p < is->unused) {
7878 q = memchr(p, '\n', is->unused - p);
7879 if (q == NULL) break;
7881 (is->func)(is, is->closure, p, q - p, 0);
7885 while (p < is->unused) {
7890 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
7895 (is->func)(is, is->closure, is->buf, count, error);
7899 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
7906 ChildProc *cp = (ChildProc *) pr;
7908 is = (InputSource *) calloc(1, sizeof(InputSource));
7909 is->lineByLine = lineByLine;
7913 is->fd = fileno(stdin);
7915 is->kind = cp->kind;
7916 is->fd = cp->fdFrom;
7919 is->unused = is->buf;
7922 is->xid = XtAppAddInput(appContext, is->fd,
7923 (XtPointer) (XtInputReadMask),
7924 (XtInputCallbackProc) DoInputCallback,
7926 is->closure = closure;
7927 return (InputSourceRef) is;
7931 RemoveInputSource(isr)
7934 InputSource *is = (InputSource *) isr;
7936 if (is->xid == 0) return;
7937 XtRemoveInput(is->xid);
7941 int OutputToProcess(pr, message, count, outError)
7947 static int line = 0;
7948 ChildProc *cp = (ChildProc *) pr;
7953 if (appData.noJoin || !appData.useInternalWrap)
7954 outCount = fwrite(message, 1, count, stdout);
7957 int width = get_term_width();
7958 int len = wrap(NULL, message, count, width, &line);
7959 char *msg = malloc(len);
7963 outCount = fwrite(message, 1, count, stdout);
7966 dbgchk = wrap(msg, message, count, width, &line);
7967 if (dbgchk != len && appData.debugMode)
7968 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
7969 outCount = fwrite(msg, 1, dbgchk, stdout);
7975 outCount = write(cp->fdTo, message, count);
7985 /* Output message to process, with "ms" milliseconds of delay
7986 between each character. This is needed when sending the logon
7987 script to ICC, which for some reason doesn't like the
7988 instantaneous send. */
7989 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
7996 ChildProc *cp = (ChildProc *) pr;
8001 r = write(cp->fdTo, message++, 1);
8014 /**** Animation code by Hugh Fisher, DCS, ANU.
8016 Known problem: if a window overlapping the board is
8017 moved away while a piece is being animated underneath,
8018 the newly exposed area won't be updated properly.
8019 I can live with this.
8021 Known problem: if you look carefully at the animation
8022 of pieces in mono mode, they are being drawn as solid
8023 shapes without interior detail while moving. Fixing
8024 this would be a major complication for minimal return.
8027 /* Masks for XPM pieces. Black and white pieces can have
8028 different shapes, but in the interest of retaining my
8029 sanity pieces must have the same outline on both light
8030 and dark squares, and all pieces must use the same
8031 background square colors/images. */
8033 static int xpmDone = 0;
8036 CreateAnimMasks (pieceDepth)
8043 unsigned long plane;
8046 /* Need a bitmap just to get a GC with right depth */
8047 buf = XCreatePixmap(xDisplay, xBoardWindow,
8049 values.foreground = 1;
8050 values.background = 0;
8051 /* Don't use XtGetGC, not read only */
8052 maskGC = XCreateGC(xDisplay, buf,
8053 GCForeground | GCBackground, &values);
8054 XFreePixmap(xDisplay, buf);
8056 buf = XCreatePixmap(xDisplay, xBoardWindow,
8057 squareSize, squareSize, pieceDepth);
8058 values.foreground = XBlackPixel(xDisplay, xScreen);
8059 values.background = XWhitePixel(xDisplay, xScreen);
8060 bufGC = XCreateGC(xDisplay, buf,
8061 GCForeground | GCBackground, &values);
8063 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8064 /* Begin with empty mask */
8065 if(!xpmDone) // [HGM] pieces: keep using existing
8066 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8067 squareSize, squareSize, 1);
8068 XSetFunction(xDisplay, maskGC, GXclear);
8069 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8070 0, 0, squareSize, squareSize);
8072 /* Take a copy of the piece */
8077 XSetFunction(xDisplay, bufGC, GXcopy);
8078 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8080 0, 0, squareSize, squareSize, 0, 0);
8082 /* XOR the background (light) over the piece */
8083 XSetFunction(xDisplay, bufGC, GXxor);
8085 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8086 0, 0, squareSize, squareSize, 0, 0);
8088 XSetForeground(xDisplay, bufGC, lightSquareColor);
8089 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8092 /* We now have an inverted piece image with the background
8093 erased. Construct mask by just selecting all the non-zero
8094 pixels - no need to reconstruct the original image. */
8095 XSetFunction(xDisplay, maskGC, GXor);
8097 /* Might be quicker to download an XImage and create bitmap
8098 data from it rather than this N copies per piece, but it
8099 only takes a fraction of a second and there is a much
8100 longer delay for loading the pieces. */
8101 for (n = 0; n < pieceDepth; n ++) {
8102 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8103 0, 0, squareSize, squareSize,
8109 XFreePixmap(xDisplay, buf);
8110 XFreeGC(xDisplay, bufGC);
8111 XFreeGC(xDisplay, maskGC);
8115 InitAnimState (anim, info)
8117 XWindowAttributes * info;
8122 /* Each buffer is square size, same depth as window */
8123 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8124 squareSize, squareSize, info->depth);
8125 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8126 squareSize, squareSize, info->depth);
8128 /* Create a plain GC for blitting */
8129 mask = GCForeground | GCBackground | GCFunction |
8130 GCPlaneMask | GCGraphicsExposures;
8131 values.foreground = XBlackPixel(xDisplay, xScreen);
8132 values.background = XWhitePixel(xDisplay, xScreen);
8133 values.function = GXcopy;
8134 values.plane_mask = AllPlanes;
8135 values.graphics_exposures = False;
8136 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8138 /* Piece will be copied from an existing context at
8139 the start of each new animation/drag. */
8140 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8142 /* Outline will be a read-only copy of an existing */
8143 anim->outlineGC = None;
8149 XWindowAttributes info;
8151 if (xpmDone && gameInfo.variant == oldVariant) return;
8152 if(xpmDone) oldVariant = gameInfo.variant; // first time pieces might not be created yet
8153 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8155 InitAnimState(&game, &info);
8156 InitAnimState(&player, &info);
8158 /* For XPM pieces, we need bitmaps to use as masks. */
8160 CreateAnimMasks(info.depth), xpmDone = 1;
8165 static Boolean frameWaiting;
8167 static RETSIGTYPE FrameAlarm (sig)
8170 frameWaiting = False;
8171 /* In case System-V style signals. Needed?? */
8172 signal(SIGALRM, FrameAlarm);
8179 struct itimerval delay;
8181 XSync(xDisplay, False);
8184 frameWaiting = True;
8185 signal(SIGALRM, FrameAlarm);
8186 delay.it_interval.tv_sec =
8187 delay.it_value.tv_sec = time / 1000;
8188 delay.it_interval.tv_usec =
8189 delay.it_value.tv_usec = (time % 1000) * 1000;
8190 setitimer(ITIMER_REAL, &delay, NULL);
8191 while (frameWaiting) pause();
8192 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8193 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8194 setitimer(ITIMER_REAL, &delay, NULL);
8204 XSync(xDisplay, False);
8206 usleep(time * 1000);
8211 /* Convert board position to corner of screen rect and color */
8214 ScreenSquare(column, row, pt, color)
8215 int column; int row; XPoint * pt; int * color;
8218 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8219 pt->y = lineGap + row * (squareSize + lineGap);
8221 pt->x = lineGap + column * (squareSize + lineGap);
8222 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8224 *color = SquareColor(row, column);
8227 /* Convert window coords to square */
8230 BoardSquare(x, y, column, row)
8231 int x; int y; int * column; int * row;
8233 *column = EventToSquare(x, BOARD_WIDTH);
8234 if (flipView && *column >= 0)
8235 *column = BOARD_WIDTH - 1 - *column;
8236 *row = EventToSquare(y, BOARD_HEIGHT);
8237 if (!flipView && *row >= 0)
8238 *row = BOARD_HEIGHT - 1 - *row;
8243 #undef Max /* just in case */
8245 #define Max(a, b) ((a) > (b) ? (a) : (b))
8246 #define Min(a, b) ((a) < (b) ? (a) : (b))
8249 SetRect(rect, x, y, width, height)
8250 XRectangle * rect; int x; int y; int width; int height;
8254 rect->width = width;
8255 rect->height = height;
8258 /* Test if two frames overlap. If they do, return
8259 intersection rect within old and location of
8260 that rect within new. */
8263 Intersect(old, new, size, area, pt)
8264 XPoint * old; XPoint * new;
8265 int size; XRectangle * area; XPoint * pt;
8267 if (old->x > new->x + size || new->x > old->x + size ||
8268 old->y > new->y + size || new->y > old->y + size) {
8271 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8272 size - abs(old->x - new->x), size - abs(old->y - new->y));
8273 pt->x = Max(old->x - new->x, 0);
8274 pt->y = Max(old->y - new->y, 0);
8279 /* For two overlapping frames, return the rect(s)
8280 in the old that do not intersect with the new. */
8283 CalcUpdateRects(old, new, size, update, nUpdates)
8284 XPoint * old; XPoint * new; int size;
8285 XRectangle update[]; int * nUpdates;
8289 /* If old = new (shouldn't happen) then nothing to draw */
8290 if (old->x == new->x && old->y == new->y) {
8294 /* Work out what bits overlap. Since we know the rects
8295 are the same size we don't need a full intersect calc. */
8297 /* Top or bottom edge? */
8298 if (new->y > old->y) {
8299 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8301 } else if (old->y > new->y) {
8302 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8303 size, old->y - new->y);
8306 /* Left or right edge - don't overlap any update calculated above. */
8307 if (new->x > old->x) {
8308 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8309 new->x - old->x, size - abs(new->y - old->y));
8311 } else if (old->x > new->x) {
8312 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8313 old->x - new->x, size - abs(new->y - old->y));
8320 /* Generate a series of frame coords from start->mid->finish.
8321 The movement rate doubles until the half way point is
8322 reached, then halves back down to the final destination,
8323 which gives a nice slow in/out effect. The algorithmn
8324 may seem to generate too many intermediates for short
8325 moves, but remember that the purpose is to attract the
8326 viewers attention to the piece about to be moved and
8327 then to where it ends up. Too few frames would be less
8331 Tween(start, mid, finish, factor, frames, nFrames)
8332 XPoint * start; XPoint * mid;
8333 XPoint * finish; int factor;
8334 XPoint frames[]; int * nFrames;
8336 int fraction, n, count;
8340 /* Slow in, stepping 1/16th, then 1/8th, ... */
8342 for (n = 0; n < factor; n++)
8344 for (n = 0; n < factor; n++) {
8345 frames[count].x = start->x + (mid->x - start->x) / fraction;
8346 frames[count].y = start->y + (mid->y - start->y) / fraction;
8348 fraction = fraction / 2;
8352 frames[count] = *mid;
8355 /* Slow out, stepping 1/2, then 1/4, ... */
8357 for (n = 0; n < factor; n++) {
8358 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8359 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8361 fraction = fraction * 2;
8366 /* Draw a piece on the screen without disturbing what's there */
8369 SelectGCMask(piece, clip, outline, mask)
8370 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8374 /* Bitmap for piece being moved. */
8375 if (appData.monoMode) {
8376 *mask = *pieceToSolid(piece);
8377 } else if (useImages) {
8379 *mask = xpmMask[piece];
8381 *mask = ximMaskPm[piece];
8384 *mask = *pieceToSolid(piece);
8387 /* GC for piece being moved. Square color doesn't matter, but
8388 since it gets modified we make a copy of the original. */
8390 if (appData.monoMode)
8395 if (appData.monoMode)
8400 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8402 /* Outline only used in mono mode and is not modified */
8404 *outline = bwPieceGC;
8406 *outline = wbPieceGC;
8410 OverlayPiece(piece, clip, outline, dest)
8411 ChessSquare piece; GC clip; GC outline; Drawable dest;
8416 /* Draw solid rectangle which will be clipped to shape of piece */
8417 XFillRectangle(xDisplay, dest, clip,
8418 0, 0, squareSize, squareSize);
8419 if (appData.monoMode)
8420 /* Also draw outline in contrasting color for black
8421 on black / white on white cases */
8422 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8423 0, 0, squareSize, squareSize, 0, 0, 1);
8425 /* Copy the piece */
8430 if(appData.upsideDown && flipView) kind ^= 2;
8431 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8433 0, 0, squareSize, squareSize,
8438 /* Animate the movement of a single piece */
8441 BeginAnimation(anim, piece, startColor, start)
8449 if(appData.upsideDown && flipView) piece += piece < BlackPawn ? BlackPawn : -BlackPawn;
8450 /* The old buffer is initialised with the start square (empty) */
8451 BlankSquare(start->x, start->y, startColor, EmptySquare, anim->saveBuf, 0);
8452 anim->prevFrame = *start;
8454 /* The piece will be drawn using its own bitmap as a matte */
8455 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8456 XSetClipMask(xDisplay, anim->pieceGC, mask);
8460 AnimationFrame(anim, frame, piece)
8465 XRectangle updates[4];
8470 /* Save what we are about to draw into the new buffer */
8471 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8472 frame->x, frame->y, squareSize, squareSize,
8475 /* Erase bits of the previous frame */
8476 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8477 /* Where the new frame overlapped the previous,
8478 the contents in newBuf are wrong. */
8479 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8480 overlap.x, overlap.y,
8481 overlap.width, overlap.height,
8483 /* Repaint the areas in the old that don't overlap new */
8484 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8485 for (i = 0; i < count; i++)
8486 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8487 updates[i].x - anim->prevFrame.x,
8488 updates[i].y - anim->prevFrame.y,
8489 updates[i].width, updates[i].height,
8490 updates[i].x, updates[i].y);
8492 /* Easy when no overlap */
8493 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8494 0, 0, squareSize, squareSize,
8495 anim->prevFrame.x, anim->prevFrame.y);
8498 /* Save this frame for next time round */
8499 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8500 0, 0, squareSize, squareSize,
8502 anim->prevFrame = *frame;
8504 /* Draw piece over original screen contents, not current,
8505 and copy entire rect. Wipes out overlapping piece images. */
8506 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8507 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8508 0, 0, squareSize, squareSize,
8509 frame->x, frame->y);
8513 EndAnimation (anim, finish)
8517 XRectangle updates[4];
8522 /* The main code will redraw the final square, so we
8523 only need to erase the bits that don't overlap. */
8524 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8525 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8526 for (i = 0; i < count; i++)
8527 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8528 updates[i].x - anim->prevFrame.x,
8529 updates[i].y - anim->prevFrame.y,
8530 updates[i].width, updates[i].height,
8531 updates[i].x, updates[i].y);
8533 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8534 0, 0, squareSize, squareSize,
8535 anim->prevFrame.x, anim->prevFrame.y);
8540 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8542 ChessSquare piece; int startColor;
8543 XPoint * start; XPoint * finish;
8544 XPoint frames[]; int nFrames;
8548 BeginAnimation(anim, piece, startColor, start);
8549 for (n = 0; n < nFrames; n++) {
8550 AnimationFrame(anim, &(frames[n]), piece);
8551 FrameDelay(appData.animSpeed);
8553 EndAnimation(anim, finish);
8557 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
8560 ChessSquare piece = board[fromY][toY];
8561 board[fromY][toY] = EmptySquare;
8562 DrawPosition(FALSE, board);
8564 x = lineGap + ((BOARD_WIDTH-1)-toX) * (squareSize + lineGap);
8565 y = lineGap + toY * (squareSize + lineGap);
8567 x = lineGap + toX * (squareSize + lineGap);
8568 y = lineGap + ((BOARD_HEIGHT-1)-toY) * (squareSize + lineGap);
8570 for(i=1; i<4*kFactor; i++) {
8571 int r = squareSize * 9 * i/(20*kFactor - 5);
8572 XFillArc(xDisplay, xBoardWindow, highlineGC,
8573 x + squareSize/2 - r, y+squareSize/2 - r, 2*r, 2*r, 0, 64*360);
8574 FrameDelay(appData.animSpeed);
8576 board[fromY][toY] = piece;
8579 /* Main control logic for deciding what to animate and how */
8582 AnimateMove(board, fromX, fromY, toX, toY)
8591 XPoint start, finish, mid;
8592 XPoint frames[kFactor * 2 + 1];
8593 int nFrames, startColor, endColor;
8595 /* Are we animating? */
8596 if (!appData.animate || appData.blindfold)
8599 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8600 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8601 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8603 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8604 piece = board[fromY][fromX];
8605 if (piece >= EmptySquare) return;
8610 hop = abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1;
8613 if (appData.debugMode) {
8614 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8615 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8616 piece, fromX, fromY, toX, toY); }
8618 ScreenSquare(fromX, fromY, &start, &startColor);
8619 ScreenSquare(toX, toY, &finish, &endColor);
8622 /* Knight: make straight movement then diagonal */
8623 if (abs(toY - fromY) < abs(toX - fromX)) {
8624 mid.x = start.x + (finish.x - start.x) / 2;
8628 mid.y = start.y + (finish.y - start.y) / 2;
8631 mid.x = start.x + (finish.x - start.x) / 2;
8632 mid.y = start.y + (finish.y - start.y) / 2;
8635 /* Don't use as many frames for very short moves */
8636 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8637 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8639 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8640 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8641 if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged
8643 for(i=0; i<BOARD_WIDTH; i++) for(j=0; j<BOARD_HEIGHT; j++)
8644 if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] = True;
8647 /* Be sure end square is redrawn */
8648 damage[0][toY][toX] = True;
8652 DragPieceBegin(x, y, instantly)
8653 int x; int y; Boolean instantly;
8655 int boardX, boardY, color;
8658 /* Are we animating? */
8659 if (!appData.animateDragging || appData.blindfold)
8662 /* Figure out which square we start in and the
8663 mouse position relative to top left corner. */
8664 BoardSquare(x, y, &boardX, &boardY);
8665 player.startBoardX = boardX;
8666 player.startBoardY = boardY;
8667 ScreenSquare(boardX, boardY, &corner, &color);
8668 player.startSquare = corner;
8669 player.startColor = color;
8670 /* As soon as we start dragging, the piece will jump slightly to
8671 be centered over the mouse pointer. */
8672 player.mouseDelta.x = squareSize/2;
8673 player.mouseDelta.y = squareSize/2;
8674 /* Initialise animation */
8675 player.dragPiece = PieceForSquare(boardX, boardY);
8677 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8678 player.dragActive = True;
8679 BeginAnimation(&player, player.dragPiece, color, &corner);
8680 /* Mark this square as needing to be redrawn. Note that
8681 we don't remove the piece though, since logically (ie
8682 as seen by opponent) the move hasn't been made yet. */
8683 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8684 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8685 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8686 corner.x, corner.y, squareSize, squareSize,
8687 0, 0); // [HGM] zh: unstack in stead of grab
8688 if(gatingPiece != EmptySquare) {
8689 /* Kludge alert: When gating we want the introduced
8690 piece to appear on the from square. To generate an
8691 image of it, we draw it on the board, copy the image,
8692 and draw the original piece again. */
8693 ChessSquare piece = boards[currentMove][boardY][boardX];
8694 DrawSquare(boardY, boardX, gatingPiece, 0);
8695 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8696 corner.x, corner.y, squareSize, squareSize, 0, 0);
8697 DrawSquare(boardY, boardX, piece, 0);
8699 damage[0][boardY][boardX] = True;
8701 player.dragActive = False;
8706 ChangeDragPiece(ChessSquare piece)
8709 player.dragPiece = piece;
8710 /* The piece will be drawn using its own bitmap as a matte */
8711 SelectGCMask(piece, &player.pieceGC, &player.outlineGC, &mask);
8712 XSetClipMask(xDisplay, player.pieceGC, mask);
8721 /* Are we animating? */
8722 if (!appData.animateDragging || appData.blindfold)
8726 if (! player.dragActive)
8728 /* Move piece, maintaining same relative position
8729 of mouse within square */
8730 corner.x = x - player.mouseDelta.x;
8731 corner.y = y - player.mouseDelta.y;
8732 AnimationFrame(&player, &corner, player.dragPiece);
8734 if (appData.highlightDragging) {
8736 BoardSquare(x, y, &boardX, &boardY);
8737 SetHighlights(fromX, fromY, boardX, boardY);
8746 int boardX, boardY, color;
8749 /* Are we animating? */
8750 if (!appData.animateDragging || appData.blindfold)
8754 if (! player.dragActive)
8756 /* Last frame in sequence is square piece is
8757 placed on, which may not match mouse exactly. */
8758 BoardSquare(x, y, &boardX, &boardY);
8759 ScreenSquare(boardX, boardY, &corner, &color);
8760 EndAnimation(&player, &corner);
8762 /* Be sure end square is redrawn */
8763 damage[0][boardY][boardX] = True;
8765 /* This prevents weird things happening with fast successive
8766 clicks which on my Sun at least can cause motion events
8767 without corresponding press/release. */
8768 player.dragActive = False;
8771 /* Handle expose event while piece being dragged */
8776 if (!player.dragActive || appData.blindfold)
8779 /* What we're doing: logically, the move hasn't been made yet,
8780 so the piece is still in it's original square. But visually
8781 it's being dragged around the board. So we erase the square
8782 that the piece is on and draw it at the last known drag point. */
8783 BlankSquare(player.startSquare.x, player.startSquare.y,
8784 player.startColor, EmptySquare, xBoardWindow, 1);
8785 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8786 damage[0][player.startBoardY][player.startBoardX] = TRUE;
8789 #include <sys/ioctl.h>
8790 int get_term_width()
8792 int fd, default_width;
8795 default_width = 79; // this is FICS default anyway...
8797 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8799 if (!ioctl(fd, TIOCGSIZE, &win))
8800 default_width = win.ts_cols;
8801 #elif defined(TIOCGWINSZ)
8803 if (!ioctl(fd, TIOCGWINSZ, &win))
8804 default_width = win.ws_col;
8806 return default_width;
8812 static int old_width = 0;
8813 int new_width = get_term_width();
8815 if (old_width != new_width)
8816 ics_printf("set width %d\n", new_width);
8817 old_width = new_width;
8820 void NotifyFrontendLogin()
8825 /* [AS] Arrow highlighting support */
8827 static double A_WIDTH = 5; /* Width of arrow body */
8829 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
8830 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
8832 static double Sqr( double x )
8837 static int Round( double x )
8839 return (int) (x + 0.5);
8842 void SquareToPos(int rank, int file, int *x, int *y)
8845 *x = lineGap + ((BOARD_WIDTH-1)-file) * (squareSize + lineGap);
8846 *y = lineGap + rank * (squareSize + lineGap);
8848 *x = lineGap + file * (squareSize + lineGap);
8849 *y = lineGap + ((BOARD_HEIGHT-1)-rank) * (squareSize + lineGap);
8853 /* Draw an arrow between two points using current settings */
8854 void DrawArrowBetweenPoints( int s_x, int s_y, int d_x, int d_y )
8857 double dx, dy, j, k, x, y;
8860 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
8862 arrow[0].x = s_x + A_WIDTH + 0.5;
8865 arrow[1].x = s_x + A_WIDTH + 0.5;
8866 arrow[1].y = d_y - h;
8868 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8869 arrow[2].y = d_y - h;
8874 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
8875 arrow[5].y = d_y - h;
8877 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8878 arrow[4].y = d_y - h;
8880 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
8883 else if( d_y == s_y ) {
8884 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
8887 arrow[0].y = s_y + A_WIDTH + 0.5;
8889 arrow[1].x = d_x - w;
8890 arrow[1].y = s_y + A_WIDTH + 0.5;
8892 arrow[2].x = d_x - w;
8893 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8898 arrow[5].x = d_x - w;
8899 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
8901 arrow[4].x = d_x - w;
8902 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8905 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
8908 /* [AS] Needed a lot of paper for this! :-) */
8909 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
8910 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
8912 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
8914 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
8919 arrow[0].x = Round(x - j);
8920 arrow[0].y = Round(y + j*dx);
8922 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
8923 arrow[1].y = Round(arrow[0].y - 2*j*dx);
8926 x = (double) d_x - k;
8927 y = (double) d_y - k*dy;
8930 x = (double) d_x + k;
8931 y = (double) d_y + k*dy;
8934 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
8936 arrow[6].x = Round(x - j);
8937 arrow[6].y = Round(y + j*dx);
8939 arrow[2].x = Round(arrow[6].x + 2*j);
8940 arrow[2].y = Round(arrow[6].y - 2*j*dx);
8942 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
8943 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
8948 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
8949 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
8952 XFillPolygon(xDisplay, xBoardWindow, highlineGC, arrow, 7, Nonconvex, CoordModeOrigin);
8953 // Polygon( hdc, arrow, 7 );
8956 /* [AS] Draw an arrow between two squares */
8957 void DrawArrowBetweenSquares( int s_col, int s_row, int d_col, int d_row )
8959 int s_x, s_y, d_x, d_y, hor, vert, i;
8961 if( s_col == d_col && s_row == d_row ) {
8965 /* Get source and destination points */
8966 SquareToPos( s_row, s_col, &s_x, &s_y);
8967 SquareToPos( d_row, d_col, &d_x, &d_y);
8970 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
8972 else if( d_y < s_y ) {
8973 d_y += squareSize / 2 + squareSize / 4;
8976 d_y += squareSize / 2;
8980 d_x += squareSize / 2 - squareSize / 4;
8982 else if( d_x < s_x ) {
8983 d_x += squareSize / 2 + squareSize / 4;
8986 d_x += squareSize / 2;
8989 s_x += squareSize / 2;
8990 s_y += squareSize / 2;
8993 A_WIDTH = squareSize / 14.; //[HGM] make float
8995 DrawArrowBetweenPoints( s_x, s_y, d_x, d_y );
8997 hor = 64*s_col + 32; vert = 64*s_row + 32;
8998 for(i=0; i<= 64; i++) {
8999 damage[0][vert+6>>6][hor+6>>6] = True;
9000 damage[0][vert-6>>6][hor+6>>6] = True;
9001 damage[0][vert+6>>6][hor-6>>6] = True;
9002 damage[0][vert-6>>6][hor-6>>6] = True;
9003 hor += d_col - s_col; vert += d_row - s_row;
9007 Boolean IsDrawArrowEnabled()
9009 return appData.highlightMoveWithArrow && squareSize >= 32;
9012 void DrawArrowHighlight(int fromX, int fromY, int toX,int toY)
9014 if( IsDrawArrowEnabled() && fromX >= 0 && fromY >= 0 && toX >= 0 && toY >= 0)
9015 DrawArrowBetweenSquares(fromX, fromY, toX, toY);
9018 void UpdateLogos(int displ)
9020 return; // no logos in XBoard yet