2 * xboard.c -- X front end for XBoard
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
8 * 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
10 * The following terms apply to Digital Equipment Corporation's copyright
12 * ------------------------------------------------------------------------
15 * Permission to use, copy, modify, and distribute this software and its
16 * documentation for any purpose and without fee is hereby granted,
17 * provided that the above copyright notice appear in all copies and that
18 * both that copyright notice and this permission notice appear in
19 * supporting documentation, and that the name of Digital not be
20 * used in advertising or publicity pertaining to distribution of the
21 * software without specific, written prior permission.
23 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
30 * ------------------------------------------------------------------------
32 * The following terms apply to the enhanced version of XBoard
33 * distributed by the Free Software Foundation:
34 * ------------------------------------------------------------------------
36 * GNU XBoard is free software: you can redistribute it and/or modify
37 * it under the terms of the GNU General Public License as published by
38 * the Free Software Foundation, either version 3 of the License, or (at
39 * your option) any later version.
41 * GNU XBoard is distributed in the hope that it will be useful, but
42 * WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44 * General Public License for more details.
46 * You should have received a copy of the GNU General Public License
47 * along with this program. If not, see http://www.gnu.org/licenses/. *
49 *------------------------------------------------------------------------
50 ** See the file ChangeLog for a revision history. */
60 #include <sys/types.h>
66 # if HAVE_SYS_SOCKET_H
67 # include <sys/socket.h>
68 # include <netinet/in.h>
70 # else /* not HAVE_SYS_SOCKET_H */
71 # if HAVE_LAN_SOCKET_H
72 # include <lan/socket.h>
74 # include <lan/netdb.h>
75 # else /* not HAVE_LAN_SOCKET_H */
76 # define OMIT_SOCKETS 1
77 # endif /* not HAVE_LAN_SOCKET_H */
78 # endif /* not HAVE_SYS_SOCKET_H */
79 #endif /* !OMIT_SOCKETS */
84 #else /* not STDC_HEADERS */
85 extern char *getenv();
88 # else /* not HAVE_STRING_H */
90 # endif /* not HAVE_STRING_H */
91 #endif /* not STDC_HEADERS */
94 # include <sys/fcntl.h>
95 #else /* not HAVE_SYS_FCNTL_H */
98 # endif /* HAVE_FCNTL_H */
99 #endif /* not HAVE_SYS_FCNTL_H */
101 #if HAVE_SYS_SYSTEMINFO_H
102 # include <sys/systeminfo.h>
103 #endif /* HAVE_SYS_SYSTEMINFO_H */
105 #if TIME_WITH_SYS_TIME
106 # include <sys/time.h>
110 # include <sys/time.h>
121 # include <sys/wait.h>
126 # define NAMLEN(dirent) strlen((dirent)->d_name)
127 # define HAVE_DIR_STRUCT
129 # define dirent direct
130 # define NAMLEN(dirent) (dirent)->d_namlen
132 # include <sys/ndir.h>
133 # define HAVE_DIR_STRUCT
136 # include <sys/dir.h>
137 # define HAVE_DIR_STRUCT
141 # define HAVE_DIR_STRUCT
149 #include <X11/Intrinsic.h>
150 #include <X11/StringDefs.h>
151 #include <X11/Shell.h>
152 #include <X11/cursorfont.h>
153 #include <X11/Xatom.h>
154 #include <X11/Xmu/Atoms.h>
156 #include <X11/Xaw3d/Dialog.h>
157 #include <X11/Xaw3d/Form.h>
158 #include <X11/Xaw3d/List.h>
159 #include <X11/Xaw3d/Label.h>
160 #include <X11/Xaw3d/SimpleMenu.h>
161 #include <X11/Xaw3d/SmeBSB.h>
162 #include <X11/Xaw3d/SmeLine.h>
163 #include <X11/Xaw3d/Box.h>
164 #include <X11/Xaw3d/MenuButton.h>
165 #include <X11/Xaw3d/Text.h>
166 #include <X11/Xaw3d/AsciiText.h>
168 #include <X11/Xaw/Dialog.h>
169 #include <X11/Xaw/Form.h>
170 #include <X11/Xaw/List.h>
171 #include <X11/Xaw/Label.h>
172 #include <X11/Xaw/SimpleMenu.h>
173 #include <X11/Xaw/SmeBSB.h>
174 #include <X11/Xaw/SmeLine.h>
175 #include <X11/Xaw/Box.h>
176 #include <X11/Xaw/MenuButton.h>
177 #include <X11/Xaw/Text.h>
178 #include <X11/Xaw/AsciiText.h>
181 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
186 #include "pixmaps/pixmaps.h"
187 #define IMAGE_EXT "xpm"
189 #define IMAGE_EXT "xim"
190 #include "bitmaps/bitmaps.h"
193 #include "bitmaps/icon_white.bm"
194 #include "bitmaps/icon_black.bm"
195 #include "bitmaps/checkmark.bm"
197 #include "frontend.h"
199 #include "backendz.h"
203 #include "xgamelist.h"
204 #include "xhistory.h"
205 #include "xedittags.h"
208 // must be moved to xengineoutput.h
210 void EngineOutputProc P((Widget w, XEvent *event,
211 String *prms, Cardinal *nprms));
212 void EvalGraphProc P((Widget w, XEvent *event,
213 String *prms, Cardinal *nprms));
220 #define usleep(t) _sleep2(((t)+500)/1000)
224 # define _(s) gettext (s)
225 # define N_(s) gettext_noop (s)
243 int main P((int argc, char **argv));
244 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
245 char *init_path, char *filter, char *mode, int (*show_entry)(), char **name_return));
246 RETSIGTYPE CmailSigHandler P((int sig));
247 RETSIGTYPE IntSigHandler P((int sig));
248 RETSIGTYPE TermSizeSigHandler P((int sig));
249 void CreateGCs P((int redo));
250 void CreateAnyPieces P((void));
251 void CreateXIMPieces P((void));
252 void CreateXPMPieces P((void));
253 void CreateXPMBoard P((char *s, int n));
254 void CreatePieces P((void));
255 void CreatePieceMenus P((void));
256 Widget CreateMenuBar P((Menu *mb));
257 Widget CreateButtonBar P ((MenuItem *mi));
259 char *InsertPxlSize P((char *pattern, int targetPxlSize));
260 XFontSet CreateFontSet P((char *base_fnt_lst));
262 char *FindFont P((char *pattern, int targetPxlSize));
264 void PieceMenuPopup P((Widget w, XEvent *event,
265 String *params, Cardinal *num_params));
266 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
267 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
268 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
269 u_int wreq, u_int hreq));
270 void CreateGrid P((void));
271 int EventToSquare P((int x, int limit));
272 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
273 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
274 void MoveTypeInProc P((Widget widget, caddr_t unused, XEvent *event));
275 void HandleUserMove P((Widget w, XEvent *event,
276 String *prms, Cardinal *nprms));
277 void AnimateUserMove P((Widget w, XEvent * event,
278 String * params, Cardinal * nParams));
279 void HandlePV P((Widget w, XEvent * event,
280 String * params, Cardinal * nParams));
281 void SelectPV P((Widget w, XEvent * event,
282 String * params, Cardinal * nParams));
283 void StopPV P((Widget w, XEvent * event,
284 String * params, Cardinal * nParams));
285 void WhiteClock P((Widget w, XEvent *event,
286 String *prms, Cardinal *nprms));
287 void BlackClock P((Widget w, XEvent *event,
288 String *prms, Cardinal *nprms));
289 void DrawPositionProc P((Widget w, XEvent *event,
290 String *prms, Cardinal *nprms));
291 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
293 void CommentClick P((Widget w, XEvent * event,
294 String * params, Cardinal * nParams));
295 void CommentPopUp P((char *title, char *label));
296 void CommentPopDown P((void));
297 void ICSInputBoxPopUp P((void));
298 void ICSInputBoxPopDown P((void));
299 void FileNamePopUp P((char *label, char *def, char *filter,
300 FileProc proc, char *openMode));
301 void FileNamePopDown P((void));
302 void FileNameCallback P((Widget w, XtPointer client_data,
303 XtPointer call_data));
304 void FileNameAction P((Widget w, XEvent *event,
305 String *prms, Cardinal *nprms));
306 void AskQuestionReplyAction P((Widget w, XEvent *event,
307 String *prms, Cardinal *nprms));
308 void AskQuestionProc P((Widget w, XEvent *event,
309 String *prms, Cardinal *nprms));
310 void AskQuestionPopDown P((void));
311 void PromotionPopDown P((void));
312 void PromotionCallback P((Widget w, XtPointer client_data,
313 XtPointer call_data));
314 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
315 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
316 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
317 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
319 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
321 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
323 void LoadPositionProc P((Widget w, XEvent *event,
324 String *prms, Cardinal *nprms));
325 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
327 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
329 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
331 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
333 void PastePositionProc P((Widget w, XEvent *event, String *prms,
335 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
336 void CopyGameListProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
337 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
338 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
339 void SavePositionProc P((Widget w, XEvent *event,
340 String *prms, Cardinal *nprms));
341 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
342 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
344 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
345 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
346 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
348 void MachineWhiteProc P((Widget w, XEvent *event,
349 String *prms, Cardinal *nprms));
350 void AnalyzeModeProc P((Widget w, XEvent *event,
351 String *prms, Cardinal *nprms));
352 void AnalyzeFileProc P((Widget w, XEvent *event,
353 String *prms, Cardinal *nprms));
354 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
356 void MatchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
357 void MatchOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
358 void IcsClientProc P((Widget w, XEvent *event, String *prms,
360 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void EditPositionProc P((Widget w, XEvent *event,
362 String *prms, Cardinal *nprms));
363 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void EditCommentProc P((Widget w, XEvent *event,
365 String *prms, Cardinal *nprms));
366 void IcsInputBoxProc P((Widget w, XEvent *event,
367 String *prms, Cardinal *nprms));
368 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
369 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
370 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
371 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
372 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
373 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
374 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
375 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
376 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
377 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
379 void TypeInProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
380 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void StopObservingProc P((Widget w, XEvent *event, String *prms,
385 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
387 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
388 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
389 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
390 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
391 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
392 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
393 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
394 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
396 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
398 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
399 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
401 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
403 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
405 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
406 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
407 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
408 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
410 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
411 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
413 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
415 void HighlightArrowProc P((Widget w, XEvent *event, String *prms,
417 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
418 //void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
419 void OneClickProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
420 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
422 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
424 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
426 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
428 //void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
429 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
431 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
433 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
435 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
437 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
442 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
443 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
444 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
445 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
446 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
447 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
448 void DisplayMove P((int moveNumber));
449 void DisplayTitle P((char *title));
450 void ICSInitScript P((void));
451 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
452 void ErrorPopUp P((char *title, char *text, int modal));
453 void ErrorPopDown P((void));
454 static char *ExpandPathName P((char *path));
455 static void CreateAnimVars P((void));
456 static void DragPieceMove P((int x, int y));
457 static void DrawDragPiece P((void));
458 char *ModeToWidgetName P((GameMode mode));
459 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
460 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
461 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
462 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
463 void OptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
464 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
465 void IcsTextProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
466 void LoadEngineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
467 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
468 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
469 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
470 void IcsOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
471 void SoundOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
472 void BoardOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
473 void LoadOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
474 void SaveOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
475 void EditBookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
476 void SelectMove P((Widget w, XEvent * event, String * params, Cardinal * nParams));
477 void GameListOptionsPopDown P(());
478 void GenericPopDown P(());
479 void update_ics_width P(());
480 int get_term_width P(());
481 int CopyMemoProc P(());
482 void DrawArrowHighlight P((int fromX, int fromY, int toX,int toY));
483 Boolean IsDrawArrowEnabled P(());
486 * XBoard depends on Xt R4 or higher
488 int xtVersion = XtSpecificationRelease;
493 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
494 jailSquareColor, highlightSquareColor, premoveHighlightColor;
495 Pixel lowTimeWarningColor;
496 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
497 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
498 wjPieceGC, bjPieceGC, prelineGC, countGC;
499 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
500 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
501 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
502 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
503 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
504 ICSInputShell, fileNameShell, askQuestionShell;
505 Widget historyShell, evalGraphShell, gameListShell;
506 int hOffset; // [HGM] dual
507 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
508 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
509 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
511 XFontSet fontSet, clockFontSet;
514 XFontStruct *clockFontStruct;
516 Font coordFontID, countFontID;
517 XFontStruct *coordFontStruct, *countFontStruct;
518 XtAppContext appContext;
520 char *oldICSInteractionTitle;
524 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
526 Position commentX = -1, commentY = -1;
527 Dimension commentW, commentH;
528 typedef unsigned int BoardSize;
530 Boolean chessProgram;
532 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
533 int squareSize, smallLayout = 0, tinyLayout = 0,
534 marginW, marginH, // [HGM] for run-time resizing
535 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
536 ICSInputBoxUp = False, askQuestionUp = False,
537 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
538 errorUp = False, errorExitStatus = -1, lineGap, defaultLineGap;
539 Pixel timerForegroundPixel, timerBackgroundPixel;
540 Pixel buttonForegroundPixel, buttonBackgroundPixel;
541 char *chessDir, *programName, *programVersion,
542 *gameCopyFilename, *gamePasteFilename;
543 Boolean alwaysOnTop = False;
544 Boolean saveSettingsOnExit;
545 char *settingsFileName;
546 char *icsTextMenuString;
548 char *firstChessProgramNames;
549 char *secondChessProgramNames;
551 WindowPlacement wpMain;
552 WindowPlacement wpConsole;
553 WindowPlacement wpComment;
554 WindowPlacement wpMoveHistory;
555 WindowPlacement wpEvalGraph;
556 WindowPlacement wpEngineOutput;
557 WindowPlacement wpGameList;
558 WindowPlacement wpTags;
560 extern Widget shells[];
561 extern Boolean shellUp[];
565 Pixmap pieceBitmap[2][(int)BlackPawn];
566 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
567 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
568 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
569 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
570 Pixmap xpmBoardBitmap[2];
571 int useImages, useImageSqs, useTexture, textureW[2], textureH[2];
572 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
573 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
574 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
575 XImage *ximLightSquare, *ximDarkSquare;
578 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
579 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
581 #define White(piece) ((int)(piece) < (int)BlackPawn)
583 /* Variables for doing smooth animation. This whole thing
584 would be much easier if the board was double-buffered,
585 but that would require a fairly major rewrite. */
590 GC blitGC, pieceGC, outlineGC;
591 XPoint startSquare, prevFrame, mouseDelta;
595 int startBoardX, startBoardY;
598 /* There can be two pieces being animated at once: a player
599 can begin dragging a piece before the remote opponent has moved. */
601 static AnimState game, player;
603 /* Bitmaps for use as masks when drawing XPM pieces.
604 Need one for each black and white piece. */
605 static Pixmap xpmMask[BlackKing + 1];
607 /* This magic number is the number of intermediate frames used
608 in each half of the animation. For short moves it's reduced
609 by 1. The total number of frames will be factor * 2 + 1. */
612 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
614 MenuItem fileMenu[] = {
615 {N_("New Game Ctrl+N"), "New Game", ResetProc},
616 {N_("New Shuffle Game ..."), "New Shuffle Game", ShuffleMenuProc},
617 {N_("New Variant ... Alt+Shift+V"), "New Variant", NewVariantProc}, // [HGM] variant: not functional yet
618 {"----", NULL, NothingProc},
619 {N_("Load Game Ctrl+O"), "Load Game", LoadGameProc},
620 {N_("Load Position Ctrl+Shift+O"), "Load Position", LoadPositionProc},
621 // {N_("Load Next Game"), "Load Next Game", LoadNextGameProc},
622 // {N_("Load Previous Game"), "Load Previous Game", LoadPrevGameProc},
623 // {N_("Reload Same Game"), "Reload Same Game", ReloadGameProc},
624 {N_("Next Position Shift+PgDn"), "Load Next Position", LoadNextPositionProc},
625 {N_("Prev Position Shift+PgUp"), "Load Previous Position", LoadPrevPositionProc},
626 {"----", NULL, NothingProc},
627 // {N_("Reload Same Position"), "Reload Same Position", ReloadPositionProc},
628 {N_("Save Game Ctrl+S"), "Save Game", SaveGameProc},
629 {N_("Save Position Ctrl+Shift+S"), "Save Position", SavePositionProc},
630 {"----", NULL, NothingProc},
631 {N_("Mail Move"), "Mail Move", MailMoveProc},
632 {N_("Reload CMail Message"), "Reload CMail Message", ReloadCmailMsgProc},
633 {"----", NULL, NothingProc},
634 {N_("Quit Ctr+Q"), "Exit", QuitProc},
638 MenuItem editMenu[] = {
639 {N_("Copy Game Ctrl+C"), "Copy Game", CopyGameProc},
640 {N_("Copy Position Ctrl+Shift+C"), "Copy Position", CopyPositionProc},
641 {N_("Copy Game List"), "Copy Game List", CopyGameListProc},
642 {"----", NULL, NothingProc},
643 {N_("Paste Game Ctrl+V"), "Paste Game", PasteGameProc},
644 {N_("Paste Position Ctrl+Shift+V"), "Paste Position", PastePositionProc},
645 {"----", NULL, NothingProc},
646 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
647 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
648 {N_("Edit Tags"), "Edit Tags", EditTagsProc},
649 {N_("Edit Comment"), "Edit Comment", EditCommentProc},
650 {N_("Edit Book"), "Edit Book", EditBookProc},
651 {"----", NULL, NothingProc},
652 {N_("Revert Home"), "Revert", RevertProc},
653 {N_("Annotate"), "Annotate", AnnotateProc},
654 {N_("Truncate Game End"), "Truncate Game", TruncateGameProc},
655 {"----", NULL, NothingProc},
656 {N_("Backward Alt+Left"), "Backward", BackwardProc},
657 {N_("Forward Alt+Right"), "Forward", ForwardProc},
658 {N_("Back to Start Alt+Home"), "Back to Start", ToStartProc},
659 {N_("Forward to End Alt+End"), "Forward to End", ToEndProc},
663 MenuItem viewMenu[] = {
664 {N_("Flip View F2"), "Flip View", FlipViewProc},
665 {"----", NULL, NothingProc},
666 {N_("Engine Output Alt+Shift+O"), "Show Engine Output", EngineOutputProc},
667 {N_("Move History Alt+Shift+H"), "Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
668 {N_("Evaluation Graph Alt+Shift+E"), "Show Evaluation Graph", EvalGraphProc},
669 {N_("Game List Alt+Shift+G"), "Show Game List", ShowGameListProc},
670 {N_("ICS text menu"), "ICStex", IcsTextProc},
671 {"----", NULL, NothingProc},
672 {N_("Tags"), "Show Tags", EditTagsProc},
673 {N_("Comments"), "Show Comments", EditCommentProc},
674 {N_("ICS Input Box"), "ICS Input Box", IcsInputBoxProc},
675 {"----", NULL, NothingProc},
676 {N_("Board..."), "Board Options", BoardOptionsProc},
677 {N_("Game List Tags..."), "Game List", GameListOptionsPopUp},
681 MenuItem modeMenu[] = {
682 {N_("Machine White Ctrl+W"), "Machine White", MachineWhiteProc},
683 {N_("Machine Black Ctrl+B"), "Machine Black", MachineBlackProc},
684 {N_("Two Machines Ctrl+T"), "Two Machines", TwoMachinesProc},
685 {N_("Analysis Mode Ctrl+A"), "Analysis Mode", AnalyzeModeProc},
686 {N_("Analyze File Ctrl+F"), "Analyze File", AnalyzeFileProc },
687 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
688 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
689 {N_("Training"), "Training", TrainingProc},
690 {N_("ICS Client"), "ICS Client", IcsClientProc},
691 {"----", NULL, NothingProc},
692 {N_("Machine Match"), "Machine Match", MatchProc},
693 {N_("Pause Pause"), "Pause", PauseProc},
697 MenuItem actionMenu[] = {
698 {N_("Accept F3"), "Accept", AcceptProc},
699 {N_("Decline F4"), "Decline", DeclineProc},
700 {N_("Rematch F12"), "Rematch", RematchProc},
701 {"----", NULL, NothingProc},
702 {N_("Call Flag F5"), "Call Flag", CallFlagProc},
703 {N_("Draw F6"), "Draw", DrawProc},
704 {N_("Adjourn F7"), "Adjourn", AdjournProc},
705 {N_("Abort F8"),"Abort", AbortProc},
706 {N_("Resign F9"), "Resign", ResignProc},
707 {"----", NULL, NothingProc},
708 {N_("Stop Observing F10"), "Stop Observing", StopObservingProc},
709 {N_("Stop Examining F11"), "Stop Examining", StopExaminingProc},
710 {N_("Upload to Examine"), "Upload to Examine", UploadProc},
711 {"----", NULL, NothingProc},
712 {N_("Adjudicate to White"), "Adjudicate to White", AdjuWhiteProc},
713 {N_("Adjudicate to Black"), "Adjudicate to Black", AdjuBlackProc},
714 {N_("Adjudicate Draw"), "Adjudicate Draw", AdjuDrawProc},
718 MenuItem engineMenu[] = {
719 {N_("Load New Engine ..."), "Load Engine", LoadEngineProc},
720 {"----", NULL, NothingProc},
721 {N_("Engine #1 Settings ..."), "Engine #1 Settings", FirstSettingsProc},
722 {N_("Engine #2 Settings ..."), "Engine #2 Settings", SecondSettingsProc},
723 {"----", NULL, NothingProc},
724 {N_("Hint"), "Hint", HintProc},
725 {N_("Book"), "Book", BookProc},
726 {"----", NULL, NothingProc},
727 {N_("Move Now Ctrl+M"), "Move Now", MoveNowProc},
728 {N_("Retract Move Ctrl+X"), "Retract Move", RetractMoveProc},
732 MenuItem optionsMenu[] = {
733 #define OPTIONSDIALOG
735 {N_("General ..."), "General", OptionsProc},
737 {N_("Time Control ... Alt+Shift+T"), "Time Control", TimeControlProc},
738 {N_("Common Engine ... Alt+Shift+U"), "Common Engine", UciMenuProc},
739 {N_("Adjudications ... Alt+Shift+J"), "Adjudications", EngineMenuProc},
740 {N_("ICS ..."), "ICS", IcsOptionsProc},
741 {N_("Match ..."), "Match", MatchOptionsProc},
742 {N_("Load Game ..."), "Load Game", LoadOptionsProc},
743 {N_("Save Game ..."), "Save Game", SaveOptionsProc},
744 // {N_(" ..."), "", OptionsProc},
745 {N_("Game List ..."), "Game List", GameListOptionsPopUp},
746 {N_("Sounds ..."), "Sounds", SoundOptionsProc},
747 {"----", NULL, NothingProc},
748 #ifndef OPTIONSDIALOG
749 {N_("Always Queen Ctrl+Shift+Q"), "Always Queen", AlwaysQueenProc},
750 {N_("Animate Dragging"), "Animate Dragging", AnimateDraggingProc},
751 {N_("Animate Moving Ctrl+Shift+A"), "Animate Moving", AnimateMovingProc},
752 {N_("Auto Flag Ctrl+Shift+F"), "Auto Flag", AutoflagProc},
753 {N_("Auto Flip View"), "Auto Flip View", AutoflipProc},
754 {N_("Blindfold"), "Blindfold", BlindfoldProc},
755 {N_("Flash Moves"), "Flash Moves", FlashMovesProc},
757 {N_("Highlight Dragging"), "Highlight Dragging", HighlightDraggingProc},
759 {N_("Highlight Last Move"), "Highlight Last Move", HighlightLastMoveProc},
760 {N_("Highlight With Arrow"), "Arrow", HighlightArrowProc},
761 {N_("Move Sound"), "Move Sound", MoveSoundProc},
762 // {N_("ICS Alarm"), "ICS Alarm", IcsAlarmProc},
763 {N_("One-Click Moving"), "OneClick", OneClickProc},
764 {N_("Periodic Updates"), "Periodic Updates", PeriodicUpdatesProc},
765 {N_("Ponder Next Move Ctrl+Shift+P"), "Ponder Next Move", PonderNextMoveProc},
766 {N_("Popup Exit Message"), "Popup Exit Message", PopupExitMessageProc},
767 {N_("Popup Move Errors"), "Popup Move Errors", PopupMoveErrorsProc},
768 // {N_("Premove"), "Premove", PremoveProc},
769 {N_("Show Coords"), "Show Coords", ShowCoordsProc},
770 {N_("Hide Thinking Ctrl+Shift+H"), "Hide Thinking", HideThinkingProc},
771 {N_("Test Legality Ctrl+Shift+L"), "Test Legality", TestLegalityProc},
772 {"----", NULL, NothingProc},
774 {N_("Save Settings Now"), "Save Settings Now", SaveSettingsProc},
775 {N_("Save Settings on Exit"), "Save Settings on Exit", SaveOnExitProc},
779 MenuItem helpMenu[] = {
780 {N_("Info XBoard"), "Info XBoard", InfoProc},
781 {N_("Man XBoard F1"), "Man XBoard", ManProc},
782 {"----", NULL, NothingProc},
783 {N_("About XBoard"), "About XBoard", AboutProc},
788 {N_("File"), "File", fileMenu},
789 {N_("Edit"), "Edit", editMenu},
790 {N_("View"), "View", viewMenu},
791 {N_("Mode"), "Mode", modeMenu},
792 {N_("Action"), "Action", actionMenu},
793 {N_("Engine"), "Engine", engineMenu},
794 {N_("Options"), "Options", optionsMenu},
795 {N_("Help"), "Help", helpMenu},
799 #define PAUSE_BUTTON "P"
800 MenuItem buttonBar[] = {
801 {"<<", "<<", ToStartProc},
802 {"<", "<", BackwardProc},
803 {PAUSE_BUTTON, PAUSE_BUTTON, PauseProc},
804 {">", ">", ForwardProc},
805 {">>", ">>", ToEndProc},
809 #define PIECE_MENU_SIZE 18
810 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
811 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
812 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
813 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
814 N_("Empty square"), N_("Clear board") },
815 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
816 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
817 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
818 N_("Empty square"), N_("Clear board") }
820 /* must be in same order as pieceMenuStrings! */
821 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
822 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
823 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
824 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
825 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
826 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
827 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
828 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
829 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
832 #define DROP_MENU_SIZE 6
833 String dropMenuStrings[DROP_MENU_SIZE] = {
834 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
836 /* must be in same order as dropMenuStrings! */
837 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
838 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
839 WhiteRook, WhiteQueen
847 DropMenuEnables dmEnables[] = {
865 { XtNborderWidth, 0 },
866 { XtNdefaultDistance, 0 },
870 { XtNborderWidth, 0 },
871 { XtNresizable, (XtArgVal) True },
875 { XtNborderWidth, 0 },
881 { XtNjustify, (XtArgVal) XtJustifyRight },
882 { XtNlabel, (XtArgVal) "..." },
883 { XtNresizable, (XtArgVal) True },
884 { XtNresize, (XtArgVal) False }
887 Arg messageArgs[] = {
888 { XtNjustify, (XtArgVal) XtJustifyLeft },
889 { XtNlabel, (XtArgVal) "..." },
890 { XtNresizable, (XtArgVal) True },
891 { XtNresize, (XtArgVal) False }
895 { XtNborderWidth, 0 },
896 { XtNjustify, (XtArgVal) XtJustifyLeft }
899 XtResource clientResources[] = {
900 { "flashCount", "flashCount", XtRInt, sizeof(int),
901 XtOffset(AppDataPtr, flashCount), XtRImmediate,
902 (XtPointer) FLASH_COUNT },
905 XrmOptionDescRec shellOptions[] = {
906 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
907 { "-flash", "flashCount", XrmoptionNoArg, "3" },
908 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
911 XtActionsRec boardActions[] = {
912 { "DrawPosition", DrawPositionProc },
913 { "HandleUserMove", HandleUserMove },
914 { "AnimateUserMove", AnimateUserMove },
915 { "HandlePV", HandlePV },
916 { "SelectPV", SelectPV },
917 { "StopPV", StopPV },
918 { "FileNameAction", FileNameAction },
919 { "AskQuestionProc", AskQuestionProc },
920 { "AskQuestionReplyAction", AskQuestionReplyAction },
921 { "PieceMenuPopup", PieceMenuPopup },
922 { "WhiteClock", WhiteClock },
923 { "BlackClock", BlackClock },
924 { "Iconify", Iconify },
925 { "ResetProc", ResetProc },
926 { "NewVariantProc", NewVariantProc },
927 { "LoadGameProc", LoadGameProc },
928 { "LoadNextGameProc", LoadNextGameProc },
929 { "LoadPrevGameProc", LoadPrevGameProc },
930 { "LoadSelectedProc", LoadSelectedProc },
931 { "SetFilterProc", SetFilterProc },
932 { "ReloadGameProc", ReloadGameProc },
933 { "LoadPositionProc", LoadPositionProc },
934 { "LoadNextPositionProc", LoadNextPositionProc },
935 { "LoadPrevPositionProc", LoadPrevPositionProc },
936 { "ReloadPositionProc", ReloadPositionProc },
937 { "CopyPositionProc", CopyPositionProc },
938 { "PastePositionProc", PastePositionProc },
939 { "CopyGameProc", CopyGameProc },
940 { "CopyGameListProc", CopyGameListProc },
941 { "PasteGameProc", PasteGameProc },
942 { "SaveGameProc", SaveGameProc },
943 { "SavePositionProc", SavePositionProc },
944 { "MailMoveProc", MailMoveProc },
945 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
946 { "QuitProc", QuitProc },
947 { "MachineWhiteProc", MachineWhiteProc },
948 { "MachineBlackProc", MachineBlackProc },
949 { "AnalysisModeProc", AnalyzeModeProc },
950 { "AnalyzeFileProc", AnalyzeFileProc },
951 { "TwoMachinesProc", TwoMachinesProc },
952 { "IcsClientProc", IcsClientProc },
953 { "EditGameProc", EditGameProc },
954 { "EditPositionProc", EditPositionProc },
955 { "TrainingProc", EditPositionProc },
956 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
957 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
958 { "ShowGameListProc", ShowGameListProc },
959 { "ShowMoveListProc", HistoryShowProc},
960 { "EditTagsProc", EditCommentProc },
961 { "EditBookProc", EditBookProc },
962 { "EditCommentProc", EditCommentProc },
963 { "IcsInputBoxProc", IcsInputBoxProc },
964 { "PauseProc", PauseProc },
965 { "AcceptProc", AcceptProc },
966 { "DeclineProc", DeclineProc },
967 { "RematchProc", RematchProc },
968 { "CallFlagProc", CallFlagProc },
969 { "DrawProc", DrawProc },
970 { "AdjournProc", AdjournProc },
971 { "AbortProc", AbortProc },
972 { "ResignProc", ResignProc },
973 { "AdjuWhiteProc", AdjuWhiteProc },
974 { "AdjuBlackProc", AdjuBlackProc },
975 { "AdjuDrawProc", AdjuDrawProc },
976 { "TypeInProc", TypeInProc },
977 { "EnterKeyProc", EnterKeyProc },
978 { "UpKeyProc", UpKeyProc },
979 { "DownKeyProc", DownKeyProc },
980 { "StopObservingProc", StopObservingProc },
981 { "StopExaminingProc", StopExaminingProc },
982 { "UploadProc", UploadProc },
983 { "BackwardProc", BackwardProc },
984 { "ForwardProc", ForwardProc },
985 { "ToStartProc", ToStartProc },
986 { "ToEndProc", ToEndProc },
987 { "RevertProc", RevertProc },
988 { "AnnotateProc", AnnotateProc },
989 { "TruncateGameProc", TruncateGameProc },
990 { "MoveNowProc", MoveNowProc },
991 { "RetractMoveProc", RetractMoveProc },
992 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
993 { "UciMenuProc", (XtActionProc) UciMenuProc },
994 { "TimeControlProc", (XtActionProc) TimeControlProc },
995 { "FlipViewProc", FlipViewProc },
996 { "PonderNextMoveProc", PonderNextMoveProc },
997 #ifndef OPTIONSDIALOG
998 { "AlwaysQueenProc", AlwaysQueenProc },
999 { "AnimateDraggingProc", AnimateDraggingProc },
1000 { "AnimateMovingProc", AnimateMovingProc },
1001 { "AutoflagProc", AutoflagProc },
1002 { "AutoflipProc", AutoflipProc },
1003 { "BlindfoldProc", BlindfoldProc },
1004 { "FlashMovesProc", FlashMovesProc },
1006 { "HighlightDraggingProc", HighlightDraggingProc },
1008 { "HighlightLastMoveProc", HighlightLastMoveProc },
1009 // { "IcsAlarmProc", IcsAlarmProc },
1010 { "MoveSoundProc", MoveSoundProc },
1011 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
1012 { "PopupExitMessageProc", PopupExitMessageProc },
1013 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
1014 // { "PremoveProc", PremoveProc },
1015 { "ShowCoordsProc", ShowCoordsProc },
1016 { "ShowThinkingProc", ShowThinkingProc },
1017 { "HideThinkingProc", HideThinkingProc },
1018 { "TestLegalityProc", TestLegalityProc },
1020 { "SaveSettingsProc", SaveSettingsProc },
1021 { "SaveOnExitProc", SaveOnExitProc },
1022 { "InfoProc", InfoProc },
1023 { "ManProc", ManProc },
1024 { "HintProc", HintProc },
1025 { "BookProc", BookProc },
1026 { "AboutGameProc", AboutGameProc },
1027 { "AboutProc", AboutProc },
1028 { "DebugProc", DebugProc },
1029 { "NothingProc", NothingProc },
1030 { "CommentClick", (XtActionProc) CommentClick },
1031 { "CommentPopDown", (XtActionProc) CommentPopDown },
1032 { "TagsPopDown", (XtActionProc) TagsPopDown },
1033 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
1034 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
1035 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
1036 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
1037 { "GameListPopDown", (XtActionProc) GameListPopDown },
1038 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
1039 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1040 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1041 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1042 { "GenericPopDown", (XtActionProc) GenericPopDown },
1043 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1044 { "SelectMove", (XtActionProc) SelectMove },
1047 char globalTranslations[] =
1048 ":<Key>F9: ResignProc() \n \
1049 :Ctrl<Key>n: ResetProc() \n \
1050 :Meta<Key>V: NewVariantProc() \n \
1051 :Ctrl<Key>o: LoadGameProc() \n \
1052 :Meta<Key>Next: LoadNextGameProc() \n \
1053 :Meta<Key>Prior: LoadPrevGameProc() \n \
1054 :Ctrl<Key>s: SaveGameProc() \n \
1055 :Ctrl<Key>c: CopyGameProc() \n \
1056 :Ctrl<Key>v: PasteGameProc() \n \
1057 :Ctrl<Key>O: LoadPositionProc() \n \
1058 :Shift<Key>Next: LoadNextPositionProc() \n \
1059 :Shift<Key>Prior: LoadPrevPositionProc() \n \
1060 :Ctrl<Key>S: SavePositionProc() \n \
1061 :Ctrl<Key>C: CopyPositionProc() \n \
1062 :Ctrl<Key>V: PastePositionProc() \n \
1063 :Ctrl<Key>q: QuitProc() \n \
1064 :Ctrl<Key>w: MachineWhiteProc() \n \
1065 :Ctrl<Key>b: MachineBlackProc() \n \
1066 :Ctrl<Key>t: TwoMachinesProc() \n \
1067 :Ctrl<Key>a: AnalysisModeProc() \n \
1068 :Ctrl<Key>f: AnalyzeFileProc() \n \
1069 :Ctrl<Key>e: EditGameProc() \n \
1070 :Ctrl<Key>E: EditPositionProc() \n \
1071 :Meta<Key>O: EngineOutputProc() \n \
1072 :Meta<Key>E: EvalGraphProc() \n \
1073 :Meta<Key>G: ShowGameListProc() \n \
1074 :Meta<Key>H: ShowMoveListProc() \n \
1075 :<Key>Pause: PauseProc() \n \
1076 :<Key>F3: AcceptProc() \n \
1077 :<Key>F4: DeclineProc() \n \
1078 :<Key>F12: RematchProc() \n \
1079 :<Key>F5: CallFlagProc() \n \
1080 :<Key>F6: DrawProc() \n \
1081 :<Key>F7: AdjournProc() \n \
1082 :<Key>F8: AbortProc() \n \
1083 :<Key>F10: StopObservingProc() \n \
1084 :<Key>F11: StopExaminingProc() \n \
1085 :Meta Ctrl<Key>F12: DebugProc() \n \
1086 :Meta<Key>End: ToEndProc() \n \
1087 :Meta<Key>Right: ForwardProc() \n \
1088 :Meta<Key>Home: ToStartProc() \n \
1089 :Meta<Key>Left: BackwardProc() \n \
1090 :<Key>Left: BackwardProc() \n \
1091 :<Key>Right: ForwardProc() \n \
1092 :<Key>Home: RevertProc() \n \
1093 :<Key>End: TruncateGameProc() \n \
1094 :Ctrl<Key>m: MoveNowProc() \n \
1095 :Ctrl<Key>x: RetractMoveProc() \n \
1096 :Meta<Key>J: EngineMenuProc() \n \
1097 :Meta<Key>U: UciMenuProc() \n \
1098 :Meta<Key>T: TimeControlProc() \n \
1099 :Ctrl<Key>P: PonderNextMoveProc() \n "
1100 #ifndef OPTIONSDIALOG
1102 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1103 :Ctrl<Key>F: AutoflagProc() \n \
1104 :Ctrl<Key>A: AnimateMovingProc() \n \
1105 :Ctrl<Key>L: TestLegalityProc() \n \
1106 :Ctrl<Key>H: HideThinkingProc() \n "
1109 :<Key>-: Iconify() \n \
1110 :<Key>F1: ManProc() \n \
1111 :<Key>F2: FlipViewProc() \n \
1112 <KeyDown>.: BackwardProc() \n \
1113 <KeyUp>.: ForwardProc() \n \
1114 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1115 \"Send to chess program:\",,1) \n \
1116 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1117 \"Send to second chess program:\",,2) \n";
1119 char boardTranslations[] =
1120 "<Btn1Down>: HandleUserMove(0) \n \
1121 Shift<Btn1Up>: HandleUserMove(1) \n \
1122 <Btn1Up>: HandleUserMove(0) \n \
1123 <Btn1Motion>: AnimateUserMove() \n \
1124 <Btn3Motion>: HandlePV() \n \
1125 <Btn3Up>: PieceMenuPopup(menuB) \n \
1126 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1127 PieceMenuPopup(menuB) \n \
1128 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1129 PieceMenuPopup(menuW) \n \
1130 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1131 PieceMenuPopup(menuW) \n \
1132 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1133 PieceMenuPopup(menuB) \n";
1135 char whiteTranslations[] =
1136 "Shift<BtnDown>: WhiteClock(1)\n \
1137 <BtnDown>: WhiteClock(0)\n";
1138 char blackTranslations[] =
1139 "Shift<BtnDown>: BlackClock(1)\n \
1140 <BtnDown>: BlackClock(0)\n";
1142 char ICSInputTranslations[] =
1143 "<Key>Up: UpKeyProc() \n "
1144 "<Key>Down: DownKeyProc() \n "
1145 "<Key>Return: EnterKeyProc() \n";
1147 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1148 // as the widget is destroyed before the up-click can call extend-end
1149 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1151 String xboardResources[] = {
1152 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1153 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1154 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1159 /* Max possible square size */
1160 #define MAXSQSIZE 256
1162 static int xpm_avail[MAXSQSIZE];
1164 #ifdef HAVE_DIR_STRUCT
1166 /* Extract piece size from filename */
1168 xpm_getsize(name, len, ext)
1179 if ((p=strchr(name, '.')) == NULL ||
1180 StrCaseCmp(p+1, ext) != 0)
1186 while (*p && isdigit(*p))
1193 /* Setup xpm_avail */
1195 xpm_getavail(dirname, ext)
1203 for (i=0; i<MAXSQSIZE; ++i)
1206 if (appData.debugMode)
1207 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1209 dir = opendir(dirname);
1212 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1213 programName, dirname);
1217 while ((ent=readdir(dir)) != NULL) {
1218 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1219 if (i > 0 && i < MAXSQSIZE)
1229 xpm_print_avail(fp, ext)
1235 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1236 for (i=1; i<MAXSQSIZE; ++i) {
1242 /* Return XPM piecesize closest to size */
1244 xpm_closest_to(dirname, size, ext)
1250 int sm_diff = MAXSQSIZE;
1254 xpm_getavail(dirname, ext);
1256 if (appData.debugMode)
1257 xpm_print_avail(stderr, ext);
1259 for (i=1; i<MAXSQSIZE; ++i) {
1262 diff = (diff<0) ? -diff : diff;
1263 if (diff < sm_diff) {
1271 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1277 #else /* !HAVE_DIR_STRUCT */
1278 /* If we are on a system without a DIR struct, we can't
1279 read the directory, so we can't collect a list of
1280 filenames, etc., so we can't do any size-fitting. */
1282 xpm_closest_to(dirname, size, ext)
1287 fprintf(stderr, _("\
1288 Warning: No DIR structure found on this system --\n\
1289 Unable to autosize for XPM/XIM pieces.\n\
1290 Please report this error to %s.\n\
1291 Include system type & operating system in message.\n"), PACKAGE_BUGREPORT););
1294 #endif /* HAVE_DIR_STRUCT */
1296 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1297 "magenta", "cyan", "white" };
1301 TextColors textColors[(int)NColorClasses];
1303 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1305 parse_color(str, which)
1309 char *p, buf[100], *d;
1312 if (strlen(str) > 99) /* watch bounds on buf */
1317 for (i=0; i<which; ++i) {
1324 /* Could be looking at something like:
1326 .. in which case we want to stop on a comma also */
1327 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1331 return -1; /* Use default for empty field */
1334 if (which == 2 || isdigit(*p))
1337 while (*p && isalpha(*p))
1342 for (i=0; i<8; ++i) {
1343 if (!StrCaseCmp(buf, cnames[i]))
1344 return which? (i+40) : (i+30);
1346 if (!StrCaseCmp(buf, "default")) return -1;
1348 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1353 parse_cpair(cc, str)
1357 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1358 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1363 /* bg and attr are optional */
1364 textColors[(int)cc].bg = parse_color(str, 1);
1365 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1366 textColors[(int)cc].attr = 0;
1372 /* Arrange to catch delete-window events */
1373 Atom wm_delete_window;
1375 CatchDeleteWindow(Widget w, String procname)
1378 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1379 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1380 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1387 XtSetArg(args[0], XtNiconic, False);
1388 XtSetValues(shellWidget, args, 1);
1390 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1393 //---------------------------------------------------------------------------------------------------------
1394 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1397 #define CW_USEDEFAULT (1<<31)
1398 #define ICS_TEXT_MENU_SIZE 90
1399 #define DEBUG_FILE "xboard.debug"
1400 #define SetCurrentDirectory chdir
1401 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1405 // these two must some day move to frontend.h, when they are implemented
1406 Boolean GameListIsUp();
1408 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1411 // front-end part of option handling
1413 // [HGM] This platform-dependent table provides the location for storing the color info
1414 extern char *crWhite, * crBlack;
1418 &appData.whitePieceColor,
1419 &appData.blackPieceColor,
1420 &appData.lightSquareColor,
1421 &appData.darkSquareColor,
1422 &appData.highlightSquareColor,
1423 &appData.premoveHighlightColor,
1424 &appData.lowTimeWarningColor,
1435 // [HGM] font: keep a font for each square size, even non-stndard ones
1436 #define NUM_SIZES 18
1437 #define MAX_SIZE 130
1438 Boolean fontIsSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1439 char *fontTable[NUM_FONTS][MAX_SIZE];
1442 ParseFont(char *name, int number)
1443 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1445 if(sscanf(name, "size%d:", &size)) {
1446 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1447 // defer processing it until we know if it matches our board size
1448 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1449 fontTable[number][size] = strdup(strchr(name, ':')+1);
1450 fontValid[number][size] = True;
1455 case 0: // CLOCK_FONT
1456 appData.clockFont = strdup(name);
1458 case 1: // MESSAGE_FONT
1459 appData.font = strdup(name);
1461 case 2: // COORD_FONT
1462 appData.coordFont = strdup(name);
1467 fontIsSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1472 { // only 2 fonts currently
1473 appData.clockFont = CLOCK_FONT_NAME;
1474 appData.coordFont = COORD_FONT_NAME;
1475 appData.font = DEFAULT_FONT_NAME;
1480 { // no-op, until we identify the code for this already in XBoard and move it here
1484 ParseColor(int n, char *name)
1485 { // in XBoard, just copy the color-name string
1486 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1490 ParseTextAttribs(ColorClass cc, char *s)
1492 (&appData.colorShout)[cc] = strdup(s);
1496 ParseBoardSize(void *addr, char *name)
1498 appData.boardSize = strdup(name);
1503 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1507 SetCommPortDefaults()
1508 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1511 // [HGM] args: these three cases taken out to stay in front-end
1513 SaveFontArg(FILE *f, ArgDescriptor *ad)
1516 int i, n = (int)(intptr_t)ad->argLoc;
1518 case 0: // CLOCK_FONT
1519 name = appData.clockFont;
1521 case 1: // MESSAGE_FONT
1522 name = appData.font;
1524 case 2: // COORD_FONT
1525 name = appData.coordFont;
1530 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1531 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1532 fontTable[n][squareSize] = strdup(name);
1533 fontValid[n][squareSize] = True;
1536 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1537 fprintf(f, OPTCHAR "%s" SEPCHAR "\"size%d:%s\"\n", ad->argName, i, fontTable[n][i]);
1542 { // nothing to do, as the sounds are at all times represented by their text-string names already
1546 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1547 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1548 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
1552 SaveColor(FILE *f, ArgDescriptor *ad)
1553 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1554 if(colorVariable[(int)(intptr_t)ad->argLoc])
1555 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
1559 SaveBoardSize(FILE *f, char *name, void *addr)
1560 { // wrapper to shield back-end from BoardSize & sizeInfo
1561 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1565 ParseCommPortSettings(char *s)
1566 { // no such option in XBoard (yet)
1569 extern Widget engineOutputShell;
1572 GetActualPlacement(Widget wg, WindowPlacement *wp)
1582 XtSetArg(args[i], XtNx, &x); i++;
1583 XtSetArg(args[i], XtNy, &y); i++;
1584 XtSetArg(args[i], XtNwidth, &w); i++;
1585 XtSetArg(args[i], XtNheight, &h); i++;
1586 XtGetValues(wg, args, i);
1595 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1596 // In XBoard this will have to wait until awareness of window parameters is implemented
1597 GetActualPlacement(shellWidget, &wpMain);
1598 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput);
1599 if(MoveHistoryIsUp()) GetActualPlacement(shells[7], &wpMoveHistory);
1600 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1601 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1602 if(shellUp[1]) GetActualPlacement(shells[1], &wpComment);
1603 if(shellUp[2]) GetActualPlacement(shells[2], &wpTags);
1607 PrintCommPortSettings(FILE *f, char *name)
1608 { // This option does not exist in XBoard
1612 MySearchPath(char *installDir, char *name, char *fullname)
1613 { // just append installDir and name. Perhaps ExpandPath should be used here?
1614 name = ExpandPathName(name);
1615 if(name && name[0] == '/')
1616 safeStrCpy(fullname, name, MSG_SIZ );
1618 sprintf(fullname, "%s%c%s", installDir, '/', name);
1624 MyGetFullPathName(char *name, char *fullname)
1625 { // should use ExpandPath?
1626 name = ExpandPathName(name);
1627 safeStrCpy(fullname, name, MSG_SIZ );
1632 EnsureOnScreen(int *x, int *y, int minX, int minY)
1639 { // [HGM] args: allows testing if main window is realized from back-end
1640 return xBoardWindow != 0;
1644 PopUpStartupDialog()
1645 { // start menu not implemented in XBoard
1649 ConvertToLine(int argc, char **argv)
1651 static char line[128*1024], buf[1024];
1655 for(i=1; i<argc; i++)
1657 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') || argv[i][0] == NULLCHAR)
1658 && argv[i][0] != '{' )
1659 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1661 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1662 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1665 line[strlen(line)-1] = NULLCHAR;
1669 //--------------------------------------------------------------------------------------------
1671 extern Boolean twoBoards, partnerUp;
1674 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1676 #define BoardSize int
1677 void InitDrawingSizes(BoardSize boardSize, int flags)
1678 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1679 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1681 XtGeometryResult gres;
1684 if(!formWidget) return;
1687 * Enable shell resizing.
1689 shellArgs[0].value = (XtArgVal) &w;
1690 shellArgs[1].value = (XtArgVal) &h;
1691 XtGetValues(shellWidget, shellArgs, 2);
1693 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1694 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1695 XtSetValues(shellWidget, &shellArgs[2], 4);
1697 XtSetArg(args[0], XtNdefaultDistance, &sep);
1698 XtGetValues(formWidget, args, 1);
1700 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1701 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1702 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1704 hOffset = boardWidth + 10;
1705 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1706 secondSegments[i] = gridSegments[i];
1707 secondSegments[i].x1 += hOffset;
1708 secondSegments[i].x2 += hOffset;
1711 XtSetArg(args[0], XtNwidth, boardWidth);
1712 XtSetArg(args[1], XtNheight, boardHeight);
1713 XtSetValues(boardWidget, args, 2);
1715 timerWidth = (boardWidth - sep) / 2;
1716 XtSetArg(args[0], XtNwidth, timerWidth);
1717 XtSetValues(whiteTimerWidget, args, 1);
1718 XtSetValues(blackTimerWidget, args, 1);
1720 XawFormDoLayout(formWidget, False);
1722 if (appData.titleInWindow) {
1724 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1725 XtSetArg(args[i], XtNheight, &h); i++;
1726 XtGetValues(titleWidget, args, i);
1728 w = boardWidth - 2*bor;
1730 XtSetArg(args[0], XtNwidth, &w);
1731 XtGetValues(menuBarWidget, args, 1);
1732 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1735 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1736 if (gres != XtGeometryYes && appData.debugMode) {
1738 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1739 programName, gres, w, h, wr, hr);
1743 XawFormDoLayout(formWidget, True);
1746 * Inhibit shell resizing.
1748 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1749 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1750 shellArgs[4].value = shellArgs[2].value = w;
1751 shellArgs[5].value = shellArgs[3].value = h;
1752 XtSetValues(shellWidget, &shellArgs[0], 6);
1754 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1757 for(i=0; i<4; i++) {
1759 for(p=0; p<=(int)WhiteKing; p++)
1760 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1761 if(gameInfo.variant == VariantShogi) {
1762 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1763 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1764 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1765 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1766 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1769 if(gameInfo.variant == VariantGothic) {
1770 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1773 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1774 xpmPieceBitmap[i][(int)WhiteAngel] = xpmPieceBitmap2[i][(int)WhiteFalcon];
1775 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1778 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1779 for(p=0; p<=(int)WhiteKing; p++)
1780 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1781 if(gameInfo.variant == VariantShogi) {
1782 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1783 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1784 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1785 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1786 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1789 if(gameInfo.variant == VariantGothic) {
1790 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1793 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1794 ximMaskPm[(int)WhiteAngel] = ximMaskPm2[(int)WhiteFalcon];
1795 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1800 for(i=0; i<2; i++) {
1802 for(p=0; p<=(int)WhiteKing; p++)
1803 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1804 if(gameInfo.variant == VariantShogi) {
1805 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1806 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1807 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1808 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1809 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1812 if(gameInfo.variant == VariantGothic) {
1813 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1816 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1817 pieceBitmap[i][(int)WhiteAngel] = pieceBitmap2[i][(int)WhiteFalcon];
1818 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1828 void ParseIcsTextColors()
1829 { // [HGM] tken out of main(), so it can be called from ICS-Options dialog
1830 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1831 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1832 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1833 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1834 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1835 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1836 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1837 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1838 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1839 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1841 if (appData.colorize) {
1843 _("%s: can't parse color names; disabling colorization\n"),
1846 appData.colorize = FALSE;
1851 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
1852 XrmValue vFrom, vTo;
1853 int forceMono = False;
1855 if (!appData.monoMode) {
1856 vFrom.addr = (caddr_t) appData.lightSquareColor;
1857 vFrom.size = strlen(appData.lightSquareColor);
1858 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1859 if (vTo.addr == NULL) {
1860 appData.monoMode = True;
1863 lightSquareColor = *(Pixel *) vTo.addr;
1866 if (!appData.monoMode) {
1867 vFrom.addr = (caddr_t) appData.darkSquareColor;
1868 vFrom.size = strlen(appData.darkSquareColor);
1869 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1870 if (vTo.addr == NULL) {
1871 appData.monoMode = True;
1874 darkSquareColor = *(Pixel *) vTo.addr;
1877 if (!appData.monoMode) {
1878 vFrom.addr = (caddr_t) appData.whitePieceColor;
1879 vFrom.size = strlen(appData.whitePieceColor);
1880 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1881 if (vTo.addr == NULL) {
1882 appData.monoMode = True;
1885 whitePieceColor = *(Pixel *) vTo.addr;
1888 if (!appData.monoMode) {
1889 vFrom.addr = (caddr_t) appData.blackPieceColor;
1890 vFrom.size = strlen(appData.blackPieceColor);
1891 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1892 if (vTo.addr == NULL) {
1893 appData.monoMode = True;
1896 blackPieceColor = *(Pixel *) vTo.addr;
1900 if (!appData.monoMode) {
1901 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1902 vFrom.size = strlen(appData.highlightSquareColor);
1903 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1904 if (vTo.addr == NULL) {
1905 appData.monoMode = True;
1908 highlightSquareColor = *(Pixel *) vTo.addr;
1912 if (!appData.monoMode) {
1913 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1914 vFrom.size = strlen(appData.premoveHighlightColor);
1915 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1916 if (vTo.addr == NULL) {
1917 appData.monoMode = True;
1920 premoveHighlightColor = *(Pixel *) vTo.addr;
1928 { // [HGM] taken out of main
1930 if (appData.monoMode && // [HGM] no sense to go on to certain doom
1931 (appData.bitmapDirectory == NULL || appData.bitmapDirectory[0] == NULLCHAR))
1932 appData.bitmapDirectory = DEF_BITMAP_DIR;
1934 if (appData.bitmapDirectory[0] != NULLCHAR) {
1938 CreateXPMBoard(appData.liteBackTextureFile, 1);
1939 CreateXPMBoard(appData.darkBackTextureFile, 0);
1943 /* Create regular pieces */
1944 if (!useImages) CreatePieces();
1953 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1954 XSetWindowAttributes window_attributes;
1956 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1957 XrmValue vFrom, vTo;
1958 XtGeometryResult gres;
1961 int forceMono = False;
1963 srandom(time(0)); // [HGM] book: make random truly random
1965 setbuf(stdout, NULL);
1966 setbuf(stderr, NULL);
1969 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1970 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1974 programName = strrchr(argv[0], '/');
1975 if (programName == NULL)
1976 programName = argv[0];
1981 XtSetLanguageProc(NULL, NULL, NULL);
1982 bindtextdomain(PACKAGE, LOCALEDIR);
1983 textdomain(PACKAGE);
1987 XtAppInitialize(&appContext, "XBoard", shellOptions,
1988 XtNumber(shellOptions),
1989 &argc, argv, xboardResources, NULL, 0);
1990 appData.boardSize = "";
1991 InitAppData(ConvertToLine(argc, argv));
1993 if (p == NULL) p = "/tmp";
1994 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1995 gameCopyFilename = (char*) malloc(i);
1996 gamePasteFilename = (char*) malloc(i);
1997 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1998 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
2000 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
2001 clientResources, XtNumber(clientResources),
2004 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
2005 static char buf[MSG_SIZ];
2006 EscapeExpand(buf, appData.firstInitString);
2007 appData.firstInitString = strdup(buf);
2008 EscapeExpand(buf, appData.secondInitString);
2009 appData.secondInitString = strdup(buf);
2010 EscapeExpand(buf, appData.firstComputerString);
2011 appData.firstComputerString = strdup(buf);
2012 EscapeExpand(buf, appData.secondComputerString);
2013 appData.secondComputerString = strdup(buf);
2016 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
2019 if (chdir(chessDir) != 0) {
2020 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
2026 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
2027 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
2028 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
2029 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
2032 setbuf(debugFP, NULL);
2036 if (appData.debugMode) {
2037 fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
2041 /* [HGM,HR] make sure board size is acceptable */
2042 if(appData.NrFiles > BOARD_FILES ||
2043 appData.NrRanks > BOARD_RANKS )
2044 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
2047 /* This feature does not work; animation needs a rewrite */
2048 appData.highlightDragging = FALSE;
2052 xDisplay = XtDisplay(shellWidget);
2053 xScreen = DefaultScreen(xDisplay);
2054 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
2056 gameInfo.variant = StringToVariant(appData.variant);
2057 InitPosition(FALSE);
2060 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
2062 if (isdigit(appData.boardSize[0])) {
2063 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
2064 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
2065 &fontPxlSize, &smallLayout, &tinyLayout);
2067 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
2068 programName, appData.boardSize);
2072 /* Find some defaults; use the nearest known size */
2073 SizeDefaults *szd, *nearest;
2074 int distance = 99999;
2075 nearest = szd = sizeDefaults;
2076 while (szd->name != NULL) {
2077 if (abs(szd->squareSize - squareSize) < distance) {
2079 distance = abs(szd->squareSize - squareSize);
2080 if (distance == 0) break;
2084 if (i < 2) lineGap = nearest->lineGap;
2085 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
2086 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
2087 if (i < 5) fontPxlSize = nearest->fontPxlSize;
2088 if (i < 6) smallLayout = nearest->smallLayout;
2089 if (i < 7) tinyLayout = nearest->tinyLayout;
2092 SizeDefaults *szd = sizeDefaults;
2093 if (*appData.boardSize == NULLCHAR) {
2094 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
2095 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
2098 if (szd->name == NULL) szd--;
2099 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
2101 while (szd->name != NULL &&
2102 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
2103 if (szd->name == NULL) {
2104 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
2105 programName, appData.boardSize);
2109 squareSize = szd->squareSize;
2110 lineGap = szd->lineGap;
2111 clockFontPxlSize = szd->clockFontPxlSize;
2112 coordFontPxlSize = szd->coordFontPxlSize;
2113 fontPxlSize = szd->fontPxlSize;
2114 smallLayout = szd->smallLayout;
2115 tinyLayout = szd->tinyLayout;
2116 // [HGM] font: use defaults from settings file if available and not overruled
2118 if(!fontIsSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
2119 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
2120 if(!fontIsSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
2121 appData.font = fontTable[MESSAGE_FONT][squareSize];
2122 if(!fontIsSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
2123 appData.coordFont = fontTable[COORD_FONT][squareSize];
2125 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
2126 if (strlen(appData.pixmapDirectory) > 0) {
2127 p = ExpandPathName(appData.pixmapDirectory);
2129 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
2130 appData.pixmapDirectory);
2133 if (appData.debugMode) {
2134 fprintf(stderr, _("\
2135 XBoard square size (hint): %d\n\
2136 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
2138 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
2139 if (appData.debugMode) {
2140 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
2143 defaultLineGap = lineGap;
2144 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
2146 /* [HR] height treated separately (hacked) */
2147 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
2148 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
2149 if (appData.showJail == 1) {
2150 /* Jail on top and bottom */
2151 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2152 XtSetArg(boardArgs[2], XtNheight,
2153 boardHeight + 2*(lineGap + squareSize));
2154 } else if (appData.showJail == 2) {
2156 XtSetArg(boardArgs[1], XtNwidth,
2157 boardWidth + 2*(lineGap + squareSize));
2158 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2161 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2162 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2166 * Determine what fonts to use.
2169 appData.font = InsertPxlSize(appData.font, fontPxlSize);
2170 appData.clockFont = InsertPxlSize(appData.clockFont, clockFontPxlSize);
2171 appData.coordFont = InsertPxlSize(appData.coordFont, coordFontPxlSize);
2172 fontSet = CreateFontSet(appData.font);
2173 clockFontSet = CreateFontSet(appData.clockFont);
2175 /* For the coordFont, use the 0th font of the fontset. */
2176 XFontSet coordFontSet = CreateFontSet(appData.coordFont);
2177 XFontStruct **font_struct_list;
2178 char **font_name_list;
2179 XFontsOfFontSet(coordFontSet, &font_struct_list, &font_name_list);
2180 coordFontID = XLoadFont(xDisplay, font_name_list[0]);
2181 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2184 appData.font = FindFont(appData.font, fontPxlSize);
2185 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2186 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2187 clockFontID = XLoadFont(xDisplay, appData.clockFont);
2188 clockFontStruct = XQueryFont(xDisplay, clockFontID);
2189 coordFontID = XLoadFont(xDisplay, appData.coordFont);
2190 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2192 countFontID = coordFontID; // [HGM] holdings
2193 countFontStruct = coordFontStruct;
2195 xdb = XtDatabase(xDisplay);
2197 XrmPutLineResource(&xdb, "*international: True");
2198 vTo.size = sizeof(XFontSet);
2199 vTo.addr = (XtPointer) &fontSet;
2200 XrmPutResource(&xdb, "*fontSet", XtRFontSet, &vTo);
2202 XrmPutStringResource(&xdb, "*font", appData.font);
2206 * Detect if there are not enough colors available and adapt.
2208 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2209 appData.monoMode = True;
2212 forceMono = MakeColors();
2215 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2217 appData.monoMode = True;
2220 if (appData.lowTimeWarning && !appData.monoMode) {
2221 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2222 vFrom.size = strlen(appData.lowTimeWarningColor);
2223 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2224 if (vTo.addr == NULL)
2225 appData.monoMode = True;
2227 lowTimeWarningColor = *(Pixel *) vTo.addr;
2230 if (appData.monoMode && appData.debugMode) {
2231 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2232 (unsigned long) XWhitePixel(xDisplay, xScreen),
2233 (unsigned long) XBlackPixel(xDisplay, xScreen));
2236 ParseIcsTextColors();
2237 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2238 textColors[ColorNone].attr = 0;
2240 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2246 layoutName = "tinyLayout";
2247 } else if (smallLayout) {
2248 layoutName = "smallLayout";
2250 layoutName = "normalLayout";
2252 /* Outer layoutWidget is there only to provide a name for use in
2253 resources that depend on the layout style */
2255 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2256 layoutArgs, XtNumber(layoutArgs));
2258 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2259 formArgs, XtNumber(formArgs));
2260 XtSetArg(args[0], XtNdefaultDistance, &sep);
2261 XtGetValues(formWidget, args, 1);
2264 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2265 XtSetArg(args[0], XtNtop, XtChainTop);
2266 XtSetArg(args[1], XtNbottom, XtChainTop);
2267 XtSetArg(args[2], XtNright, XtChainLeft);
2268 XtSetValues(menuBarWidget, args, 3);
2270 widgetList[j++] = whiteTimerWidget =
2271 XtCreateWidget("whiteTime", labelWidgetClass,
2272 formWidget, timerArgs, XtNumber(timerArgs));
2274 XtSetArg(args[0], XtNfontSet, clockFontSet);
2276 XtSetArg(args[0], XtNfont, clockFontStruct);
2278 XtSetArg(args[1], XtNtop, XtChainTop);
2279 XtSetArg(args[2], XtNbottom, XtChainTop);
2280 XtSetValues(whiteTimerWidget, args, 3);
2282 widgetList[j++] = blackTimerWidget =
2283 XtCreateWidget("blackTime", labelWidgetClass,
2284 formWidget, timerArgs, XtNumber(timerArgs));
2286 XtSetArg(args[0], XtNfontSet, clockFontSet);
2288 XtSetArg(args[0], XtNfont, clockFontStruct);
2290 XtSetArg(args[1], XtNtop, XtChainTop);
2291 XtSetArg(args[2], XtNbottom, XtChainTop);
2292 XtSetValues(blackTimerWidget, args, 3);
2294 if (appData.titleInWindow) {
2295 widgetList[j++] = titleWidget =
2296 XtCreateWidget("title", labelWidgetClass, formWidget,
2297 titleArgs, XtNumber(titleArgs));
2298 XtSetArg(args[0], XtNtop, XtChainTop);
2299 XtSetArg(args[1], XtNbottom, XtChainTop);
2300 XtSetValues(titleWidget, args, 2);
2303 if (appData.showButtonBar) {
2304 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2305 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2306 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2307 XtSetArg(args[2], XtNtop, XtChainTop);
2308 XtSetArg(args[3], XtNbottom, XtChainTop);
2309 XtSetValues(buttonBarWidget, args, 4);
2312 widgetList[j++] = messageWidget =
2313 XtCreateWidget("message", labelWidgetClass, formWidget,
2314 messageArgs, XtNumber(messageArgs));
2315 XtSetArg(args[0], XtNtop, XtChainTop);
2316 XtSetArg(args[1], XtNbottom, XtChainTop);
2317 XtSetValues(messageWidget, args, 2);
2319 widgetList[j++] = boardWidget =
2320 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2321 XtNumber(boardArgs));
2323 XtManageChildren(widgetList, j);
2325 timerWidth = (boardWidth - sep) / 2;
2326 XtSetArg(args[0], XtNwidth, timerWidth);
2327 XtSetValues(whiteTimerWidget, args, 1);
2328 XtSetValues(blackTimerWidget, args, 1);
2330 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2331 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2332 XtGetValues(whiteTimerWidget, args, 2);
2334 if (appData.showButtonBar) {
2335 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2336 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2337 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2341 * formWidget uses these constraints but they are stored
2345 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2346 XtSetValues(menuBarWidget, args, i);
2347 if (appData.titleInWindow) {
2350 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2351 XtSetValues(whiteTimerWidget, args, i);
2353 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2354 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2355 XtSetValues(blackTimerWidget, args, i);
2357 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2358 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2359 XtSetValues(titleWidget, args, i);
2361 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2362 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2363 XtSetValues(messageWidget, args, i);
2364 if (appData.showButtonBar) {
2366 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2367 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2368 XtSetValues(buttonBarWidget, args, i);
2372 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2373 XtSetValues(whiteTimerWidget, args, i);
2375 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2376 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2377 XtSetValues(blackTimerWidget, args, i);
2379 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2380 XtSetValues(titleWidget, args, i);
2382 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2383 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2384 XtSetValues(messageWidget, args, i);
2385 if (appData.showButtonBar) {
2387 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2388 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2389 XtSetValues(buttonBarWidget, args, i);
2394 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2395 XtSetValues(whiteTimerWidget, args, i);
2397 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2398 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2399 XtSetValues(blackTimerWidget, args, i);
2401 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2402 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2403 XtSetValues(messageWidget, args, i);
2404 if (appData.showButtonBar) {
2406 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2407 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2408 XtSetValues(buttonBarWidget, args, i);
2412 XtSetArg(args[0], XtNfromVert, messageWidget);
2413 XtSetArg(args[1], XtNtop, XtChainTop);
2414 XtSetArg(args[2], XtNbottom, XtChainBottom);
2415 XtSetArg(args[3], XtNleft, XtChainLeft);
2416 XtSetArg(args[4], XtNright, XtChainRight);
2417 XtSetValues(boardWidget, args, 5);
2419 XtRealizeWidget(shellWidget);
2422 XtSetArg(args[0], XtNx, wpMain.x);
2423 XtSetArg(args[1], XtNy, wpMain.y);
2424 XtSetValues(shellWidget, args, 2);
2428 * Correct the width of the message and title widgets.
2429 * It is not known why some systems need the extra fudge term.
2430 * The value "2" is probably larger than needed.
2432 XawFormDoLayout(formWidget, False);
2434 #define WIDTH_FUDGE 2
2436 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2437 XtSetArg(args[i], XtNheight, &h); i++;
2438 XtGetValues(messageWidget, args, i);
2439 if (appData.showButtonBar) {
2441 XtSetArg(args[i], XtNwidth, &w); i++;
2442 XtGetValues(buttonBarWidget, args, i);
2443 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2445 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2448 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2449 if (gres != XtGeometryYes && appData.debugMode) {
2450 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2451 programName, gres, w, h, wr, hr);
2454 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2455 /* The size used for the child widget in layout lags one resize behind
2456 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2458 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2459 if (gres != XtGeometryYes && appData.debugMode) {
2460 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2461 programName, gres, w, h, wr, hr);
2464 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2465 XtSetArg(args[1], XtNright, XtChainRight);
2466 XtSetValues(messageWidget, args, 2);
2468 if (appData.titleInWindow) {
2470 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2471 XtSetArg(args[i], XtNheight, &h); i++;
2472 XtGetValues(titleWidget, args, i);
2474 w = boardWidth - 2*bor;
2476 XtSetArg(args[0], XtNwidth, &w);
2477 XtGetValues(menuBarWidget, args, 1);
2478 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2481 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2482 if (gres != XtGeometryYes && appData.debugMode) {
2484 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2485 programName, gres, w, h, wr, hr);
2488 XawFormDoLayout(formWidget, True);
2490 xBoardWindow = XtWindow(boardWidget);
2492 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2493 // not need to go into InitDrawingSizes().
2497 * Create X checkmark bitmap and initialize option menu checks.
2499 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2500 checkmark_bits, checkmark_width, checkmark_height);
2501 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2502 #ifndef OPTIONSDIALOG
2503 if (appData.alwaysPromoteToQueen) {
2504 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2507 if (appData.animateDragging) {
2508 XtSetValues(XtNameToWidget(menuBarWidget,
2509 "menuOptions.Animate Dragging"),
2512 if (appData.animate) {
2513 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2516 if (appData.autoCallFlag) {
2517 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2520 if (appData.autoFlipView) {
2521 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2524 if (appData.blindfold) {
2525 XtSetValues(XtNameToWidget(menuBarWidget,
2526 "menuOptions.Blindfold"), args, 1);
2528 if (appData.flashCount > 0) {
2529 XtSetValues(XtNameToWidget(menuBarWidget,
2530 "menuOptions.Flash Moves"),
2534 if (appData.highlightDragging) {
2535 XtSetValues(XtNameToWidget(menuBarWidget,
2536 "menuOptions.Highlight Dragging"),
2540 if (appData.highlightLastMove) {
2541 XtSetValues(XtNameToWidget(menuBarWidget,
2542 "menuOptions.Highlight Last Move"),
2545 if (appData.highlightMoveWithArrow) {
2546 XtSetValues(XtNameToWidget(menuBarWidget,
2547 "menuOptions.Arrow"),
2550 // if (appData.icsAlarm) {
2551 // XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2554 if (appData.ringBellAfterMoves) {
2555 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2558 if (appData.oneClick) {
2559 XtSetValues(XtNameToWidget(menuBarWidget,
2560 "menuOptions.OneClick"), args, 1);
2562 if (appData.periodicUpdates) {
2563 XtSetValues(XtNameToWidget(menuBarWidget,
2564 "menuOptions.Periodic Updates"), args, 1);
2566 if (appData.ponderNextMove) {
2567 XtSetValues(XtNameToWidget(menuBarWidget,
2568 "menuOptions.Ponder Next Move"), args, 1);
2570 if (appData.popupExitMessage) {
2571 XtSetValues(XtNameToWidget(menuBarWidget,
2572 "menuOptions.Popup Exit Message"), args, 1);
2574 if (appData.popupMoveErrors) {
2575 XtSetValues(XtNameToWidget(menuBarWidget,
2576 "menuOptions.Popup Move Errors"), args, 1);
2578 // if (appData.premove) {
2579 // XtSetValues(XtNameToWidget(menuBarWidget,
2580 // "menuOptions.Premove"), args, 1);
2582 if (appData.showCoords) {
2583 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2586 if (appData.hideThinkingFromHuman) {
2587 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2590 if (appData.testLegality) {
2591 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2595 if (saveSettingsOnExit) {
2596 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2603 ReadBitmap(&wIconPixmap, "icon_white.bm",
2604 icon_white_bits, icon_white_width, icon_white_height);
2605 ReadBitmap(&bIconPixmap, "icon_black.bm",
2606 icon_black_bits, icon_black_width, icon_black_height);
2607 iconPixmap = wIconPixmap;
2609 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2610 XtSetValues(shellWidget, args, i);
2613 * Create a cursor for the board widget.
2615 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2616 XChangeWindowAttributes(xDisplay, xBoardWindow,
2617 CWCursor, &window_attributes);
2620 * Inhibit shell resizing.
2622 shellArgs[0].value = (XtArgVal) &w;
2623 shellArgs[1].value = (XtArgVal) &h;
2624 XtGetValues(shellWidget, shellArgs, 2);
2625 shellArgs[4].value = shellArgs[2].value = w;
2626 shellArgs[5].value = shellArgs[3].value = h;
2627 XtSetValues(shellWidget, &shellArgs[2], 4);
2628 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2629 marginH = h - boardHeight;
2631 CatchDeleteWindow(shellWidget, "QuitProc");
2639 if (appData.animate || appData.animateDragging)
2642 XtAugmentTranslations(formWidget,
2643 XtParseTranslationTable(globalTranslations));
2644 XtAugmentTranslations(boardWidget,
2645 XtParseTranslationTable(boardTranslations));
2646 XtAugmentTranslations(whiteTimerWidget,
2647 XtParseTranslationTable(whiteTranslations));
2648 XtAugmentTranslations(blackTimerWidget,
2649 XtParseTranslationTable(blackTranslations));
2651 /* Why is the following needed on some versions of X instead
2652 * of a translation? */
2653 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2654 (XtEventHandler) EventProc, NULL);
2656 XtAddEventHandler(formWidget, KeyPressMask, False,
2657 (XtEventHandler) MoveTypeInProc, NULL);
2659 /* [AS] Restore layout */
2660 if( wpMoveHistory.visible ) {
2664 if( wpEvalGraph.visible )
2669 if( wpEngineOutput.visible ) {
2670 EngineOutputPopUp();
2675 if (errorExitStatus == -1) {
2676 if (appData.icsActive) {
2677 /* We now wait until we see "login:" from the ICS before
2678 sending the logon script (problems with timestamp otherwise) */
2679 /*ICSInitScript();*/
2680 if (appData.icsInputBox) ICSInputBoxPopUp();
2684 signal(SIGWINCH, TermSizeSigHandler);
2686 signal(SIGINT, IntSigHandler);
2687 signal(SIGTERM, IntSigHandler);
2688 if (*appData.cmailGameName != NULLCHAR) {
2689 signal(SIGUSR1, CmailSigHandler);
2692 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2694 // XtSetKeyboardFocus(shellWidget, formWidget);
2695 XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
2697 XtAppMainLoop(appContext);
2698 if (appData.debugMode) fclose(debugFP); // [DM] debug
2702 static Boolean noEcho;
2707 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2708 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2710 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2711 unlink(gameCopyFilename);
2712 unlink(gamePasteFilename);
2713 if(noEcho) EchoOn();
2716 RETSIGTYPE TermSizeSigHandler(int sig)
2729 CmailSigHandler(sig)
2735 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2737 /* Activate call-back function CmailSigHandlerCallBack() */
2738 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2740 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2744 CmailSigHandlerCallBack(isr, closure, message, count, error)
2752 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2754 /**** end signal code ****/
2760 /* try to open the icsLogon script, either in the location given
2761 * or in the users HOME directory
2768 f = fopen(appData.icsLogon, "r");
2771 homedir = getenv("HOME");
2772 if (homedir != NULL)
2774 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2775 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2776 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2777 f = fopen(buf, "r");
2782 ProcessICSInitScript(f);
2784 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2807 if (!menuBarWidget) return;
2808 w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2810 DisplayError("menuEdit.Revert", 0);
2812 XtSetSensitive(w, !grey);
2814 w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2816 DisplayError("menuEdit.Annotate", 0);
2818 XtSetSensitive(w, !grey);
2823 SetMenuEnables(enab)
2827 if (!menuBarWidget) return;
2828 while (enab->name != NULL) {
2829 w = XtNameToWidget(menuBarWidget, enab->name);
2831 DisplayError(enab->name, 0);
2833 XtSetSensitive(w, enab->value);
2839 Enables icsEnables[] = {
2840 { "menuFile.Mail Move", False },
2841 { "menuFile.Reload CMail Message", False },
2842 { "menuMode.Machine Black", False },
2843 { "menuMode.Machine White", False },
2844 { "menuMode.Analysis Mode", False },
2845 { "menuMode.Analyze File", False },
2846 { "menuMode.Two Machines", False },
2847 { "menuMode.Machine Match", False },
2849 { "menuEngine.Hint", False },
2850 { "menuEngine.Book", False },
2851 { "menuEngine.Move Now", False },
2852 #ifndef OPTIONSDIALOG
2853 { "menuOptions.Periodic Updates", False },
2854 { "menuOptions.Hide Thinking", False },
2855 { "menuOptions.Ponder Next Move", False },
2858 { "menuEngine.Engine #1 Settings", False },
2859 { "menuEngine.Engine #2 Settings", False },
2860 { "menuEngine.Load Engine", False },
2861 { "menuEdit.Annotate", False },
2862 { "menuOptions.Match", False },
2866 Enables ncpEnables[] = {
2867 { "menuFile.Mail Move", False },
2868 { "menuFile.Reload CMail Message", False },
2869 { "menuMode.Machine White", False },
2870 { "menuMode.Machine Black", False },
2871 { "menuMode.Analysis Mode", False },
2872 { "menuMode.Analyze File", False },
2873 { "menuMode.Two Machines", False },
2874 { "menuMode.Machine Match", False },
2875 { "menuMode.ICS Client", False },
2876 { "menuView.ICStex", False },
2877 { "menuView.ICS Input Box", False },
2878 { "Action", False },
2879 { "menuEdit.Revert", False },
2880 { "menuEdit.Annotate", False },
2881 { "menuEngine.Engine #1 Settings", False },
2882 { "menuEngine.Engine #2 Settings", False },
2883 { "menuEngine.Move Now", False },
2884 { "menuEngine.Retract Move", False },
2885 { "menuOptions.ICS", False },
2886 #ifndef OPTIONSDIALOG
2887 { "menuOptions.Auto Flag", False },
2888 { "menuOptions.Auto Flip View", False },
2889 // { "menuOptions.ICS Alarm", False },
2890 { "menuOptions.Move Sound", False },
2891 { "menuOptions.Hide Thinking", False },
2892 { "menuOptions.Periodic Updates", False },
2893 { "menuOptions.Ponder Next Move", False },
2895 { "menuEngine.Hint", False },
2896 { "menuEngine.Book", False },
2900 Enables gnuEnables[] = {
2901 { "menuMode.ICS Client", False },
2902 { "menuView.ICStex", False },
2903 { "menuView.ICS Input Box", False },
2904 { "menuAction.Accept", False },
2905 { "menuAction.Decline", False },
2906 { "menuAction.Rematch", False },
2907 { "menuAction.Adjourn", False },
2908 { "menuAction.Stop Examining", False },
2909 { "menuAction.Stop Observing", False },
2910 { "menuAction.Upload to Examine", False },
2911 { "menuEdit.Revert", False },
2912 { "menuEdit.Annotate", False },
2913 { "menuOptions.ICS", False },
2915 /* The next two options rely on SetCmailMode being called *after* */
2916 /* SetGNUMode so that when GNU is being used to give hints these */
2917 /* menu options are still available */
2919 { "menuFile.Mail Move", False },
2920 { "menuFile.Reload CMail Message", False },
2921 // [HGM] The following have been added to make a switch from ncp to GNU mode possible
2922 { "menuMode.Machine White", True },
2923 { "menuMode.Machine Black", True },
2924 { "menuMode.Analysis Mode", True },
2925 { "menuMode.Analyze File", True },
2926 { "menuMode.Two Machines", True },
2927 { "menuMode.Machine Match", True },
2928 { "menuEngine.Engine #1 Settings", True },
2929 { "menuEngine.Engine #2 Settings", True },
2930 { "menuEngine.Hint", True },
2931 { "menuEngine.Book", True },
2932 { "menuEngine.Move Now", True },
2933 { "menuEngine.Retract Move", True },
2938 Enables cmailEnables[] = {
2940 { "menuAction.Call Flag", False },
2941 { "menuAction.Draw", True },
2942 { "menuAction.Adjourn", False },
2943 { "menuAction.Abort", False },
2944 { "menuAction.Stop Observing", False },
2945 { "menuAction.Stop Examining", False },
2946 { "menuFile.Mail Move", True },
2947 { "menuFile.Reload CMail Message", True },
2951 Enables trainingOnEnables[] = {
2952 { "menuMode.Edit Comment", False },
2953 { "menuMode.Pause", False },
2954 { "menuEdit.Forward", False },
2955 { "menuEdit.Backward", False },
2956 { "menuEdit.Forward to End", False },
2957 { "menuEdit.Back to Start", False },
2958 { "menuEngine.Move Now", False },
2959 { "menuEdit.Truncate Game", False },
2963 Enables trainingOffEnables[] = {
2964 { "menuMode.Edit Comment", True },
2965 { "menuMode.Pause", True },
2966 { "menuEdit.Forward", True },
2967 { "menuEdit.Backward", True },
2968 { "menuEdit.Forward to End", True },
2969 { "menuEdit.Back to Start", True },
2970 { "menuEngine.Move Now", True },
2971 { "menuEdit.Truncate Game", True },
2975 Enables machineThinkingEnables[] = {
2976 { "menuFile.Load Game", False },
2977 // { "menuFile.Load Next Game", False },
2978 // { "menuFile.Load Previous Game", False },
2979 // { "menuFile.Reload Same Game", False },
2980 { "menuEdit.Paste Game", False },
2981 { "menuFile.Load Position", False },
2982 // { "menuFile.Load Next Position", False },
2983 // { "menuFile.Load Previous Position", False },
2984 // { "menuFile.Reload Same Position", False },
2985 { "menuEdit.Paste Position", False },
2986 { "menuMode.Machine White", False },
2987 { "menuMode.Machine Black", False },
2988 { "menuMode.Two Machines", False },
2989 // { "menuMode.Machine Match", False },
2990 { "menuEngine.Retract Move", False },
2994 Enables userThinkingEnables[] = {
2995 { "menuFile.Load Game", True },
2996 // { "menuFile.Load Next Game", True },
2997 // { "menuFile.Load Previous Game", True },
2998 // { "menuFile.Reload Same Game", True },
2999 { "menuEdit.Paste Game", True },
3000 { "menuFile.Load Position", True },
3001 // { "menuFile.Load Next Position", True },
3002 // { "menuFile.Load Previous Position", True },
3003 // { "menuFile.Reload Same Position", True },
3004 { "menuEdit.Paste Position", True },
3005 { "menuMode.Machine White", True },
3006 { "menuMode.Machine Black", True },
3007 { "menuMode.Two Machines", True },
3008 // { "menuMode.Machine Match", True },
3009 { "menuEngine.Retract Move", True },
3015 SetMenuEnables(icsEnables);
3018 if (appData.zippyPlay && !appData.noChessProgram) { /* [DM] icsEngineAnalyze */
3019 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
3020 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuEngine.Engine #1 Settings"), True);
3028 SetMenuEnables(ncpEnables);
3034 SetMenuEnables(gnuEnables);
3040 SetMenuEnables(cmailEnables);
3046 SetMenuEnables(trainingOnEnables);
3047 if (appData.showButtonBar) {
3048 XtSetSensitive(buttonBarWidget, False);
3054 SetTrainingModeOff()
3056 SetMenuEnables(trainingOffEnables);
3057 if (appData.showButtonBar) {
3058 XtSetSensitive(buttonBarWidget, True);
3063 SetUserThinkingEnables()
3065 if (appData.noChessProgram) return;
3066 SetMenuEnables(userThinkingEnables);
3070 SetMachineThinkingEnables()
3072 if (appData.noChessProgram) return;
3073 SetMenuEnables(machineThinkingEnables);
3075 case MachinePlaysBlack:
3076 case MachinePlaysWhite:
3077 case TwoMachinesPlay:
3078 XtSetSensitive(XtNameToWidget(menuBarWidget,
3079 ModeToWidgetName(gameMode)), True);
3086 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
3087 #define HISTORY_SIZE 64
3088 static char *history[HISTORY_SIZE];
3089 int histIn = 0, histP = 0;
3092 SaveInHistory(char *cmd)
3094 if (history[histIn] != NULL) {
3095 free(history[histIn]);
3096 history[histIn] = NULL;
3098 if (*cmd == NULLCHAR) return;
3099 history[histIn] = StrSave(cmd);
3100 histIn = (histIn + 1) % HISTORY_SIZE;
3101 if (history[histIn] != NULL) {
3102 free(history[histIn]);
3103 history[histIn] = NULL;
3109 PrevInHistory(char *cmd)
3112 if (histP == histIn) {
3113 if (history[histIn] != NULL) free(history[histIn]);
3114 history[histIn] = StrSave(cmd);
3116 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
3117 if (newhp == histIn || history[newhp] == NULL) return NULL;
3119 return history[histP];
3125 if (histP == histIn) return NULL;
3126 histP = (histP + 1) % HISTORY_SIZE;
3127 return history[histP];
3129 // end of borrowed code
3131 #define Abs(n) ((n)<0 ? -(n) : (n))
3135 InsertPxlSize(pattern, targetPxlSize)
3139 char *base_fnt_lst, strInt[12], *p, *q;
3140 int alternatives, i, len, strIntLen;
3143 * Replace the "*" (if present) in the pixel-size slot of each
3144 * alternative with the targetPxlSize.
3148 while ((p = strchr(p, ',')) != NULL) {
3152 snprintf(strInt, sizeof(strInt), "%d", targetPxlSize);
3153 strIntLen = strlen(strInt);
3154 base_fnt_lst = calloc(1, strlen(pattern) + strIntLen * alternatives + 1);
3158 while (alternatives--) {
3159 char *comma = strchr(p, ',');
3160 for (i=0; i<14; i++) {
3161 char *hyphen = strchr(p, '-');
3163 if (comma && hyphen > comma) break;
3164 len = hyphen + 1 - p;
3165 if (i == 7 && *p == '*' && len == 2) {
3167 memcpy(q, strInt, strIntLen);
3177 len = comma + 1 - p;
3184 return base_fnt_lst;
3188 CreateFontSet(base_fnt_lst)
3192 char **missing_list;
3196 fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
3197 &missing_list, &missing_count, &def_string);
3198 if (appData.debugMode) {
3200 XFontStruct **font_struct_list;
3201 char **font_name_list;
3202 fprintf(debugFP, "Requested font set for list %s\n", base_fnt_lst);
3204 fprintf(debugFP, " got list %s, locale %s\n",
3205 XBaseFontNameListOfFontSet(fntSet),
3206 XLocaleOfFontSet(fntSet));
3207 count = XFontsOfFontSet(fntSet, &font_struct_list, &font_name_list);
3208 for (i = 0; i < count; i++) {
3209 fprintf(debugFP, " got charset %s\n", font_name_list[i]);
3212 for (i = 0; i < missing_count; i++) {
3213 fprintf(debugFP, " missing charset %s\n", missing_list[i]);
3216 if (fntSet == NULL) {
3217 fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
3222 #else // not ENABLE_NLS
3224 * Find a font that matches "pattern" that is as close as
3225 * possible to the targetPxlSize. Prefer fonts that are k
3226 * pixels smaller to fonts that are k pixels larger. The
3227 * pattern must be in the X Consortium standard format,
3228 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3229 * The return value should be freed with XtFree when no
3233 FindFont(pattern, targetPxlSize)
3237 char **fonts, *p, *best, *scalable, *scalableTail;
3238 int i, j, nfonts, minerr, err, pxlSize;
3240 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3242 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3243 programName, pattern);
3250 for (i=0; i<nfonts; i++) {
3253 if (*p != '-') continue;
3255 if (*p == NULLCHAR) break;
3256 if (*p++ == '-') j++;
3258 if (j < 7) continue;
3261 scalable = fonts[i];
3264 err = pxlSize - targetPxlSize;
3265 if (Abs(err) < Abs(minerr) ||
3266 (minerr > 0 && err < 0 && -err == minerr)) {
3272 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3273 /* If the error is too big and there is a scalable font,
3274 use the scalable font. */
3275 int headlen = scalableTail - scalable;
3276 p = (char *) XtMalloc(strlen(scalable) + 10);
3277 while (isdigit(*scalableTail)) scalableTail++;
3278 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3280 p = (char *) XtMalloc(strlen(best) + 2);
3281 safeStrCpy(p, best, strlen(best)+1 );
3283 if (appData.debugMode) {
3284 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3285 pattern, targetPxlSize, p);
3287 XFreeFontNames(fonts);
3293 { // [HGM] deletes GCs that are to be remade, to prevent resource leak;
3294 // must be called before all non-first callse to CreateGCs()
3295 XtReleaseGC(shellWidget, highlineGC);
3296 XtReleaseGC(shellWidget, lightSquareGC);
3297 XtReleaseGC(shellWidget, darkSquareGC);
3298 XtReleaseGC(shellWidget, lineGC);
3299 if (appData.monoMode) {
3300 if (DefaultDepth(xDisplay, xScreen) == 1) {
3301 XtReleaseGC(shellWidget, wbPieceGC);
3303 XtReleaseGC(shellWidget, bwPieceGC);
3306 XtReleaseGC(shellWidget, prelineGC);
3307 XtReleaseGC(shellWidget, jailSquareGC);
3308 XtReleaseGC(shellWidget, wdPieceGC);
3309 XtReleaseGC(shellWidget, wlPieceGC);
3310 XtReleaseGC(shellWidget, wjPieceGC);
3311 XtReleaseGC(shellWidget, bdPieceGC);
3312 XtReleaseGC(shellWidget, blPieceGC);
3313 XtReleaseGC(shellWidget, bjPieceGC);
3317 void CreateGCs(int redo)
3319 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3320 | GCBackground | GCFunction | GCPlaneMask;
3321 XGCValues gc_values;
3324 gc_values.plane_mask = AllPlanes;
3325 gc_values.line_width = lineGap;
3326 gc_values.line_style = LineSolid;
3327 gc_values.function = GXcopy;
3330 DeleteGCs(); // called a second time; clean up old GCs first
3331 } else { // [HGM] grid and font GCs created on first call only
3332 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3333 gc_values.background = XWhitePixel(xDisplay, xScreen);
3334 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3335 XSetFont(xDisplay, coordGC, coordFontID);
3337 // [HGM] make font for holdings counts (white on black)
3338 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3339 gc_values.background = XBlackPixel(xDisplay, xScreen);
3340 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3341 XSetFont(xDisplay, countGC, countFontID);
3343 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3344 gc_values.background = XBlackPixel(xDisplay, xScreen);
3345 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3347 if (appData.monoMode) {
3348 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3349 gc_values.background = XWhitePixel(xDisplay, xScreen);
3350 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3352 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3353 gc_values.background = XBlackPixel(xDisplay, xScreen);
3354 lightSquareGC = wbPieceGC
3355 = XtGetGC(shellWidget, value_mask, &gc_values);
3357 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3358 gc_values.background = XWhitePixel(xDisplay, xScreen);
3359 darkSquareGC = bwPieceGC
3360 = XtGetGC(shellWidget, value_mask, &gc_values);
3362 if (DefaultDepth(xDisplay, xScreen) == 1) {
3363 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3364 gc_values.function = GXcopyInverted;
3365 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3366 gc_values.function = GXcopy;
3367 if (XBlackPixel(xDisplay, xScreen) == 1) {
3368 bwPieceGC = darkSquareGC;
3369 wbPieceGC = copyInvertedGC;
3371 bwPieceGC = copyInvertedGC;
3372 wbPieceGC = lightSquareGC;
3376 gc_values.foreground = highlightSquareColor;
3377 gc_values.background = highlightSquareColor;
3378 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3380 gc_values.foreground = premoveHighlightColor;
3381 gc_values.background = premoveHighlightColor;
3382 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3384 gc_values.foreground = lightSquareColor;
3385 gc_values.background = darkSquareColor;
3386 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3388 gc_values.foreground = darkSquareColor;
3389 gc_values.background = lightSquareColor;
3390 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3392 gc_values.foreground = jailSquareColor;
3393 gc_values.background = jailSquareColor;
3394 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3396 gc_values.foreground = whitePieceColor;
3397 gc_values.background = darkSquareColor;
3398 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3400 gc_values.foreground = whitePieceColor;
3401 gc_values.background = lightSquareColor;
3402 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3404 gc_values.foreground = whitePieceColor;
3405 gc_values.background = jailSquareColor;
3406 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3408 gc_values.foreground = blackPieceColor;
3409 gc_values.background = darkSquareColor;
3410 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3412 gc_values.foreground = blackPieceColor;
3413 gc_values.background = lightSquareColor;
3414 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3416 gc_values.foreground = blackPieceColor;
3417 gc_values.background = jailSquareColor;
3418 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3422 void loadXIM(xim, xmask, filename, dest, mask)
3435 fp = fopen(filename, "rb");
3437 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3444 for (y=0; y<h; ++y) {
3445 for (x=0; x<h; ++x) {
3450 XPutPixel(xim, x, y, blackPieceColor);
3452 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3455 XPutPixel(xim, x, y, darkSquareColor);
3457 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3460 XPutPixel(xim, x, y, whitePieceColor);
3462 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3465 XPutPixel(xim, x, y, lightSquareColor);
3467 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3475 /* create Pixmap of piece */
3476 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3478 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3481 /* create Pixmap of clipmask
3482 Note: We assume the white/black pieces have the same
3483 outline, so we make only 6 masks. This is okay
3484 since the XPM clipmask routines do the same. */
3486 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3488 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3491 /* now create the 1-bit version */
3492 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3495 values.foreground = 1;
3496 values.background = 0;
3498 /* Don't use XtGetGC, not read only */
3499 maskGC = XCreateGC(xDisplay, *mask,
3500 GCForeground | GCBackground, &values);
3501 XCopyPlane(xDisplay, temp, *mask, maskGC,
3502 0, 0, squareSize, squareSize, 0, 0, 1);
3503 XFreePixmap(xDisplay, temp);
3508 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3510 void CreateXIMPieces()
3515 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3520 /* The XSynchronize calls were copied from CreatePieces.
3521 Not sure if needed, but can't hurt */
3522 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3525 /* temp needed by loadXIM() */
3526 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3527 0, 0, ss, ss, AllPlanes, XYPixmap);
3529 if (strlen(appData.pixmapDirectory) == 0) {
3533 if (appData.monoMode) {
3534 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3538 fprintf(stderr, _("\nLoading XIMs...\n"));
3540 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3541 fprintf(stderr, "%d", piece+1);
3542 for (kind=0; kind<4; kind++) {
3543 fprintf(stderr, ".");
3544 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3545 ExpandPathName(appData.pixmapDirectory),
3546 piece <= (int) WhiteKing ? "" : "w",
3547 pieceBitmapNames[piece],
3549 ximPieceBitmap[kind][piece] =
3550 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3551 0, 0, ss, ss, AllPlanes, XYPixmap);
3552 if (appData.debugMode)
3553 fprintf(stderr, _("(File:%s:) "), buf);
3554 loadXIM(ximPieceBitmap[kind][piece],
3556 &(xpmPieceBitmap2[kind][piece]),
3557 &(ximMaskPm2[piece]));
3558 if(piece <= (int)WhiteKing)
3559 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3561 fprintf(stderr," ");
3563 /* Load light and dark squares */
3564 /* If the LSQ and DSQ pieces don't exist, we will
3565 draw them with solid squares. */
3566 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3567 if (access(buf, 0) != 0) {
3571 fprintf(stderr, _("light square "));
3573 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3574 0, 0, ss, ss, AllPlanes, XYPixmap);
3575 if (appData.debugMode)
3576 fprintf(stderr, _("(File:%s:) "), buf);
3578 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3579 fprintf(stderr, _("dark square "));
3580 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3581 ExpandPathName(appData.pixmapDirectory), ss);
3582 if (appData.debugMode)
3583 fprintf(stderr, _("(File:%s:) "), buf);
3585 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3586 0, 0, ss, ss, AllPlanes, XYPixmap);
3587 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3588 xpmJailSquare = xpmLightSquare;
3590 fprintf(stderr, _("Done.\n"));
3592 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3595 static VariantClass oldVariant = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
3598 void CreateXPMBoard(char *s, int kind)
3602 if(s == NULL || *s == 0 || *s == '*') { useTexture &= ~(kind+1); return; }
3603 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3604 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3608 void FreeXPMPieces()
3609 { // [HGM] to prevent resoucre leak on calling CreaeXPMPieces() a second time,
3610 // thisroutine has to be called t free the old piece pixmaps
3612 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++)
3613 for (kind=0; kind<4; kind++) XFreePixmap(xDisplay, xpmPieceBitmap2[kind][piece]);
3615 XFreePixmap(xDisplay, xpmLightSquare);
3616 XFreePixmap(xDisplay, xpmDarkSquare);
3620 void CreateXPMPieces()
3624 u_int ss = squareSize;
3626 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3627 XpmColorSymbol symbols[4];
3628 static int redo = False;
3630 if(redo) FreeXPMPieces(); else redo = 1;
3632 /* The XSynchronize calls were copied from CreatePieces.
3633 Not sure if needed, but can't hurt */
3634 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3636 /* Setup translations so piece colors match square colors */
3637 symbols[0].name = "light_piece";
3638 symbols[0].value = appData.whitePieceColor;
3639 symbols[1].name = "dark_piece";
3640 symbols[1].value = appData.blackPieceColor;
3641 symbols[2].name = "light_square";
3642 symbols[2].value = appData.lightSquareColor;
3643 symbols[3].name = "dark_square";
3644 symbols[3].value = appData.darkSquareColor;
3646 attr.valuemask = XpmColorSymbols;
3647 attr.colorsymbols = symbols;
3648 attr.numsymbols = 4;
3650 if (appData.monoMode) {
3651 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3655 if (strlen(appData.pixmapDirectory) == 0) {
3656 XpmPieces* pieces = builtInXpms;
3659 while (pieces->size != squareSize && pieces->size) pieces++;
3660 if (!pieces->size) {
3661 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3664 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3665 for (kind=0; kind<4; kind++) {
3667 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3668 pieces->xpm[piece][kind],
3669 &(xpmPieceBitmap2[kind][piece]),
3670 NULL, &attr)) != 0) {
3671 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3675 if(piece <= (int) WhiteKing)
3676 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3680 xpmJailSquare = xpmLightSquare;
3684 fprintf(stderr, _("\nLoading XPMs...\n"));
3687 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3688 fprintf(stderr, "%d ", piece+1);
3689 for (kind=0; kind<4; kind++) {
3690 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3691 ExpandPathName(appData.pixmapDirectory),
3692 piece > (int) WhiteKing ? "w" : "",
3693 pieceBitmapNames[piece],
3695 if (appData.debugMode) {
3696 fprintf(stderr, _("(File:%s:) "), buf);
3698 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3699 &(xpmPieceBitmap2[kind][piece]),
3700 NULL, &attr)) != 0) {
3701 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3702 // [HGM] missing: read of unorthodox piece failed; substitute King.
3703 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3704 ExpandPathName(appData.pixmapDirectory),
3706 if (appData.debugMode) {
3707 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3709 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3710 &(xpmPieceBitmap2[kind][piece]),
3714 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3719 if(piece <= (int) WhiteKing)
3720 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3723 /* Load light and dark squares */
3724 /* If the LSQ and DSQ pieces don't exist, we will
3725 draw them with solid squares. */
3726 fprintf(stderr, _("light square "));
3727 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3728 if (access(buf, 0) != 0) {
3732 if (appData.debugMode)
3733 fprintf(stderr, _("(File:%s:) "), buf);
3735 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3736 &xpmLightSquare, NULL, &attr)) != 0) {
3737 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3740 fprintf(stderr, _("dark square "));
3741 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3742 ExpandPathName(appData.pixmapDirectory), ss);
3743 if (appData.debugMode) {
3744 fprintf(stderr, _("(File:%s:) "), buf);
3746 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3747 &xpmDarkSquare, NULL, &attr)) != 0) {
3748 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3752 xpmJailSquare = xpmLightSquare;
3753 fprintf(stderr, _("Done.\n"));
3755 oldVariant = -1; // kludge to force re-makig of animation masks
3756 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3759 #endif /* HAVE_LIBXPM */
3762 /* No built-in bitmaps */
3767 u_int ss = squareSize;
3769 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3772 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3773 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3774 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3775 pieceBitmapNames[piece],
3776 ss, kind == SOLID ? 's' : 'o');
3777 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3778 if(piece <= (int)WhiteKing)
3779 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3783 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3787 /* With built-in bitmaps */
3790 BuiltInBits* bib = builtInBits;
3793 u_int ss = squareSize;
3795 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3798 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3800 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3801 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3802 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3803 pieceBitmapNames[piece],
3804 ss, kind == SOLID ? 's' : 'o');
3805 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3806 bib->bits[kind][piece], ss, ss);
3807 if(piece <= (int)WhiteKing)
3808 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3812 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3817 void ReadBitmap(pm, name, bits, wreq, hreq)
3820 unsigned char bits[];
3826 char msg[MSG_SIZ], fullname[MSG_SIZ];
3828 if (*appData.bitmapDirectory != NULLCHAR) {
3829 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3830 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3831 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3832 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3833 &w, &h, pm, &x_hot, &y_hot);
3834 fprintf(stderr, "load %s\n", name);
3835 if (errcode != BitmapSuccess) {
3837 case BitmapOpenFailed:
3838 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3840 case BitmapFileInvalid:
3841 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3843 case BitmapNoMemory:
3844 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3848 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3852 fprintf(stderr, _("%s: %s...using built-in\n"),
3854 } else if (w != wreq || h != hreq) {
3856 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3857 programName, fullname, w, h, wreq, hreq);
3863 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3872 if (lineGap == 0) return;
3874 /* [HR] Split this into 2 loops for non-square boards. */
3876 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3877 gridSegments[i].x1 = 0;
3878 gridSegments[i].x2 =
3879 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3880 gridSegments[i].y1 = gridSegments[i].y2
3881 = lineGap / 2 + (i * (squareSize + lineGap));
3884 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3885 gridSegments[j + i].y1 = 0;
3886 gridSegments[j + i].y2 =
3887 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3888 gridSegments[j + i].x1 = gridSegments[j + i].x2
3889 = lineGap / 2 + (j * (squareSize + lineGap));
3893 static void MenuBarSelect(w, addr, index)
3898 XtActionProc proc = (XtActionProc) addr;
3900 (proc)(NULL, NULL, NULL, NULL);
3903 void CreateMenuBarPopup(parent, name, mb)
3913 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3916 XtSetArg(args[j], XtNleftMargin, 20); j++;
3917 XtSetArg(args[j], XtNrightMargin, 20); j++;
3919 while (mi->string != NULL) {
3920 if (strcmp(mi->string, "----") == 0) {
3921 entry = XtCreateManagedWidget(_(mi->string), smeLineObjectClass,
3924 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3925 entry = XtCreateManagedWidget(mi->ref, smeBSBObjectClass,
3927 XtAddCallback(entry, XtNcallback,
3928 (XtCallbackProc) MenuBarSelect,
3929 (caddr_t) mi->proc);
3935 Widget CreateMenuBar(mb)
3939 Widget anchor, menuBar;
3941 char menuName[MSG_SIZ];
3944 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3945 XtSetArg(args[j], XtNvSpace, 0); j++;
3946 XtSetArg(args[j], XtNborderWidth, 0); j++;
3947 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3948 formWidget, args, j);
3950 while (mb->name != NULL) {
3951 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3952 strncat(menuName, mb->ref, MSG_SIZ - strlen(menuName) - 1);
3954 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3957 shortName[0] = mb->name[0];
3958 shortName[1] = NULLCHAR;
3959 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3962 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3965 XtSetArg(args[j], XtNborderWidth, 0); j++;
3966 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3968 CreateMenuBarPopup(menuBar, menuName, mb);
3974 Widget CreateButtonBar(mi)
3978 Widget button, buttonBar;
3982 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3984 XtSetArg(args[j], XtNhSpace, 0); j++;
3986 XtSetArg(args[j], XtNborderWidth, 0); j++;
3987 XtSetArg(args[j], XtNvSpace, 0); j++;
3988 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3989 formWidget, args, j);
3991 while (mi->string != NULL) {
3994 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3995 XtSetArg(args[j], XtNborderWidth, 0); j++;
3997 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3998 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3999 buttonBar, args, j);
4000 XtAddCallback(button, XtNcallback,
4001 (XtCallbackProc) MenuBarSelect,
4002 (caddr_t) mi->proc);
4009 CreatePieceMenu(name, color)
4016 ChessSquare selection;
4018 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
4019 boardWidget, args, 0);
4021 for (i = 0; i < PIECE_MENU_SIZE; i++) {
4022 String item = pieceMenuStrings[color][i];
4024 if (strcmp(item, "----") == 0) {
4025 entry = XtCreateManagedWidget(item, smeLineObjectClass,
4028 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
4029 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
4031 selection = pieceMenuTranslation[color][i];
4032 XtAddCallback(entry, XtNcallback,
4033 (XtCallbackProc) PieceMenuSelect,
4034 (caddr_t) selection);
4035 if (selection == WhitePawn || selection == BlackPawn) {
4036 XtSetArg(args[0], XtNpopupOnEntry, entry);
4037 XtSetValues(menu, args, 1);
4050 ChessSquare selection;
4052 whitePieceMenu = CreatePieceMenu("menuW", 0);
4053 blackPieceMenu = CreatePieceMenu("menuB", 1);
4055 XtRegisterGrabAction(PieceMenuPopup, True,
4056 (unsigned)(ButtonPressMask|ButtonReleaseMask),
4057 GrabModeAsync, GrabModeAsync);
4059 XtSetArg(args[0], XtNlabel, _("Drop"));
4060 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
4061 boardWidget, args, 1);
4062 for (i = 0; i < DROP_MENU_SIZE; i++) {
4063 String item = dropMenuStrings[i];
4065 if (strcmp(item, "----") == 0) {
4066 entry = XtCreateManagedWidget(item, smeLineObjectClass,
4069 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
4070 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
4072 selection = dropMenuTranslation[i];
4073 XtAddCallback(entry, XtNcallback,
4074 (XtCallbackProc) DropMenuSelect,
4075 (caddr_t) selection);
4080 void SetupDropMenu()
4088 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
4089 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
4090 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
4091 dmEnables[i].piece);
4092 XtSetSensitive(entry, p != NULL || !appData.testLegality
4093 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
4094 && !appData.icsActive));
4096 while (p && *p++ == dmEnables[i].piece) count++;
4097 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
4099 XtSetArg(args[j], XtNlabel, label); j++;
4100 XtSetValues(entry, args, j);
4104 void PieceMenuPopup(w, event, params, num_params)
4108 Cardinal *num_params;
4110 String whichMenu; int menuNr = -2;
4111 shiftKey = strcmp(params[0], "menuW"); // used to indicate black
4112 if (event->type == ButtonRelease)
4113 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
4114 else if (event->type == ButtonPress)
4115 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
4117 case 0: whichMenu = params[0]; break;
4118 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
4120 case -1: if (errorUp) ErrorPopDown();
4123 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
4126 static void PieceMenuSelect(w, piece, junk)
4131 if (pmFromX < 0 || pmFromY < 0) return;
4132 EditPositionMenuEvent(piece, pmFromX, pmFromY);
4135 static void DropMenuSelect(w, piece, junk)
4140 if (pmFromX < 0 || pmFromY < 0) return;
4141 DropMenuEvent(piece, pmFromX, pmFromY);
4144 void WhiteClock(w, event, prms, nprms)
4150 shiftKey = prms[0][0] & 1;
4154 void BlackClock(w, event, prms, nprms)
4160 shiftKey = prms[0][0] & 1;
4166 * If the user selects on a border boundary, return -1; if off the board,
4167 * return -2. Otherwise map the event coordinate to the square.
4169 int EventToSquare(x, limit)
4177 if ((x % (squareSize + lineGap)) >= squareSize)
4179 x /= (squareSize + lineGap);
4185 static void do_flash_delay(msec)
4191 static void drawHighlight(file, rank, gc)
4197 if (lineGap == 0) return;
4200 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
4201 (squareSize + lineGap);
4202 y = lineGap/2 + rank * (squareSize + lineGap);
4204 x = lineGap/2 + file * (squareSize + lineGap);
4205 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
4206 (squareSize + lineGap);
4209 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
4210 squareSize+lineGap, squareSize+lineGap);
4213 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
4214 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4217 SetHighlights(fromX, fromY, toX, toY)
4218 int fromX, fromY, toX, toY;
4220 if (hi1X != fromX || hi1Y != fromY) {
4221 if (hi1X >= 0 && hi1Y >= 0) {
4222 drawHighlight(hi1X, hi1Y, lineGC);
4224 } // [HGM] first erase both, then draw new!
4225 if (hi2X != toX || hi2Y != toY) {
4226 if (hi2X >= 0 && hi2Y >= 0) {
4227 drawHighlight(hi2X, hi2Y, lineGC);
4230 if (hi1X != fromX || hi1Y != fromY) {
4231 if (fromX >= 0 && fromY >= 0) {
4232 drawHighlight(fromX, fromY, highlineGC);
4235 if (hi2X != toX || hi2Y != toY) {
4236 if (toX >= 0 && toY >= 0) {
4237 drawHighlight(toX, toY, highlineGC);
4249 SetHighlights(-1, -1, -1, -1);
4254 SetPremoveHighlights(fromX, fromY, toX, toY)
4255 int fromX, fromY, toX, toY;
4257 if (pm1X != fromX || pm1Y != fromY) {
4258 if (pm1X >= 0 && pm1Y >= 0) {
4259 drawHighlight(pm1X, pm1Y, lineGC);
4261 if (fromX >= 0 && fromY >= 0) {
4262 drawHighlight(fromX, fromY, prelineGC);
4265 if (pm2X != toX || pm2Y != toY) {
4266 if (pm2X >= 0 && pm2Y >= 0) {
4267 drawHighlight(pm2X, pm2Y, lineGC);
4269 if (toX >= 0 && toY >= 0) {
4270 drawHighlight(toX, toY, prelineGC);
4280 ClearPremoveHighlights()
4282 SetPremoveHighlights(-1, -1, -1, -1);
4285 static int CutOutSquare(x, y, x0, y0, kind)
4286 int x, y, *x0, *y0, kind;
4288 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
4289 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
4291 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
4292 if(textureW[kind] < W*squareSize)
4293 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
4295 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
4296 if(textureH[kind] < H*squareSize)
4297 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
4299 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
4303 static void BlankSquare(x, y, color, piece, dest, fac)
4304 int x, y, color, fac;
4307 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
4309 if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
4310 XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
4311 squareSize, squareSize, x*fac, y*fac);
4313 if (useImages && useImageSqs) {
4317 pm = xpmLightSquare;
4322 case 2: /* neutral */
4327 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4328 squareSize, squareSize, x*fac, y*fac);
4338 case 2: /* neutral */
4343 XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
4348 I split out the routines to draw a piece so that I could
4349 make a generic flash routine.
4351 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4353 int square_color, x, y;
4356 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4357 switch (square_color) {
4359 case 2: /* neutral */
4361 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4362 ? *pieceToOutline(piece)
4363 : *pieceToSolid(piece),
4364 dest, bwPieceGC, 0, 0,
4365 squareSize, squareSize, x, y);
4368 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4369 ? *pieceToSolid(piece)
4370 : *pieceToOutline(piece),
4371 dest, wbPieceGC, 0, 0,
4372 squareSize, squareSize, x, y);
4377 static void monoDrawPiece(piece, square_color, x, y, dest)
4379 int square_color, x, y;
4382 switch (square_color) {
4384 case 2: /* neutral */
4386 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4387 ? *pieceToOutline(piece)
4388 : *pieceToSolid(piece),
4389 dest, bwPieceGC, 0, 0,
4390 squareSize, squareSize, x, y, 1);
4393 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4394 ? *pieceToSolid(piece)
4395 : *pieceToOutline(piece),
4396 dest, wbPieceGC, 0, 0,
4397 squareSize, squareSize, x, y, 1);
4402 static void colorDrawPiece(piece, square_color, x, y, dest)
4404 int square_color, x, y;
4407 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4408 switch (square_color) {
4410 XCopyPlane(xDisplay, *pieceToSolid(piece),
4411 dest, (int) piece < (int) BlackPawn
4412 ? wlPieceGC : blPieceGC, 0, 0,
4413 squareSize, squareSize, x, y, 1);
4416 XCopyPlane(xDisplay, *pieceToSolid(piece),
4417 dest, (int) piece < (int) BlackPawn
4418 ? wdPieceGC : bdPieceGC, 0, 0,
4419 squareSize, squareSize, x, y, 1);
4421 case 2: /* neutral */
4423 XCopyPlane(xDisplay, *pieceToSolid(piece),
4424 dest, (int) piece < (int) BlackPawn
4425 ? wjPieceGC : bjPieceGC, 0, 0,
4426 squareSize, squareSize, x, y, 1);
4431 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4433 int square_color, x, y;
4436 int kind, p = piece;
4438 switch (square_color) {
4440 case 2: /* neutral */
4442 if ((int)piece < (int) BlackPawn) {
4450 if ((int)piece < (int) BlackPawn) {
4458 if(appData.upsideDown && flipView) { kind ^= 2; p += p < BlackPawn ? BlackPawn : -BlackPawn; }// swap white and black pieces
4459 if(useTexture & square_color+1) {
4460 BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background
4461 XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]);
4462 XSetClipOrigin(xDisplay, wlPieceGC, x, y);
4463 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y);
4464 XSetClipMask(xDisplay, wlPieceGC, None);
4465 XSetClipOrigin(xDisplay, wlPieceGC, 0, 0);
4467 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4468 dest, wlPieceGC, 0, 0,
4469 squareSize, squareSize, x, y);
4472 typedef void (*DrawFunc)();
4474 DrawFunc ChooseDrawFunc()
4476 if (appData.monoMode) {
4477 if (DefaultDepth(xDisplay, xScreen) == 1) {
4478 return monoDrawPiece_1bit;
4480 return monoDrawPiece;
4484 return colorDrawPieceImage;
4486 return colorDrawPiece;
4490 /* [HR] determine square color depending on chess variant. */
4491 static int SquareColor(row, column)
4496 if (gameInfo.variant == VariantXiangqi) {
4497 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4499 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4501 } else if (row <= 4) {
4507 square_color = ((column + row) % 2) == 1;
4510 /* [hgm] holdings: next line makes all holdings squares light */
4511 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4513 return square_color;
4516 void DrawSquare(row, column, piece, do_flash)
4517 int row, column, do_flash;
4520 int square_color, x, y, direction, font_ascent, font_descent;
4523 XCharStruct overall;
4527 /* Calculate delay in milliseconds (2-delays per complete flash) */
4528 flash_delay = 500 / appData.flashRate;
4531 x = lineGap + ((BOARD_WIDTH-1)-column) *
4532 (squareSize + lineGap);
4533 y = lineGap + row * (squareSize + lineGap);
4535 x = lineGap + column * (squareSize + lineGap);
4536 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4537 (squareSize + lineGap);
4540 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4542 square_color = SquareColor(row, column);
4544 if ( // [HGM] holdings: blank out area between board and holdings
4545 column == BOARD_LEFT-1 || column == BOARD_RGHT
4546 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4547 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4548 BlankSquare(x, y, 2, EmptySquare, xBoardWindow, 1);
4550 // [HGM] print piece counts next to holdings
4551 string[1] = NULLCHAR;
4552 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4553 string[0] = '0' + piece;
4554 XTextExtents(countFontStruct, string, 1, &direction,
4555 &font_ascent, &font_descent, &overall);
4556 if (appData.monoMode) {
4557 XDrawImageString(xDisplay, xBoardWindow, countGC,
4558 x + squareSize - overall.width - 2,
4559 y + font_ascent + 1, string, 1);
4561 XDrawString(xDisplay, xBoardWindow, countGC,
4562 x + squareSize - overall.width - 2,
4563 y + font_ascent + 1, string, 1);
4566 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4567 string[0] = '0' + piece;
4568 XTextExtents(countFontStruct, string, 1, &direction,
4569 &font_ascent, &font_descent, &overall);
4570 if (appData.monoMode) {
4571 XDrawImageString(xDisplay, xBoardWindow, countGC,
4572 x + 2, y + font_ascent + 1, string, 1);
4574 XDrawString(xDisplay, xBoardWindow, countGC,
4575 x + 2, y + font_ascent + 1, string, 1);
4579 if (piece == EmptySquare || appData.blindfold) {
4580 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4582 drawfunc = ChooseDrawFunc();
4584 if (do_flash && appData.flashCount > 0) {
4585 for (i=0; i<appData.flashCount; ++i) {
4586 drawfunc(piece, square_color, x, y, xBoardWindow);
4587 XSync(xDisplay, False);
4588 do_flash_delay(flash_delay);
4590 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4591 XSync(xDisplay, False);
4592 do_flash_delay(flash_delay);
4595 drawfunc(piece, square_color, x, y, xBoardWindow);
4599 string[1] = NULLCHAR;
4600 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4601 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4602 string[0] = 'a' + column - BOARD_LEFT;
4603 XTextExtents(coordFontStruct, string, 1, &direction,
4604 &font_ascent, &font_descent, &overall);
4605 if (appData.monoMode) {
4606 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4607 x + squareSize - overall.width - 2,
4608 y + squareSize - font_descent - 1, string, 1);
4610 XDrawString(xDisplay, xBoardWindow, coordGC,
4611 x + squareSize - overall.width - 2,
4612 y + squareSize - font_descent - 1, string, 1);
4615 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4616 string[0] = ONE + row;
4617 XTextExtents(coordFontStruct, string, 1, &direction,
4618 &font_ascent, &font_descent, &overall);
4619 if (appData.monoMode) {
4620 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4621 x + 2, y + font_ascent + 1, string, 1);
4623 XDrawString(xDisplay, xBoardWindow, coordGC,
4624 x + 2, y + font_ascent + 1, string, 1);
4627 if(!partnerUp && marker[row][column]) {
4628 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4629 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4634 /* Why is this needed on some versions of X? */
4635 void EventProc(widget, unused, event)
4640 if (!XtIsRealized(widget))
4643 switch (event->type) {
4645 if (event->xexpose.count > 0) return; /* no clipping is done */
4646 XDrawPosition(widget, True, NULL);
4647 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4648 flipView = !flipView; partnerUp = !partnerUp;
4649 XDrawPosition(widget, True, NULL);
4650 flipView = !flipView; partnerUp = !partnerUp;
4654 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
4661 void DrawPosition(fullRedraw, board)
4662 /*Boolean*/int fullRedraw;
4665 XDrawPosition(boardWidget, fullRedraw, board);
4668 /* Returns 1 if there are "too many" differences between b1 and b2
4669 (i.e. more than 1 move was made) */
4670 static int too_many_diffs(b1, b2)
4676 for (i=0; i<BOARD_HEIGHT; ++i) {
4677 for (j=0; j<BOARD_WIDTH; ++j) {
4678 if (b1[i][j] != b2[i][j]) {
4679 if (++c > 4) /* Castling causes 4 diffs */
4687 /* Matrix describing castling maneuvers */
4688 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4689 static int castling_matrix[4][5] = {
4690 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4691 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4692 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4693 { 7, 7, 4, 5, 6 } /* 0-0, black */
4696 /* Checks whether castling occurred. If it did, *rrow and *rcol
4697 are set to the destination (row,col) of the rook that moved.
4699 Returns 1 if castling occurred, 0 if not.
4701 Note: Only handles a max of 1 castling move, so be sure
4702 to call too_many_diffs() first.
4704 static int check_castle_draw(newb, oldb, rrow, rcol)
4711 /* For each type of castling... */
4712 for (i=0; i<4; ++i) {
4713 r = castling_matrix[i];
4715 /* Check the 4 squares involved in the castling move */
4717 for (j=1; j<=4; ++j) {
4718 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4725 /* All 4 changed, so it must be a castling move */
4734 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4735 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4737 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4740 void DrawSeekBackground( int left, int top, int right, int bottom )
4742 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4745 void DrawSeekText(char *buf, int x, int y)
4747 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4750 void DrawSeekDot(int x, int y, int colorNr)
4752 int square = colorNr & 0x80;
4755 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4757 XFillRectangle(xDisplay, xBoardWindow, color,
4758 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4760 XFillArc(xDisplay, xBoardWindow, color,
4761 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4764 static int damage[2][BOARD_RANKS][BOARD_FILES];
4767 * event handler for redrawing the board
4769 void XDrawPosition(w, repaint, board)
4771 /*Boolean*/int repaint;
4775 static int lastFlipView = 0;
4776 static int lastBoardValid[2] = {0, 0};
4777 static Board lastBoard[2];
4780 int nr = twoBoards*partnerUp;
4782 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4784 if (board == NULL) {
4785 if (!lastBoardValid[nr]) return;
4786 board = lastBoard[nr];
4788 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4789 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4790 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Flip View"),
4795 * It would be simpler to clear the window with XClearWindow()
4796 * but this causes a very distracting flicker.
4799 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4801 if ( lineGap && IsDrawArrowEnabled())
4802 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4803 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4805 /* If too much changes (begin observing new game, etc.), don't
4807 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4809 /* Special check for castling so we don't flash both the king
4810 and the rook (just flash the king). */
4812 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4813 /* Draw rook with NO flashing. King will be drawn flashing later */
4814 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4815 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4819 /* First pass -- Draw (newly) empty squares and repair damage.
4820 This prevents you from having a piece show up twice while it
4821 is flashing on its new square */
4822 for (i = 0; i < BOARD_HEIGHT; i++)
4823 for (j = 0; j < BOARD_WIDTH; j++)
4824 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4825 || damage[nr][i][j]) {
4826 DrawSquare(i, j, board[i][j], 0);
4827 damage[nr][i][j] = False;
4830 /* Second pass -- Draw piece(s) in new position and flash them */
4831 for (i = 0; i < BOARD_HEIGHT; i++)
4832 for (j = 0; j < BOARD_WIDTH; j++)
4833 if (board[i][j] != lastBoard[nr][i][j]) {
4834 DrawSquare(i, j, board[i][j], do_flash);
4838 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4839 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4840 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4842 for (i = 0; i < BOARD_HEIGHT; i++)
4843 for (j = 0; j < BOARD_WIDTH; j++) {
4844 DrawSquare(i, j, board[i][j], 0);
4845 damage[nr][i][j] = False;
4849 CopyBoard(lastBoard[nr], board);
4850 lastBoardValid[nr] = 1;
4851 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4852 lastFlipView = flipView;
4854 /* Draw highlights */
4855 if (pm1X >= 0 && pm1Y >= 0) {
4856 drawHighlight(pm1X, pm1Y, prelineGC);
4858 if (pm2X >= 0 && pm2Y >= 0) {
4859 drawHighlight(pm2X, pm2Y, prelineGC);
4861 if (hi1X >= 0 && hi1Y >= 0) {
4862 drawHighlight(hi1X, hi1Y, highlineGC);
4864 if (hi2X >= 0 && hi2Y >= 0) {
4865 drawHighlight(hi2X, hi2Y, highlineGC);
4867 DrawArrowHighlight(hi1X, hi1Y, hi2X, hi2Y);
4869 /* If piece being dragged around board, must redraw that too */
4872 XSync(xDisplay, False);
4877 * event handler for redrawing the board
4879 void DrawPositionProc(w, event, prms, nprms)
4885 XDrawPosition(w, True, NULL);
4890 * event handler for parsing user moves
4892 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4893 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4894 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4895 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4896 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4897 // and at the end FinishMove() to perform the move after optional promotion popups.
4898 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4899 void HandleUserMove(w, event, prms, nprms)
4905 if (w != boardWidget || errorExitStatus != -1) return;
4906 if(nprms) shiftKey = !strcmp(prms[0], "1");
4909 if (event->type == ButtonPress) {
4910 XtPopdown(promotionShell);
4911 XtDestroyWidget(promotionShell);
4912 promotionUp = False;
4920 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4921 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4922 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4925 void AnimateUserMove (Widget w, XEvent * event,
4926 String * params, Cardinal * nParams)
4928 if(!PromoScroll(event->xmotion.x, event->xmotion.y))
4929 DragPieceMove(event->xmotion.x, event->xmotion.y);
4932 void HandlePV (Widget w, XEvent * event,
4933 String * params, Cardinal * nParams)
4934 { // [HGM] pv: walk PV
4935 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4938 static int savedIndex; /* gross that this is global */
4940 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
4943 XawTextPosition index, dummy;
4946 XawTextGetSelectionPos(w, &index, &dummy);
4947 XtSetArg(arg, XtNstring, &val);
4948 XtGetValues(w, &arg, 1);
4949 ReplaceComment(savedIndex, val);
4950 if(savedIndex != currentMove) ToNrEvent(savedIndex);
4951 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
4954 void EditCommentPopUp(index, title, text)
4959 if (text == NULL) text = "";
4960 NewCommentPopup(title, text, index);
4963 void ICSInputBoxPopUp()
4968 extern Option boxOptions[];
4970 void ICSInputSendText()
4977 edit = boxOptions[0].handle;
4979 XtSetArg(args[j], XtNstring, &val); j++;
4980 XtGetValues(edit, args, j);
4982 SendMultiLineToICS(val);
4983 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4984 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4987 void ICSInputBoxPopDown()
4992 void CommentPopUp(title, text)
4995 savedIndex = currentMove; // [HGM] vari
4996 NewCommentPopup(title, text, currentMove);
4999 void CommentPopDown()
5004 static char *openName;
5009 (void) (*fileProc)(openFP, 0, openName);
5012 void FileNamePopUp(label, def, filter, proc, openMode)
5019 fileProc = proc; /* I can't see a way not */
5020 fileOpenMode = openMode; /* to use globals here */
5021 { // [HGM] use file-selector dialog stolen from Ghostview
5022 int index; // this is not supported yet
5023 if(openFP = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5024 (def[0] ? def : NULL), filter, openMode, NULL, &openName))
5025 // [HGM] delay to give expose event opportunity to redraw board after browser-dialog popdown before lengthy load starts
5026 ScheduleDelayedEvent(&DelayedLoad, 50);
5030 void FileNamePopDown()
5032 if (!filenameUp) return;
5033 XtPopdown(fileNameShell);
5034 XtDestroyWidget(fileNameShell);
5039 void FileNameCallback(w, client_data, call_data)
5041 XtPointer client_data, call_data;
5046 XtSetArg(args[0], XtNlabel, &name);
5047 XtGetValues(w, args, 1);
5049 if (strcmp(name, _("cancel")) == 0) {
5054 FileNameAction(w, NULL, NULL, NULL);
5057 void FileNameAction(w, event, prms, nprms)
5069 name = XawDialogGetValueString(w = XtParent(w));
5071 if ((name != NULL) && (*name != NULLCHAR)) {
5072 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
5073 XtPopdown(w = XtParent(XtParent(w)));
5077 p = strrchr(buf, ' ');
5084 fullname = ExpandPathName(buf);
5086 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5089 f = fopen(fullname, fileOpenMode);
5091 DisplayError(_("Failed to open file"), errno);
5093 (void) (*fileProc)(f, index, buf);
5100 XtPopdown(w = XtParent(XtParent(w)));
5106 void PromotionPopUp()
5109 Widget dialog, layout;
5111 Dimension bw_width, pw_width;
5115 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5116 XtGetValues(boardWidget, args, j);
5119 XtSetArg(args[j], XtNresizable, True); j++;
5120 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5122 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5123 shellWidget, args, j);
5125 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5126 layoutArgs, XtNumber(layoutArgs));
5129 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5130 XtSetArg(args[j], XtNborderWidth, 0); j++;
5131 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5134 if(gameInfo.variant != VariantShogi) {
5135 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) {
5136 XawDialogAddButton(dialog, _("Warlord"), PromotionCallback,
5137 (XtPointer) dialog);
5138 XawDialogAddButton(dialog, _("General"), PromotionCallback,
5139 (XtPointer) dialog);
5140 XawDialogAddButton(dialog, _("Lieutenant"), PromotionCallback,
5141 (XtPointer) dialog);
5142 XawDialogAddButton(dialog, _("Captain"), PromotionCallback,
5143 (XtPointer) dialog);
5145 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5146 (XtPointer) dialog);
5147 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5148 (XtPointer) dialog);
5149 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5150 (XtPointer) dialog);
5151 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5152 (XtPointer) dialog);
5154 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5155 gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
5156 gameInfo.variant == VariantGiveaway) {
5157 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5158 (XtPointer) dialog);
5160 if(gameInfo.variant == VariantCapablanca ||
5161 gameInfo.variant == VariantGothic ||
5162 gameInfo.variant == VariantCapaRandom) {
5163 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5164 (XtPointer) dialog);
5165 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5166 (XtPointer) dialog);
5168 } else // [HGM] shogi
5170 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5171 (XtPointer) dialog);
5172 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5173 (XtPointer) dialog);
5175 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5176 (XtPointer) dialog);
5178 XtRealizeWidget(promotionShell);
5179 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5182 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5183 XtGetValues(promotionShell, args, j);
5185 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5186 lineGap + squareSize/3 +
5187 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5188 0 : 6*(squareSize + lineGap)), &x, &y);
5191 XtSetArg(args[j], XtNx, x); j++;
5192 XtSetArg(args[j], XtNy, y); j++;
5193 XtSetValues(promotionShell, args, j);
5195 XtPopup(promotionShell, XtGrabNone);
5200 void PromotionPopDown()
5202 if (!promotionUp) return;
5203 XtPopdown(promotionShell);
5204 XtDestroyWidget(promotionShell);
5205 promotionUp = False;
5208 void PromotionCallback(w, client_data, call_data)
5210 XtPointer client_data, call_data;
5216 XtSetArg(args[0], XtNlabel, &name);
5217 XtGetValues(w, args, 1);
5221 if (fromX == -1) return;
5223 if (strcmp(name, _("cancel")) == 0) {
5227 } else if (strcmp(name, _("Knight")) == 0) {
5229 } else if (strcmp(name, _("Promote")) == 0) {
5231 } else if (strcmp(name, _("Defer")) == 0) {
5234 promoChar = ToLower(name[0]);
5237 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5239 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5240 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5245 void ErrorCallback(w, client_data, call_data)
5247 XtPointer client_data, call_data;
5250 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5252 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5258 if (!errorUp) return;
5260 XtPopdown(errorShell);
5261 XtDestroyWidget(errorShell);
5262 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5265 void ErrorPopUp(title, label, modal)
5266 char *title, *label;
5270 Widget dialog, layout;
5274 Dimension bw_width, pw_width;
5275 Dimension pw_height;
5279 XtSetArg(args[i], XtNresizable, True); i++;
5280 XtSetArg(args[i], XtNtitle, title); i++;
5282 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5283 shellWidget, args, i);
5285 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5286 layoutArgs, XtNumber(layoutArgs));
5289 XtSetArg(args[i], XtNlabel, label); i++;
5290 XtSetArg(args[i], XtNborderWidth, 0); i++;
5291 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5294 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5296 XtRealizeWidget(errorShell);
5297 CatchDeleteWindow(errorShell, "ErrorPopDown");
5300 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5301 XtGetValues(boardWidget, args, i);
5303 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5304 XtSetArg(args[i], XtNheight, &pw_height); i++;
5305 XtGetValues(errorShell, args, i);
5308 /* This code seems to tickle an X bug if it is executed too soon
5309 after xboard starts up. The coordinates get transformed as if
5310 the main window was positioned at (0, 0).
5312 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5313 0 - pw_height + squareSize / 3, &x, &y);
5315 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5316 RootWindowOfScreen(XtScreen(boardWidget)),
5317 (bw_width - pw_width) / 2,
5318 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5322 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5325 XtSetArg(args[i], XtNx, x); i++;
5326 XtSetArg(args[i], XtNy, y); i++;
5327 XtSetValues(errorShell, args, i);
5330 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5333 /* Disable all user input other than deleting the window */
5334 static int frozen = 0;
5338 /* Grab by a widget that doesn't accept input */
5339 XtAddGrab(messageWidget, TRUE, FALSE);
5343 /* Undo a FreezeUI */
5346 if (!frozen) return;
5347 XtRemoveGrab(messageWidget);
5351 char *ModeToWidgetName(mode)
5355 case BeginningOfGame:
5356 if (appData.icsActive)
5357 return "menuMode.ICS Client";
5358 else if (appData.noChessProgram ||
5359 *appData.cmailGameName != NULLCHAR)
5360 return "menuMode.Edit Game";
5362 return "menuMode.Machine Black";
5363 case MachinePlaysBlack:
5364 return "menuMode.Machine Black";
5365 case MachinePlaysWhite:
5366 return "menuMode.Machine White";
5368 return "menuMode.Analysis Mode";
5370 return "menuMode.Analyze File";
5371 case TwoMachinesPlay:
5372 return "menuMode.Two Machines";
5374 return "menuMode.Edit Game";
5375 case PlayFromGameFile:
5376 return "menuFile.Load Game";
5378 return "menuMode.Edit Position";
5380 return "menuMode.Training";
5381 case IcsPlayingWhite:
5382 case IcsPlayingBlack:
5386 return "menuMode.ICS Client";
5393 void ModeHighlight()
5396 static int oldPausing = FALSE;
5397 static GameMode oldmode = (GameMode) -1;
5400 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5402 if (pausing != oldPausing) {
5403 oldPausing = pausing;
5405 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5407 XtSetArg(args[0], XtNleftBitmap, None);
5409 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5412 if (appData.showButtonBar) {
5413 /* Always toggle, don't set. Previous code messes up when
5414 invoked while the button is pressed, as releasing it
5415 toggles the state again. */
5418 XtSetArg(args[0], XtNbackground, &oldbg);
5419 XtSetArg(args[1], XtNforeground, &oldfg);
5420 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5422 XtSetArg(args[0], XtNbackground, oldfg);
5423 XtSetArg(args[1], XtNforeground, oldbg);
5425 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5429 wname = ModeToWidgetName(oldmode);
5430 if (wname != NULL) {
5431 XtSetArg(args[0], XtNleftBitmap, None);
5432 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5434 wname = ModeToWidgetName(gameMode);
5435 if (wname != NULL) {
5436 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5437 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5440 XtSetArg(args[0], XtNleftBitmap, matchMode && matchGame < appData.matchGames ? xMarkPixmap : None);
5441 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Machine Match"), args, 1);
5443 /* Maybe all the enables should be handled here, not just this one */
5444 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5445 gameMode == Training || gameMode == PlayFromGameFile);
5450 * Button/menu procedures
5452 void ResetProc(w, event, prms, nprms)
5461 int LoadGamePopUp(f, gameNumber, title)
5466 cmailMsgLoaded = FALSE;
5467 if (gameNumber == 0) {
5468 int error = GameListBuild(f);
5470 DisplayError(_("Cannot build game list"), error);
5471 } else if (!ListEmpty(&gameList) &&
5472 ((ListGame *) gameList.tailPred)->number > 1) {
5473 GameListPopUp(f, title);
5479 return LoadGame(f, gameNumber, title, FALSE);
5482 void LoadGameProc(w, event, prms, nprms)
5488 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5491 FileNamePopUp(_("Load game file name?"), "", ".pgn .game", LoadGamePopUp, "rb");
5494 void LoadNextGameProc(w, event, prms, nprms)
5503 void LoadPrevGameProc(w, event, prms, nprms)
5512 void ReloadGameProc(w, event, prms, nprms)
5521 void LoadNextPositionProc(w, event, prms, nprms)
5530 void LoadPrevPositionProc(w, event, prms, nprms)
5539 void ReloadPositionProc(w, event, prms, nprms)
5548 void LoadPositionProc(w, event, prms, nprms)
5554 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5557 FileNamePopUp(_("Load position file name?"), "", ".fen .epd .pos", LoadPosition, "rb");
5560 void SaveGameProc(w, event, prms, nprms)
5566 FileNamePopUp(_("Save game file name?"),
5567 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5568 appData.oldSaveStyle ? ".game" : ".pgn",
5572 void SavePositionProc(w, event, prms, nprms)
5578 FileNamePopUp(_("Save position file name?"),
5579 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5580 appData.oldSaveStyle ? ".pos" : ".fen",
5584 void ReloadCmailMsgProc(w, event, prms, nprms)
5590 ReloadCmailMsgEvent(FALSE);
5593 void MailMoveProc(w, event, prms, nprms)
5602 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5603 char *selected_fen_position=NULL;
5606 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5607 Atom *type_return, XtPointer *value_return,
5608 unsigned long *length_return, int *format_return)
5610 char *selection_tmp;
5612 if (!selected_fen_position) return False; /* should never happen */
5613 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5614 /* note: since no XtSelectionDoneProc was registered, Xt will
5615 * automatically call XtFree on the value returned. So have to
5616 * make a copy of it allocated with XtMalloc */
5617 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5618 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
5620 *value_return=selection_tmp;
5621 *length_return=strlen(selection_tmp);
5622 *type_return=*target;
5623 *format_return = 8; /* bits per byte */
5625 } else if (*target == XA_TARGETS(xDisplay)) {
5626 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5627 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5628 targets_tmp[1] = XA_STRING;
5629 *value_return = targets_tmp;
5630 *type_return = XA_ATOM;
5632 *format_return = 8 * sizeof(Atom);
5633 if (*format_return > 32) {
5634 *length_return *= *format_return / 32;
5635 *format_return = 32;
5643 /* note: when called from menu all parameters are NULL, so no clue what the
5644 * Widget which was clicked on was, or what the click event was
5646 void CopyPositionProc(w, event, prms, nprms)
5653 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5654 * have a notion of a position that is selected but not copied.
5655 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5657 if(gameMode == EditPosition) EditPositionDone(TRUE);
5658 if (selected_fen_position) free(selected_fen_position);
5659 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5660 if (!selected_fen_position) return;
5661 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5663 SendPositionSelection,
5664 NULL/* lose_ownership_proc */ ,
5665 NULL/* transfer_done_proc */);
5666 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5668 SendPositionSelection,
5669 NULL/* lose_ownership_proc */ ,
5670 NULL/* transfer_done_proc */);
5673 /* function called when the data to Paste is ready */
5675 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5676 Atom *type, XtPointer value, unsigned long *len, int *format)
5679 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5680 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5681 EditPositionPasteFEN(fenstr);
5685 /* called when Paste Position button is pressed,
5686 * all parameters will be NULL */
5687 void PastePositionProc(w, event, prms, nprms)
5693 XtGetSelectionValue(menuBarWidget,
5694 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5695 /* (XtSelectionCallbackProc) */ PastePositionCB,
5696 NULL, /* client_data passed to PastePositionCB */
5698 /* better to use the time field from the event that triggered the
5699 * call to this function, but that isn't trivial to get
5707 SendGameSelection(Widget w, Atom *selection, Atom *target,
5708 Atom *type_return, XtPointer *value_return,
5709 unsigned long *length_return, int *format_return)
5711 char *selection_tmp;
5713 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5714 FILE* f = fopen(gameCopyFilename, "r");
5717 if (f == NULL) return False;
5721 selection_tmp = XtMalloc(len + 1);
5722 count = fread(selection_tmp, 1, len, f);
5725 XtFree(selection_tmp);
5728 selection_tmp[len] = NULLCHAR;
5729 *value_return = selection_tmp;
5730 *length_return = len;
5731 *type_return = *target;
5732 *format_return = 8; /* bits per byte */
5734 } else if (*target == XA_TARGETS(xDisplay)) {
5735 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5736 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5737 targets_tmp[1] = XA_STRING;
5738 *value_return = targets_tmp;
5739 *type_return = XA_ATOM;
5741 *format_return = 8 * sizeof(Atom);
5742 if (*format_return > 32) {
5743 *length_return *= *format_return / 32;
5744 *format_return = 32;
5752 void CopySomething()
5755 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5756 * have a notion of a game that is selected but not copied.
5757 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5759 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5762 NULL/* lose_ownership_proc */ ,
5763 NULL/* transfer_done_proc */);
5764 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5767 NULL/* lose_ownership_proc */ ,
5768 NULL/* transfer_done_proc */);
5771 /* note: when called from menu all parameters are NULL, so no clue what the
5772 * Widget which was clicked on was, or what the click event was
5774 void CopyGameProc(w, event, prms, nprms)
5782 ret = SaveGameToFile(gameCopyFilename, FALSE);
5788 void CopyGameListProc(w, event, prms, nprms)
5794 if(!SaveGameListAsText(fopen(gameCopyFilename, "w"))) return;
5798 /* function called when the data to Paste is ready */
5800 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5801 Atom *type, XtPointer value, unsigned long *len, int *format)
5804 if (value == NULL || *len == 0) {
5805 return; /* nothing had been selected to copy */
5807 f = fopen(gamePasteFilename, "w");
5809 DisplayError(_("Can't open temp file"), errno);
5812 fwrite(value, 1, *len, f);
5815 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5818 /* called when Paste Game button is pressed,
5819 * all parameters will be NULL */
5820 void PasteGameProc(w, event, prms, nprms)
5826 XtGetSelectionValue(menuBarWidget,
5827 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5828 /* (XtSelectionCallbackProc) */ PasteGameCB,
5829 NULL, /* client_data passed to PasteGameCB */
5831 /* better to use the time field from the event that triggered the
5832 * call to this function, but that isn't trivial to get
5842 SaveGameProc(NULL, NULL, NULL, NULL);
5846 void QuitProc(w, event, prms, nprms)
5855 void PauseProc(w, event, prms, nprms)
5865 void MachineBlackProc(w, event, prms, nprms)
5871 MachineBlackEvent();
5874 void MachineWhiteProc(w, event, prms, nprms)
5880 MachineWhiteEvent();
5883 void AnalyzeModeProc(w, event, prms, nprms)
5891 if (!first.analysisSupport) {
5892 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5893 DisplayError(buf, 0);
5896 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5897 if (appData.icsActive) {
5898 if (gameMode != IcsObserving) {
5899 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
5900 DisplayError(buf, 0);
5902 if (appData.icsEngineAnalyze) {
5903 if (appData.debugMode)
5904 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5910 /* if enable, use want disable icsEngineAnalyze */
5911 if (appData.icsEngineAnalyze) {
5916 appData.icsEngineAnalyze = TRUE;
5917 if (appData.debugMode)
5918 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5920 #ifndef OPTIONSDIALOG
5921 if (!appData.showThinking)
5922 ShowThinkingProc(w,event,prms,nprms);
5928 void AnalyzeFileProc(w, event, prms, nprms)
5934 if (!first.analysisSupport) {
5936 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5937 DisplayError(buf, 0);
5941 #ifndef OPTIONSDIALOG
5942 if (!appData.showThinking)
5943 ShowThinkingProc(w,event,prms,nprms);
5946 FileNamePopUp(_("File to analyze"), "", ".pgn .game", LoadGamePopUp, "rb");
5947 AnalysisPeriodicEvent(1);
5950 void TwoMachinesProc(w, event, prms, nprms)
5959 void MatchProc(w, event, prms, nprms)
5968 void IcsClientProc(w, event, prms, nprms)
5977 void EditGameProc(w, event, prms, nprms)
5986 void EditPositionProc(w, event, prms, nprms)
5992 EditPositionEvent();
5995 void TrainingProc(w, event, prms, nprms)
6004 void EditCommentProc(w, event, prms, nprms)
6012 if (PopDown(1)) { // popdown succesful
6014 XtSetArg(args[j], XtNleftBitmap, None); j++;
6015 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"), args, j);
6016 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"), args, j);
6017 } else // was not up
6021 void IcsInputBoxProc(w, event, prms, nprms)
6027 if (!PopDown(4)) ICSInputBoxPopUp();
6030 void AcceptProc(w, event, prms, nprms)
6039 void DeclineProc(w, event, prms, nprms)
6048 void RematchProc(w, event, prms, nprms)
6057 void CallFlagProc(w, event, prms, nprms)
6066 void DrawProc(w, event, prms, nprms)
6075 void AbortProc(w, event, prms, nprms)
6084 void AdjournProc(w, event, prms, nprms)
6093 void ResignProc(w, event, prms, nprms)
6102 void AdjuWhiteProc(w, event, prms, nprms)
6108 UserAdjudicationEvent(+1);
6111 void AdjuBlackProc(w, event, prms, nprms)
6117 UserAdjudicationEvent(-1);
6120 void AdjuDrawProc(w, event, prms, nprms)
6126 UserAdjudicationEvent(0);
6129 void EnterKeyProc(w, event, prms, nprms)
6135 if (shellUp[4] == True)
6139 void UpKeyProc(w, event, prms, nprms)
6144 { // [HGM] input: let up-arrow recall previous line from history
6151 if (!shellUp[4]) return;
6152 edit = boxOptions[0].handle;
6154 XtSetArg(args[j], XtNstring, &val); j++;
6155 XtGetValues(edit, args, j);
6156 val = PrevInHistory(val);
6157 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6158 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6160 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6161 XawTextReplace(edit, 0, 0, &t);
6162 XawTextSetInsertionPoint(edit, 9999);
6166 void DownKeyProc(w, event, prms, nprms)
6171 { // [HGM] input: let down-arrow recall next line from history
6176 if (!shellUp[4]) return;
6177 edit = boxOptions[0].handle;
6178 val = NextInHistory();
6179 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6180 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6182 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6183 XawTextReplace(edit, 0, 0, &t);
6184 XawTextSetInsertionPoint(edit, 9999);
6188 void StopObservingProc(w, event, prms, nprms)
6194 StopObservingEvent();
6197 void StopExaminingProc(w, event, prms, nprms)
6203 StopExaminingEvent();
6206 void UploadProc(w, event, prms, nprms)
6216 void ForwardProc(w, event, prms, nprms)
6226 void BackwardProc(w, event, prms, nprms)
6235 void ToStartProc(w, event, prms, nprms)
6244 void ToEndProc(w, event, prms, nprms)
6253 void RevertProc(w, event, prms, nprms)
6262 void AnnotateProc(w, event, prms, nprms)
6271 void TruncateGameProc(w, event, prms, nprms)
6277 TruncateGameEvent();
6279 void RetractMoveProc(w, event, prms, nprms)
6288 void MoveNowProc(w, event, prms, nprms)
6297 void FlipViewProc(w, event, prms, nprms)
6303 flipView = !flipView;
6304 DrawPosition(True, NULL);
6307 void PonderNextMoveProc(w, event, prms, nprms)
6315 PonderNextMoveEvent(!appData.ponderNextMove);
6316 #ifndef OPTIONSDIALOG
6317 if (appData.ponderNextMove) {
6318 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6320 XtSetArg(args[0], XtNleftBitmap, None);
6322 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6327 #ifndef OPTIONSDIALOG
6328 void AlwaysQueenProc(w, event, prms, nprms)
6336 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6338 if (appData.alwaysPromoteToQueen) {
6339 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6341 XtSetArg(args[0], XtNleftBitmap, None);
6343 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6347 void AnimateDraggingProc(w, event, prms, nprms)
6355 appData.animateDragging = !appData.animateDragging;
6357 if (appData.animateDragging) {
6358 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6361 XtSetArg(args[0], XtNleftBitmap, None);
6363 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6367 void AnimateMovingProc(w, event, prms, nprms)
6375 appData.animate = !appData.animate;
6377 if (appData.animate) {
6378 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6381 XtSetArg(args[0], XtNleftBitmap, None);
6383 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6387 void AutoflagProc(w, event, prms, nprms)
6395 appData.autoCallFlag = !appData.autoCallFlag;
6397 if (appData.autoCallFlag) {
6398 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6400 XtSetArg(args[0], XtNleftBitmap, None);
6402 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6406 void AutoflipProc(w, event, prms, nprms)
6414 appData.autoFlipView = !appData.autoFlipView;
6416 if (appData.autoFlipView) {
6417 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6419 XtSetArg(args[0], XtNleftBitmap, None);
6421 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6425 void BlindfoldProc(w, event, prms, nprms)
6433 appData.blindfold = !appData.blindfold;
6435 if (appData.blindfold) {
6436 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6438 XtSetArg(args[0], XtNleftBitmap, None);
6440 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6443 DrawPosition(True, NULL);
6446 void TestLegalityProc(w, event, prms, nprms)
6454 appData.testLegality = !appData.testLegality;
6456 if (appData.testLegality) {
6457 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6459 XtSetArg(args[0], XtNleftBitmap, None);
6461 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6466 void FlashMovesProc(w, event, prms, nprms)
6474 if (appData.flashCount == 0) {
6475 appData.flashCount = 3;
6477 appData.flashCount = -appData.flashCount;
6480 if (appData.flashCount > 0) {
6481 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6483 XtSetArg(args[0], XtNleftBitmap, None);
6485 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6490 void HighlightDraggingProc(w, event, prms, nprms)
6498 appData.highlightDragging = !appData.highlightDragging;
6500 if (appData.highlightDragging) {
6501 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6503 XtSetArg(args[0], XtNleftBitmap, None);
6505 XtSetValues(XtNameToWidget(menuBarWidget,
6506 "menuOptions.Highlight Dragging"), args, 1);
6510 void HighlightLastMoveProc(w, event, prms, nprms)
6518 appData.highlightLastMove = !appData.highlightLastMove;
6520 if (appData.highlightLastMove) {
6521 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6523 XtSetArg(args[0], XtNleftBitmap, None);
6525 XtSetValues(XtNameToWidget(menuBarWidget,
6526 "menuOptions.Highlight Last Move"), args, 1);
6529 void HighlightArrowProc(w, event, prms, nprms)
6537 appData.highlightMoveWithArrow = !appData.highlightMoveWithArrow;
6539 if (appData.highlightMoveWithArrow) {
6540 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6542 XtSetArg(args[0], XtNleftBitmap, None);
6544 XtSetValues(XtNameToWidget(menuBarWidget,
6545 "menuOptions.Arrow"), args, 1);
6549 void IcsAlarmProc(w, event, prms, nprms)
6557 appData.icsAlarm = !appData.icsAlarm;
6559 if (appData.icsAlarm) {
6560 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6562 XtSetArg(args[0], XtNleftBitmap, None);
6564 XtSetValues(XtNameToWidget(menuBarWidget,
6565 "menuOptions.ICS Alarm"), args, 1);
6569 void MoveSoundProc(w, event, prms, nprms)
6577 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6579 if (appData.ringBellAfterMoves) {
6580 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6582 XtSetArg(args[0], XtNleftBitmap, None);
6584 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6588 void OneClickProc(w, event, prms, nprms)
6596 appData.oneClick = !appData.oneClick;
6598 if (appData.oneClick) {
6599 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6601 XtSetArg(args[0], XtNleftBitmap, None);
6603 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.OneClick"),
6607 void PeriodicUpdatesProc(w, event, prms, nprms)
6615 PeriodicUpdatesEvent(!appData.periodicUpdates);
6617 if (appData.periodicUpdates) {
6618 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6620 XtSetArg(args[0], XtNleftBitmap, None);
6622 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6626 void PopupExitMessageProc(w, event, prms, nprms)
6634 appData.popupExitMessage = !appData.popupExitMessage;
6636 if (appData.popupExitMessage) {
6637 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6639 XtSetArg(args[0], XtNleftBitmap, None);
6641 XtSetValues(XtNameToWidget(menuBarWidget,
6642 "menuOptions.Popup Exit Message"), args, 1);
6645 void PopupMoveErrorsProc(w, event, prms, nprms)
6653 appData.popupMoveErrors = !appData.popupMoveErrors;
6655 if (appData.popupMoveErrors) {
6656 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6658 XtSetArg(args[0], XtNleftBitmap, None);
6660 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6665 void PremoveProc(w, event, prms, nprms)
6673 appData.premove = !appData.premove;
6675 if (appData.premove) {
6676 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6678 XtSetArg(args[0], XtNleftBitmap, None);
6680 XtSetValues(XtNameToWidget(menuBarWidget,
6681 "menuOptions.Premove"), args, 1);
6685 void ShowCoordsProc(w, event, prms, nprms)
6693 appData.showCoords = !appData.showCoords;
6695 if (appData.showCoords) {
6696 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6698 XtSetArg(args[0], XtNleftBitmap, None);
6700 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6703 DrawPosition(True, NULL);
6706 void ShowThinkingProc(w, event, prms, nprms)
6712 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6713 ShowThinkingEvent();
6716 void HideThinkingProc(w, event, prms, nprms)
6724 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6725 ShowThinkingEvent();
6727 if (appData.hideThinkingFromHuman) {
6728 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6730 XtSetArg(args[0], XtNleftBitmap, None);
6732 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6737 void SaveOnExitProc(w, event, prms, nprms)
6745 saveSettingsOnExit = !saveSettingsOnExit;
6747 if (saveSettingsOnExit) {
6748 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6750 XtSetArg(args[0], XtNleftBitmap, None);
6752 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6756 void SaveSettingsProc(w, event, prms, nprms)
6762 SaveSettings(settingsFileName);
6765 void InfoProc(w, event, prms, nprms)
6772 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6777 void ManProc(w, event, prms, nprms)
6785 if (nprms && *nprms > 0)
6789 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6793 void HintProc(w, event, prms, nprms)
6802 void BookProc(w, event, prms, nprms)
6811 void AboutProc(w, event, prms, nprms)
6819 char *zippy = " (with Zippy code)";
6823 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6824 programVersion, zippy,
6825 "Copyright 1991 Digital Equipment Corporation",
6826 "Enhancements Copyright 1992-2009 Free Software Foundation",
6827 "Enhancements Copyright 2005 Alessandro Scotti",
6828 PACKAGE, " is free software and carries NO WARRANTY;",
6829 "see the file COPYING for more information.");
6830 ErrorPopUp(_("About XBoard"), buf, FALSE);
6833 void DebugProc(w, event, prms, nprms)
6839 appData.debugMode = !appData.debugMode;
6842 void AboutGameProc(w, event, prms, nprms)
6851 void NothingProc(w, event, prms, nprms)
6860 void Iconify(w, event, prms, nprms)
6869 XtSetArg(args[0], XtNiconic, True);
6870 XtSetValues(shellWidget, args, 1);
6873 void DisplayMessage(message, extMessage)
6874 char *message, *extMessage;
6876 /* display a message in the message widget */
6885 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
6890 message = extMessage;
6894 safeStrCpy(lastMsg, message, MSG_SIZ); // [HGM] make available
6896 /* need to test if messageWidget already exists, since this function
6897 can also be called during the startup, if for example a Xresource
6898 is not set up correctly */
6901 XtSetArg(arg, XtNlabel, message);
6902 XtSetValues(messageWidget, &arg, 1);
6908 void DisplayTitle(text)
6913 char title[MSG_SIZ];
6916 if (text == NULL) text = "";
6918 if (appData.titleInWindow) {
6920 XtSetArg(args[i], XtNlabel, text); i++;
6921 XtSetValues(titleWidget, args, i);
6924 if (*text != NULLCHAR) {
6925 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
6926 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
6927 } else if (appData.icsActive) {
6928 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
6929 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
6930 } else if (appData.cmailGameName[0] != NULLCHAR) {
6931 snprintf(icon, sizeof(icon), "%s", "CMail");
6932 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
6934 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
6935 } else if (gameInfo.variant == VariantGothic) {
6936 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6937 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
6940 } else if (gameInfo.variant == VariantFalcon) {
6941 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6942 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
6944 } else if (appData.noChessProgram) {
6945 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6946 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
6948 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
6949 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
6952 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
6953 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
6954 XtSetValues(shellWidget, args, i);
6955 XSync(xDisplay, False);
6960 DisplayError(message, error)
6967 if (appData.debugMode || appData.matchMode) {
6968 fprintf(stderr, "%s: %s\n", programName, message);
6971 if (appData.debugMode || appData.matchMode) {
6972 fprintf(stderr, "%s: %s: %s\n",
6973 programName, message, strerror(error));
6975 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6978 ErrorPopUp(_("Error"), message, FALSE);
6982 void DisplayMoveError(message)
6987 DrawPosition(FALSE, NULL);
6988 if (appData.debugMode || appData.matchMode) {
6989 fprintf(stderr, "%s: %s\n", programName, message);
6991 if (appData.popupMoveErrors) {
6992 ErrorPopUp(_("Error"), message, FALSE);
6994 DisplayMessage(message, "");
6999 void DisplayFatalError(message, error, status)
7005 errorExitStatus = status;
7007 fprintf(stderr, "%s: %s\n", programName, message);
7009 fprintf(stderr, "%s: %s: %s\n",
7010 programName, message, strerror(error));
7011 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7014 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7015 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7021 void DisplayInformation(message)
7025 ErrorPopUp(_("Information"), message, TRUE);
7028 void DisplayNote(message)
7032 ErrorPopUp(_("Note"), message, FALSE);
7036 NullXErrorCheck(dpy, error_event)
7038 XErrorEvent *error_event;
7043 void DisplayIcsInteractionTitle(message)
7046 if (oldICSInteractionTitle == NULL) {
7047 /* Magic to find the old window title, adapted from vim */
7048 char *wina = getenv("WINDOWID");
7050 Window win = (Window) atoi(wina);
7051 Window root, parent, *children;
7052 unsigned int nchildren;
7053 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7055 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7056 if (!XQueryTree(xDisplay, win, &root, &parent,
7057 &children, &nchildren)) break;
7058 if (children) XFree((void *)children);
7059 if (parent == root || parent == 0) break;
7062 XSetErrorHandler(oldHandler);
7064 if (oldICSInteractionTitle == NULL) {
7065 oldICSInteractionTitle = "xterm";
7068 printf("\033]0;%s\007", message);
7072 char pendingReplyPrefix[MSG_SIZ];
7073 ProcRef pendingReplyPR;
7075 void AskQuestionProc(w, event, prms, nprms)
7082 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7086 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7089 void AskQuestionPopDown()
7091 if (!askQuestionUp) return;
7092 XtPopdown(askQuestionShell);
7093 XtDestroyWidget(askQuestionShell);
7094 askQuestionUp = False;
7097 void AskQuestionReplyAction(w, event, prms, nprms)
7107 reply = XawDialogGetValueString(w = XtParent(w));
7108 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
7109 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
7110 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
7111 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
7112 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7113 AskQuestionPopDown();
7115 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7118 void AskQuestionCallback(w, client_data, call_data)
7120 XtPointer client_data, call_data;
7125 XtSetArg(args[0], XtNlabel, &name);
7126 XtGetValues(w, args, 1);
7128 if (strcmp(name, _("cancel")) == 0) {
7129 AskQuestionPopDown();
7131 AskQuestionReplyAction(w, NULL, NULL, NULL);
7135 void AskQuestion(title, question, replyPrefix, pr)
7136 char *title, *question, *replyPrefix;
7140 Widget popup, layout, dialog, edit;
7146 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
7147 pendingReplyPR = pr;
7150 XtSetArg(args[i], XtNresizable, True); i++;
7151 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7152 askQuestionShell = popup =
7153 XtCreatePopupShell(title, transientShellWidgetClass,
7154 shellWidget, args, i);
7157 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7158 layoutArgs, XtNumber(layoutArgs));
7161 XtSetArg(args[i], XtNlabel, question); i++;
7162 XtSetArg(args[i], XtNvalue, ""); i++;
7163 XtSetArg(args[i], XtNborderWidth, 0); i++;
7164 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7167 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7168 (XtPointer) dialog);
7169 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7170 (XtPointer) dialog);
7172 XtRealizeWidget(popup);
7173 CatchDeleteWindow(popup, "AskQuestionPopDown");
7175 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7176 &x, &y, &win_x, &win_y, &mask);
7178 XtSetArg(args[0], XtNx, x - 10);
7179 XtSetArg(args[1], XtNy, y - 30);
7180 XtSetValues(popup, args, 2);
7182 XtPopup(popup, XtGrabExclusive);
7183 askQuestionUp = True;
7185 edit = XtNameToWidget(dialog, "*value");
7186 XtSetKeyboardFocus(popup, edit);
7194 if (*name == NULLCHAR) {
7196 } else if (strcmp(name, "$") == 0) {
7197 putc(BELLCHAR, stderr);
7200 char *prefix = "", *sep = "";
7201 if(!strchr(name, '/')) { prefix = appData.soundDirectory; sep = "/"; }
7202 snprintf(buf, sizeof(buf), "%s '%s%s%s' &", appData.soundProgram, prefix, sep, name);
7210 PlaySound(appData.soundMove);
7216 PlaySound(appData.soundIcsWin);
7222 PlaySound(appData.soundIcsLoss);
7228 PlaySound(appData.soundIcsDraw);
7232 PlayIcsUnfinishedSound()
7234 PlaySound(appData.soundIcsUnfinished);
7240 PlaySound(appData.soundIcsAlarm);
7246 PlaySound(appData.soundTell);
7252 system("stty echo");
7259 system("stty -echo");
7264 Colorize(cc, continuation)
7269 int count, outCount, error;
7271 if (textColors[(int)cc].bg > 0) {
7272 if (textColors[(int)cc].fg > 0) {
7273 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7274 textColors[(int)cc].fg, textColors[(int)cc].bg);
7276 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7277 textColors[(int)cc].bg);
7280 if (textColors[(int)cc].fg > 0) {
7281 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7282 textColors[(int)cc].fg);
7284 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7287 count = strlen(buf);
7288 outCount = OutputToProcess(NoProc, buf, count, &error);
7289 if (outCount < count) {
7290 DisplayFatalError(_("Error writing to display"), error, 1);
7293 if (continuation) return;
7296 PlaySound(appData.soundShout);
7299 PlaySound(appData.soundSShout);
7302 PlaySound(appData.soundChannel1);
7305 PlaySound(appData.soundChannel);
7308 PlaySound(appData.soundKibitz);
7311 PlaySound(appData.soundTell);
7313 case ColorChallenge:
7314 PlaySound(appData.soundChallenge);
7317 PlaySound(appData.soundRequest);
7320 PlaySound(appData.soundSeek);
7331 return getpwuid(getuid())->pw_name;
7335 ExpandPathName(path)
7338 static char static_buf[4*MSG_SIZ];
7339 char *d, *s, buf[4*MSG_SIZ];
7345 while (*s && isspace(*s))
7354 if (*(s+1) == '/') {
7355 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7359 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7360 { char *p; if(p = strchr(buf, '/')) *p = 0; }
7361 pwd = getpwnam(buf);
7364 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7368 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7369 strcat(d, strchr(s+1, '/'));
7373 safeStrCpy(d, s, 4*MSG_SIZ );
7380 static char host_name[MSG_SIZ];
7382 #if HAVE_GETHOSTNAME
7383 gethostname(host_name, MSG_SIZ);
7385 #else /* not HAVE_GETHOSTNAME */
7386 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7387 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7389 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7391 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7392 #endif /* not HAVE_GETHOSTNAME */
7395 XtIntervalId delayedEventTimerXID = 0;
7396 DelayedEventCallback delayedEventCallback = 0;
7401 delayedEventTimerXID = 0;
7402 delayedEventCallback();
7406 ScheduleDelayedEvent(cb, millisec)
7407 DelayedEventCallback cb; long millisec;
7409 if(delayedEventTimerXID && delayedEventCallback == cb)
7410 // [HGM] alive: replace, rather than add or flush identical event
7411 XtRemoveTimeOut(delayedEventTimerXID);
7412 delayedEventCallback = cb;
7413 delayedEventTimerXID =
7414 XtAppAddTimeOut(appContext, millisec,
7415 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7418 DelayedEventCallback
7421 if (delayedEventTimerXID) {
7422 return delayedEventCallback;
7429 CancelDelayedEvent()
7431 if (delayedEventTimerXID) {
7432 XtRemoveTimeOut(delayedEventTimerXID);
7433 delayedEventTimerXID = 0;
7437 XtIntervalId loadGameTimerXID = 0;
7439 int LoadGameTimerRunning()
7441 return loadGameTimerXID != 0;
7444 int StopLoadGameTimer()
7446 if (loadGameTimerXID != 0) {
7447 XtRemoveTimeOut(loadGameTimerXID);
7448 loadGameTimerXID = 0;
7456 LoadGameTimerCallback(arg, id)
7460 loadGameTimerXID = 0;
7465 StartLoadGameTimer(millisec)
7469 XtAppAddTimeOut(appContext, millisec,
7470 (XtTimerCallbackProc) LoadGameTimerCallback,
7474 XtIntervalId analysisClockXID = 0;
7477 AnalysisClockCallback(arg, id)
7481 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7482 || appData.icsEngineAnalyze) { // [DM]
7483 AnalysisPeriodicEvent(0);
7484 StartAnalysisClock();
7489 StartAnalysisClock()
7492 XtAppAddTimeOut(appContext, 2000,
7493 (XtTimerCallbackProc) AnalysisClockCallback,
7497 XtIntervalId clockTimerXID = 0;
7499 int ClockTimerRunning()
7501 return clockTimerXID != 0;
7504 int StopClockTimer()
7506 if (clockTimerXID != 0) {
7507 XtRemoveTimeOut(clockTimerXID);
7516 ClockTimerCallback(arg, id)
7525 StartClockTimer(millisec)
7529 XtAppAddTimeOut(appContext, millisec,
7530 (XtTimerCallbackProc) ClockTimerCallback,
7535 DisplayTimerLabel(w, color, timer, highlight)
7544 /* check for low time warning */
7545 Pixel foregroundOrWarningColor = timerForegroundPixel;
7548 appData.lowTimeWarning &&
7549 (timer / 1000) < appData.icsAlarmTime)
7550 foregroundOrWarningColor = lowTimeWarningColor;
7552 if (appData.clockMode) {
7553 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7554 XtSetArg(args[0], XtNlabel, buf);
7556 snprintf(buf, MSG_SIZ, "%s ", color);
7557 XtSetArg(args[0], XtNlabel, buf);
7562 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7563 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7565 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7566 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7569 XtSetValues(w, args, 3);
7573 DisplayWhiteClock(timeRemaining, highlight)
7579 if(appData.noGUI) return;
7580 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7581 if (highlight && iconPixmap == bIconPixmap) {
7582 iconPixmap = wIconPixmap;
7583 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7584 XtSetValues(shellWidget, args, 1);
7589 DisplayBlackClock(timeRemaining, highlight)
7595 if(appData.noGUI) return;
7596 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7597 if (highlight && iconPixmap == wIconPixmap) {
7598 iconPixmap = bIconPixmap;
7599 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7600 XtSetValues(shellWidget, args, 1);
7618 int StartChildProcess(cmdLine, dir, pr)
7625 int to_prog[2], from_prog[2];
7629 if (appData.debugMode) {
7630 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7633 /* We do NOT feed the cmdLine to the shell; we just
7634 parse it into blank-separated arguments in the
7635 most simple-minded way possible.
7638 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7641 while(*p == ' ') p++;
7643 if(*p == '"' || *p == '\'')
7644 p = strchr(++argv[i-1], *p);
7645 else p = strchr(p, ' ');
7646 if (p == NULL) break;
7651 SetUpChildIO(to_prog, from_prog);
7653 if ((pid = fork()) == 0) {
7655 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7656 close(to_prog[1]); // first close the unused pipe ends
7657 close(from_prog[0]);
7658 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7659 dup2(from_prog[1], 1);
7660 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7661 close(from_prog[1]); // and closing again loses one of the pipes!
7662 if(fileno(stderr) >= 2) // better safe than sorry...
7663 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7665 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7670 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7672 execvp(argv[0], argv);
7674 /* If we get here, exec failed */
7679 /* Parent process */
7681 close(from_prog[1]);
7683 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7686 cp->fdFrom = from_prog[0];
7687 cp->fdTo = to_prog[1];
7692 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7693 static RETSIGTYPE AlarmCallBack(int n)
7699 DestroyChildProcess(pr, signalType)
7703 ChildProc *cp = (ChildProc *) pr;
7705 if (cp->kind != CPReal) return;
7707 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7708 signal(SIGALRM, AlarmCallBack);
7710 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7711 kill(cp->pid, SIGKILL); // kill it forcefully
7712 wait((int *) 0); // and wait again
7716 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7718 /* Process is exiting either because of the kill or because of
7719 a quit command sent by the backend; either way, wait for it to die.
7728 InterruptChildProcess(pr)
7731 ChildProc *cp = (ChildProc *) pr;
7733 if (cp->kind != CPReal) return;
7734 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7737 int OpenTelnet(host, port, pr)
7742 char cmdLine[MSG_SIZ];
7744 if (port[0] == NULLCHAR) {
7745 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7747 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7749 return StartChildProcess(cmdLine, "", pr);
7752 int OpenTCP(host, port, pr)
7758 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7759 #else /* !OMIT_SOCKETS */
7760 struct addrinfo hints;
7761 struct addrinfo *ais, *ai;
7766 memset(&hints, 0, sizeof(hints));
7767 hints.ai_family = AF_UNSPEC;
7768 hints.ai_socktype = SOCK_STREAM;
7770 error = getaddrinfo(host, port, &hints, &ais);
7772 /* a getaddrinfo error is not an errno, so can't return it */
7773 fprintf(debugFP, "getaddrinfo(%s, %s): %s\n",
7774 host, port, gai_strerror(error));
7778 for (ai = ais; ai != NULL; ai = ai->ai_next) {
7779 if ((s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) < 0) {
7783 if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0) {
7796 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7802 #endif /* !OMIT_SOCKETS */
7807 int OpenCommPort(name, pr)
7814 fd = open(name, 2, 0);
7815 if (fd < 0) return errno;
7817 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7827 int OpenLoopback(pr)
7833 SetUpChildIO(to, from);
7835 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7838 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7845 int OpenRcmd(host, user, cmd, pr)
7846 char *host, *user, *cmd;
7849 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7853 #define INPUT_SOURCE_BUF_SIZE 8192
7862 char buf[INPUT_SOURCE_BUF_SIZE];
7867 DoInputCallback(closure, source, xid)
7872 InputSource *is = (InputSource *) closure;
7877 if (is->lineByLine) {
7878 count = read(is->fd, is->unused,
7879 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7881 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7884 is->unused += count;
7886 while (p < is->unused) {
7887 q = memchr(p, '\n', is->unused - p);
7888 if (q == NULL) break;
7890 (is->func)(is, is->closure, p, q - p, 0);
7894 while (p < is->unused) {
7899 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
7904 (is->func)(is, is->closure, is->buf, count, error);
7908 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
7915 ChildProc *cp = (ChildProc *) pr;
7917 is = (InputSource *) calloc(1, sizeof(InputSource));
7918 is->lineByLine = lineByLine;
7922 is->fd = fileno(stdin);
7924 is->kind = cp->kind;
7925 is->fd = cp->fdFrom;
7928 is->unused = is->buf;
7931 is->xid = XtAppAddInput(appContext, is->fd,
7932 (XtPointer) (XtInputReadMask),
7933 (XtInputCallbackProc) DoInputCallback,
7935 is->closure = closure;
7936 return (InputSourceRef) is;
7940 RemoveInputSource(isr)
7943 InputSource *is = (InputSource *) isr;
7945 if (is->xid == 0) return;
7946 XtRemoveInput(is->xid);
7950 int OutputToProcess(pr, message, count, outError)
7956 static int line = 0;
7957 ChildProc *cp = (ChildProc *) pr;
7962 if (appData.noJoin || !appData.useInternalWrap)
7963 outCount = fwrite(message, 1, count, stdout);
7966 int width = get_term_width();
7967 int len = wrap(NULL, message, count, width, &line);
7968 char *msg = malloc(len);
7972 outCount = fwrite(message, 1, count, stdout);
7975 dbgchk = wrap(msg, message, count, width, &line);
7976 if (dbgchk != len && appData.debugMode)
7977 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
7978 outCount = fwrite(msg, 1, dbgchk, stdout);
7984 outCount = write(cp->fdTo, message, count);
7994 /* Output message to process, with "ms" milliseconds of delay
7995 between each character. This is needed when sending the logon
7996 script to ICC, which for some reason doesn't like the
7997 instantaneous send. */
7998 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8005 ChildProc *cp = (ChildProc *) pr;
8010 r = write(cp->fdTo, message++, 1);
8023 /**** Animation code by Hugh Fisher, DCS, ANU.
8025 Known problem: if a window overlapping the board is
8026 moved away while a piece is being animated underneath,
8027 the newly exposed area won't be updated properly.
8028 I can live with this.
8030 Known problem: if you look carefully at the animation
8031 of pieces in mono mode, they are being drawn as solid
8032 shapes without interior detail while moving. Fixing
8033 this would be a major complication for minimal return.
8036 /* Masks for XPM pieces. Black and white pieces can have
8037 different shapes, but in the interest of retaining my
8038 sanity pieces must have the same outline on both light
8039 and dark squares, and all pieces must use the same
8040 background square colors/images. */
8042 static int xpmDone = 0;
8045 CreateAnimMasks (pieceDepth)
8052 unsigned long plane;
8055 /* Need a bitmap just to get a GC with right depth */
8056 buf = XCreatePixmap(xDisplay, xBoardWindow,
8058 values.foreground = 1;
8059 values.background = 0;
8060 /* Don't use XtGetGC, not read only */
8061 maskGC = XCreateGC(xDisplay, buf,
8062 GCForeground | GCBackground, &values);
8063 XFreePixmap(xDisplay, buf);
8065 buf = XCreatePixmap(xDisplay, xBoardWindow,
8066 squareSize, squareSize, pieceDepth);
8067 values.foreground = XBlackPixel(xDisplay, xScreen);
8068 values.background = XWhitePixel(xDisplay, xScreen);
8069 bufGC = XCreateGC(xDisplay, buf,
8070 GCForeground | GCBackground, &values);
8072 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8073 /* Begin with empty mask */
8074 if(!xpmDone) // [HGM] pieces: keep using existing
8075 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8076 squareSize, squareSize, 1);
8077 XSetFunction(xDisplay, maskGC, GXclear);
8078 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8079 0, 0, squareSize, squareSize);
8081 /* Take a copy of the piece */
8086 XSetFunction(xDisplay, bufGC, GXcopy);
8087 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8089 0, 0, squareSize, squareSize, 0, 0);
8091 /* XOR the background (light) over the piece */
8092 XSetFunction(xDisplay, bufGC, GXxor);
8094 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8095 0, 0, squareSize, squareSize, 0, 0);
8097 XSetForeground(xDisplay, bufGC, lightSquareColor);
8098 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8101 /* We now have an inverted piece image with the background
8102 erased. Construct mask by just selecting all the non-zero
8103 pixels - no need to reconstruct the original image. */
8104 XSetFunction(xDisplay, maskGC, GXor);
8106 /* Might be quicker to download an XImage and create bitmap
8107 data from it rather than this N copies per piece, but it
8108 only takes a fraction of a second and there is a much
8109 longer delay for loading the pieces. */
8110 for (n = 0; n < pieceDepth; n ++) {
8111 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8112 0, 0, squareSize, squareSize,
8118 XFreePixmap(xDisplay, buf);
8119 XFreeGC(xDisplay, bufGC);
8120 XFreeGC(xDisplay, maskGC);
8124 InitAnimState (anim, info)
8126 XWindowAttributes * info;
8131 /* Each buffer is square size, same depth as window */
8132 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8133 squareSize, squareSize, info->depth);
8134 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8135 squareSize, squareSize, info->depth);
8137 /* Create a plain GC for blitting */
8138 mask = GCForeground | GCBackground | GCFunction |
8139 GCPlaneMask | GCGraphicsExposures;
8140 values.foreground = XBlackPixel(xDisplay, xScreen);
8141 values.background = XWhitePixel(xDisplay, xScreen);
8142 values.function = GXcopy;
8143 values.plane_mask = AllPlanes;
8144 values.graphics_exposures = False;
8145 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8147 /* Piece will be copied from an existing context at
8148 the start of each new animation/drag. */
8149 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8151 /* Outline will be a read-only copy of an existing */
8152 anim->outlineGC = None;
8158 XWindowAttributes info;
8160 if (xpmDone && gameInfo.variant == oldVariant) return;
8161 if(xpmDone) oldVariant = gameInfo.variant; // first time pieces might not be created yet
8162 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8164 InitAnimState(&game, &info);
8165 InitAnimState(&player, &info);
8167 /* For XPM pieces, we need bitmaps to use as masks. */
8169 CreateAnimMasks(info.depth), xpmDone = 1;
8174 static Boolean frameWaiting;
8176 static RETSIGTYPE FrameAlarm (sig)
8179 frameWaiting = False;
8180 /* In case System-V style signals. Needed?? */
8181 signal(SIGALRM, FrameAlarm);
8188 struct itimerval delay;
8190 XSync(xDisplay, False);
8193 frameWaiting = True;
8194 signal(SIGALRM, FrameAlarm);
8195 delay.it_interval.tv_sec =
8196 delay.it_value.tv_sec = time / 1000;
8197 delay.it_interval.tv_usec =
8198 delay.it_value.tv_usec = (time % 1000) * 1000;
8199 setitimer(ITIMER_REAL, &delay, NULL);
8200 while (frameWaiting) pause();
8201 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8202 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8203 setitimer(ITIMER_REAL, &delay, NULL);
8213 XSync(xDisplay, False);
8215 usleep(time * 1000);
8220 /* Convert board position to corner of screen rect and color */
8223 ScreenSquare(column, row, pt, color)
8224 int column; int row; XPoint * pt; int * color;
8227 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8228 pt->y = lineGap + row * (squareSize + lineGap);
8230 pt->x = lineGap + column * (squareSize + lineGap);
8231 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8233 *color = SquareColor(row, column);
8236 /* Convert window coords to square */
8239 BoardSquare(x, y, column, row)
8240 int x; int y; int * column; int * row;
8242 *column = EventToSquare(x, BOARD_WIDTH);
8243 if (flipView && *column >= 0)
8244 *column = BOARD_WIDTH - 1 - *column;
8245 *row = EventToSquare(y, BOARD_HEIGHT);
8246 if (!flipView && *row >= 0)
8247 *row = BOARD_HEIGHT - 1 - *row;
8252 #undef Max /* just in case */
8254 #define Max(a, b) ((a) > (b) ? (a) : (b))
8255 #define Min(a, b) ((a) < (b) ? (a) : (b))
8258 SetRect(rect, x, y, width, height)
8259 XRectangle * rect; int x; int y; int width; int height;
8263 rect->width = width;
8264 rect->height = height;
8267 /* Test if two frames overlap. If they do, return
8268 intersection rect within old and location of
8269 that rect within new. */
8272 Intersect(old, new, size, area, pt)
8273 XPoint * old; XPoint * new;
8274 int size; XRectangle * area; XPoint * pt;
8276 if (old->x > new->x + size || new->x > old->x + size ||
8277 old->y > new->y + size || new->y > old->y + size) {
8280 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8281 size - abs(old->x - new->x), size - abs(old->y - new->y));
8282 pt->x = Max(old->x - new->x, 0);
8283 pt->y = Max(old->y - new->y, 0);
8288 /* For two overlapping frames, return the rect(s)
8289 in the old that do not intersect with the new. */
8292 CalcUpdateRects(old, new, size, update, nUpdates)
8293 XPoint * old; XPoint * new; int size;
8294 XRectangle update[]; int * nUpdates;
8298 /* If old = new (shouldn't happen) then nothing to draw */
8299 if (old->x == new->x && old->y == new->y) {
8303 /* Work out what bits overlap. Since we know the rects
8304 are the same size we don't need a full intersect calc. */
8306 /* Top or bottom edge? */
8307 if (new->y > old->y) {
8308 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8310 } else if (old->y > new->y) {
8311 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8312 size, old->y - new->y);
8315 /* Left or right edge - don't overlap any update calculated above. */
8316 if (new->x > old->x) {
8317 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8318 new->x - old->x, size - abs(new->y - old->y));
8320 } else if (old->x > new->x) {
8321 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8322 old->x - new->x, size - abs(new->y - old->y));
8329 /* Generate a series of frame coords from start->mid->finish.
8330 The movement rate doubles until the half way point is
8331 reached, then halves back down to the final destination,
8332 which gives a nice slow in/out effect. The algorithmn
8333 may seem to generate too many intermediates for short
8334 moves, but remember that the purpose is to attract the
8335 viewers attention to the piece about to be moved and
8336 then to where it ends up. Too few frames would be less
8340 Tween(start, mid, finish, factor, frames, nFrames)
8341 XPoint * start; XPoint * mid;
8342 XPoint * finish; int factor;
8343 XPoint frames[]; int * nFrames;
8345 int fraction, n, count;
8349 /* Slow in, stepping 1/16th, then 1/8th, ... */
8351 for (n = 0; n < factor; n++)
8353 for (n = 0; n < factor; n++) {
8354 frames[count].x = start->x + (mid->x - start->x) / fraction;
8355 frames[count].y = start->y + (mid->y - start->y) / fraction;
8357 fraction = fraction / 2;
8361 frames[count] = *mid;
8364 /* Slow out, stepping 1/2, then 1/4, ... */
8366 for (n = 0; n < factor; n++) {
8367 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8368 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8370 fraction = fraction * 2;
8375 /* Draw a piece on the screen without disturbing what's there */
8378 SelectGCMask(piece, clip, outline, mask)
8379 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8383 /* Bitmap for piece being moved. */
8384 if (appData.monoMode) {
8385 *mask = *pieceToSolid(piece);
8386 } else if (useImages) {
8388 *mask = xpmMask[piece];
8390 *mask = ximMaskPm[piece];
8393 *mask = *pieceToSolid(piece);
8396 /* GC for piece being moved. Square color doesn't matter, but
8397 since it gets modified we make a copy of the original. */
8399 if (appData.monoMode)
8404 if (appData.monoMode)
8409 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8411 /* Outline only used in mono mode and is not modified */
8413 *outline = bwPieceGC;
8415 *outline = wbPieceGC;
8419 OverlayPiece(piece, clip, outline, dest)
8420 ChessSquare piece; GC clip; GC outline; Drawable dest;
8425 /* Draw solid rectangle which will be clipped to shape of piece */
8426 XFillRectangle(xDisplay, dest, clip,
8427 0, 0, squareSize, squareSize);
8428 if (appData.monoMode)
8429 /* Also draw outline in contrasting color for black
8430 on black / white on white cases */
8431 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8432 0, 0, squareSize, squareSize, 0, 0, 1);
8434 /* Copy the piece */
8439 if(appData.upsideDown && flipView) kind ^= 2;
8440 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8442 0, 0, squareSize, squareSize,
8447 /* Animate the movement of a single piece */
8450 BeginAnimation(anim, piece, startColor, start)
8458 if(appData.upsideDown && flipView) piece += piece < BlackPawn ? BlackPawn : -BlackPawn;
8459 /* The old buffer is initialised with the start square (empty) */
8460 BlankSquare(start->x, start->y, startColor, EmptySquare, anim->saveBuf, 0);
8461 anim->prevFrame = *start;
8463 /* The piece will be drawn using its own bitmap as a matte */
8464 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8465 XSetClipMask(xDisplay, anim->pieceGC, mask);
8469 AnimationFrame(anim, frame, piece)
8474 XRectangle updates[4];
8479 /* Save what we are about to draw into the new buffer */
8480 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8481 frame->x, frame->y, squareSize, squareSize,
8484 /* Erase bits of the previous frame */
8485 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8486 /* Where the new frame overlapped the previous,
8487 the contents in newBuf are wrong. */
8488 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8489 overlap.x, overlap.y,
8490 overlap.width, overlap.height,
8492 /* Repaint the areas in the old that don't overlap new */
8493 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8494 for (i = 0; i < count; i++)
8495 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8496 updates[i].x - anim->prevFrame.x,
8497 updates[i].y - anim->prevFrame.y,
8498 updates[i].width, updates[i].height,
8499 updates[i].x, updates[i].y);
8501 /* Easy when no overlap */
8502 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8503 0, 0, squareSize, squareSize,
8504 anim->prevFrame.x, anim->prevFrame.y);
8507 /* Save this frame for next time round */
8508 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8509 0, 0, squareSize, squareSize,
8511 anim->prevFrame = *frame;
8513 /* Draw piece over original screen contents, not current,
8514 and copy entire rect. Wipes out overlapping piece images. */
8515 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8516 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8517 0, 0, squareSize, squareSize,
8518 frame->x, frame->y);
8522 EndAnimation (anim, finish)
8526 XRectangle updates[4];
8531 /* The main code will redraw the final square, so we
8532 only need to erase the bits that don't overlap. */
8533 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8534 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8535 for (i = 0; i < count; i++)
8536 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8537 updates[i].x - anim->prevFrame.x,
8538 updates[i].y - anim->prevFrame.y,
8539 updates[i].width, updates[i].height,
8540 updates[i].x, updates[i].y);
8542 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8543 0, 0, squareSize, squareSize,
8544 anim->prevFrame.x, anim->prevFrame.y);
8549 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8551 ChessSquare piece; int startColor;
8552 XPoint * start; XPoint * finish;
8553 XPoint frames[]; int nFrames;
8557 BeginAnimation(anim, piece, startColor, start);
8558 for (n = 0; n < nFrames; n++) {
8559 AnimationFrame(anim, &(frames[n]), piece);
8560 FrameDelay(appData.animSpeed);
8562 EndAnimation(anim, finish);
8566 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
8569 ChessSquare piece = board[fromY][toY];
8570 board[fromY][toY] = EmptySquare;
8571 DrawPosition(FALSE, board);
8573 x = lineGap + ((BOARD_WIDTH-1)-toX) * (squareSize + lineGap);
8574 y = lineGap + toY * (squareSize + lineGap);
8576 x = lineGap + toX * (squareSize + lineGap);
8577 y = lineGap + ((BOARD_HEIGHT-1)-toY) * (squareSize + lineGap);
8579 for(i=1; i<4*kFactor; i++) {
8580 int r = squareSize * 9 * i/(20*kFactor - 5);
8581 XFillArc(xDisplay, xBoardWindow, highlineGC,
8582 x + squareSize/2 - r, y+squareSize/2 - r, 2*r, 2*r, 0, 64*360);
8583 FrameDelay(appData.animSpeed);
8585 board[fromY][toY] = piece;
8588 /* Main control logic for deciding what to animate and how */
8591 AnimateMove(board, fromX, fromY, toX, toY)
8600 XPoint start, finish, mid;
8601 XPoint frames[kFactor * 2 + 1];
8602 int nFrames, startColor, endColor;
8604 /* Are we animating? */
8605 if (!appData.animate || appData.blindfold)
8608 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8609 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8610 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8612 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8613 piece = board[fromY][fromX];
8614 if (piece >= EmptySquare) return;
8619 hop = abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1;
8622 if (appData.debugMode) {
8623 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8624 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8625 piece, fromX, fromY, toX, toY); }
8627 ScreenSquare(fromX, fromY, &start, &startColor);
8628 ScreenSquare(toX, toY, &finish, &endColor);
8631 /* Knight: make straight movement then diagonal */
8632 if (abs(toY - fromY) < abs(toX - fromX)) {
8633 mid.x = start.x + (finish.x - start.x) / 2;
8637 mid.y = start.y + (finish.y - start.y) / 2;
8640 mid.x = start.x + (finish.x - start.x) / 2;
8641 mid.y = start.y + (finish.y - start.y) / 2;
8644 /* Don't use as many frames for very short moves */
8645 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8646 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8648 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8649 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8650 if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged
8652 for(i=0; i<BOARD_WIDTH; i++) for(j=0; j<BOARD_HEIGHT; j++)
8653 if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] = True;
8656 /* Be sure end square is redrawn */
8657 damage[0][toY][toX] = True;
8661 DragPieceBegin(x, y, instantly)
8662 int x; int y; Boolean instantly;
8664 int boardX, boardY, color;
8667 /* Are we animating? */
8668 if (!appData.animateDragging || appData.blindfold)
8671 /* Figure out which square we start in and the
8672 mouse position relative to top left corner. */
8673 BoardSquare(x, y, &boardX, &boardY);
8674 player.startBoardX = boardX;
8675 player.startBoardY = boardY;
8676 ScreenSquare(boardX, boardY, &corner, &color);
8677 player.startSquare = corner;
8678 player.startColor = color;
8679 /* As soon as we start dragging, the piece will jump slightly to
8680 be centered over the mouse pointer. */
8681 player.mouseDelta.x = squareSize/2;
8682 player.mouseDelta.y = squareSize/2;
8683 /* Initialise animation */
8684 player.dragPiece = PieceForSquare(boardX, boardY);
8686 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8687 player.dragActive = True;
8688 BeginAnimation(&player, player.dragPiece, color, &corner);
8689 /* Mark this square as needing to be redrawn. Note that
8690 we don't remove the piece though, since logically (ie
8691 as seen by opponent) the move hasn't been made yet. */
8692 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8693 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8694 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8695 corner.x, corner.y, squareSize, squareSize,
8696 0, 0); // [HGM] zh: unstack in stead of grab
8697 if(gatingPiece != EmptySquare) {
8698 /* Kludge alert: When gating we want the introduced
8699 piece to appear on the from square. To generate an
8700 image of it, we draw it on the board, copy the image,
8701 and draw the original piece again. */
8702 ChessSquare piece = boards[currentMove][boardY][boardX];
8703 DrawSquare(boardY, boardX, gatingPiece, 0);
8704 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8705 corner.x, corner.y, squareSize, squareSize, 0, 0);
8706 DrawSquare(boardY, boardX, piece, 0);
8708 damage[0][boardY][boardX] = True;
8710 player.dragActive = False;
8715 ChangeDragPiece(ChessSquare piece)
8718 player.dragPiece = piece;
8719 /* The piece will be drawn using its own bitmap as a matte */
8720 SelectGCMask(piece, &player.pieceGC, &player.outlineGC, &mask);
8721 XSetClipMask(xDisplay, player.pieceGC, mask);
8730 /* Are we animating? */
8731 if (!appData.animateDragging || appData.blindfold)
8735 if (! player.dragActive)
8737 /* Move piece, maintaining same relative position
8738 of mouse within square */
8739 corner.x = x - player.mouseDelta.x;
8740 corner.y = y - player.mouseDelta.y;
8741 AnimationFrame(&player, &corner, player.dragPiece);
8743 if (appData.highlightDragging) {
8745 BoardSquare(x, y, &boardX, &boardY);
8746 SetHighlights(fromX, fromY, boardX, boardY);
8755 int boardX, boardY, color;
8758 /* Are we animating? */
8759 if (!appData.animateDragging || appData.blindfold)
8763 if (! player.dragActive)
8765 /* Last frame in sequence is square piece is
8766 placed on, which may not match mouse exactly. */
8767 BoardSquare(x, y, &boardX, &boardY);
8768 ScreenSquare(boardX, boardY, &corner, &color);
8769 EndAnimation(&player, &corner);
8771 /* Be sure end square is redrawn */
8772 damage[0][boardY][boardX] = True;
8774 /* This prevents weird things happening with fast successive
8775 clicks which on my Sun at least can cause motion events
8776 without corresponding press/release. */
8777 player.dragActive = False;
8780 /* Handle expose event while piece being dragged */
8785 if (!player.dragActive || appData.blindfold)
8788 /* What we're doing: logically, the move hasn't been made yet,
8789 so the piece is still in it's original square. But visually
8790 it's being dragged around the board. So we erase the square
8791 that the piece is on and draw it at the last known drag point. */
8792 BlankSquare(player.startSquare.x, player.startSquare.y,
8793 player.startColor, EmptySquare, xBoardWindow, 1);
8794 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8795 damage[0][player.startBoardY][player.startBoardX] = TRUE;
8798 #include <sys/ioctl.h>
8799 int get_term_width()
8801 int fd, default_width;
8804 default_width = 79; // this is FICS default anyway...
8806 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8808 if (!ioctl(fd, TIOCGSIZE, &win))
8809 default_width = win.ts_cols;
8810 #elif defined(TIOCGWINSZ)
8812 if (!ioctl(fd, TIOCGWINSZ, &win))
8813 default_width = win.ws_col;
8815 return default_width;
8821 static int old_width = 0;
8822 int new_width = get_term_width();
8824 if (old_width != new_width)
8825 ics_printf("set width %d\n", new_width);
8826 old_width = new_width;
8829 void NotifyFrontendLogin()
8834 /* [AS] Arrow highlighting support */
8836 static double A_WIDTH = 5; /* Width of arrow body */
8838 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
8839 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
8841 static double Sqr( double x )
8846 static int Round( double x )
8848 return (int) (x + 0.5);
8851 void SquareToPos(int rank, int file, int *x, int *y)
8854 *x = lineGap + ((BOARD_WIDTH-1)-file) * (squareSize + lineGap);
8855 *y = lineGap + rank * (squareSize + lineGap);
8857 *x = lineGap + file * (squareSize + lineGap);
8858 *y = lineGap + ((BOARD_HEIGHT-1)-rank) * (squareSize + lineGap);
8862 /* Draw an arrow between two points using current settings */
8863 void DrawArrowBetweenPoints( int s_x, int s_y, int d_x, int d_y )
8866 double dx, dy, j, k, x, y;
8869 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
8871 arrow[0].x = s_x + A_WIDTH + 0.5;
8874 arrow[1].x = s_x + A_WIDTH + 0.5;
8875 arrow[1].y = d_y - h;
8877 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8878 arrow[2].y = d_y - h;
8883 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
8884 arrow[5].y = d_y - h;
8886 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8887 arrow[4].y = d_y - h;
8889 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
8892 else if( d_y == s_y ) {
8893 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
8896 arrow[0].y = s_y + A_WIDTH + 0.5;
8898 arrow[1].x = d_x - w;
8899 arrow[1].y = s_y + A_WIDTH + 0.5;
8901 arrow[2].x = d_x - w;
8902 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8907 arrow[5].x = d_x - w;
8908 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
8910 arrow[4].x = d_x - w;
8911 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8914 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
8917 /* [AS] Needed a lot of paper for this! :-) */
8918 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
8919 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
8921 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
8923 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
8928 arrow[0].x = Round(x - j);
8929 arrow[0].y = Round(y + j*dx);
8931 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
8932 arrow[1].y = Round(arrow[0].y - 2*j*dx);
8935 x = (double) d_x - k;
8936 y = (double) d_y - k*dy;
8939 x = (double) d_x + k;
8940 y = (double) d_y + k*dy;
8943 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
8945 arrow[6].x = Round(x - j);
8946 arrow[6].y = Round(y + j*dx);
8948 arrow[2].x = Round(arrow[6].x + 2*j);
8949 arrow[2].y = Round(arrow[6].y - 2*j*dx);
8951 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
8952 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
8957 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
8958 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
8961 XFillPolygon(xDisplay, xBoardWindow, highlineGC, arrow, 7, Nonconvex, CoordModeOrigin);
8962 // Polygon( hdc, arrow, 7 );
8965 /* [AS] Draw an arrow between two squares */
8966 void DrawArrowBetweenSquares( int s_col, int s_row, int d_col, int d_row )
8968 int s_x, s_y, d_x, d_y, hor, vert, i;
8970 if( s_col == d_col && s_row == d_row ) {
8974 /* Get source and destination points */
8975 SquareToPos( s_row, s_col, &s_x, &s_y);
8976 SquareToPos( d_row, d_col, &d_x, &d_y);
8979 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
8981 else if( d_y < s_y ) {
8982 d_y += squareSize / 2 + squareSize / 4;
8985 d_y += squareSize / 2;
8989 d_x += squareSize / 2 - squareSize / 4;
8991 else if( d_x < s_x ) {
8992 d_x += squareSize / 2 + squareSize / 4;
8995 d_x += squareSize / 2;
8998 s_x += squareSize / 2;
8999 s_y += squareSize / 2;
9002 A_WIDTH = squareSize / 14.; //[HGM] make float
9004 DrawArrowBetweenPoints( s_x, s_y, d_x, d_y );
9006 hor = 64*s_col + 32; vert = 64*s_row + 32;
9007 for(i=0; i<= 64; i++) {
9008 damage[0][vert+6>>6][hor+6>>6] = True;
9009 damage[0][vert-6>>6][hor+6>>6] = True;
9010 damage[0][vert+6>>6][hor-6>>6] = True;
9011 damage[0][vert-6>>6][hor-6>>6] = True;
9012 hor += d_col - s_col; vert += d_row - s_row;
9016 Boolean IsDrawArrowEnabled()
9018 return appData.highlightMoveWithArrow && squareSize >= 32;
9021 void DrawArrowHighlight(int fromX, int fromY, int toX,int toY)
9023 if( IsDrawArrowEnabled() && fromX >= 0 && fromY >= 0 && toX >= 0 && toY >= 0)
9024 DrawArrowBetweenSquares(fromX, fromY, toX, toY);
9027 void UpdateLogos(int displ)
9029 return; // no logos in XBoard yet