2 * xboard.c -- X front end for XBoard
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
8 * 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
10 * The following terms apply to Digital Equipment Corporation's copyright
12 * ------------------------------------------------------------------------
15 * Permission to use, copy, modify, and distribute this software and its
16 * documentation for any purpose and without fee is hereby granted,
17 * provided that the above copyright notice appear in all copies and that
18 * both that copyright notice and this permission notice appear in
19 * supporting documentation, and that the name of Digital not be
20 * used in advertising or publicity pertaining to distribution of the
21 * software without specific, written prior permission.
23 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
30 * ------------------------------------------------------------------------
32 * The following terms apply to the enhanced version of XBoard
33 * distributed by the Free Software Foundation:
34 * ------------------------------------------------------------------------
36 * GNU XBoard is free software: you can redistribute it and/or modify
37 * it under the terms of the GNU General Public License as published by
38 * the Free Software Foundation, either version 3 of the License, or (at
39 * your option) any later version.
41 * GNU XBoard is distributed in the hope that it will be useful, but
42 * WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44 * General Public License for more details.
46 * You should have received a copy of the GNU General Public License
47 * along with this program. If not, see http://www.gnu.org/licenses/. *
49 *------------------------------------------------------------------------
50 ** See the file ChangeLog for a revision history. */
60 #include <sys/types.h>
66 # if HAVE_SYS_SOCKET_H
67 # include <sys/socket.h>
68 # include <netinet/in.h>
70 # else /* not HAVE_SYS_SOCKET_H */
71 # if HAVE_LAN_SOCKET_H
72 # include <lan/socket.h>
74 # include <lan/netdb.h>
75 # else /* not HAVE_LAN_SOCKET_H */
76 # define OMIT_SOCKETS 1
77 # endif /* not HAVE_LAN_SOCKET_H */
78 # endif /* not HAVE_SYS_SOCKET_H */
79 #endif /* !OMIT_SOCKETS */
84 #else /* not STDC_HEADERS */
85 extern char *getenv();
88 # else /* not HAVE_STRING_H */
90 # endif /* not HAVE_STRING_H */
91 #endif /* not STDC_HEADERS */
94 # include <sys/fcntl.h>
95 #else /* not HAVE_SYS_FCNTL_H */
98 # endif /* HAVE_FCNTL_H */
99 #endif /* not HAVE_SYS_FCNTL_H */
101 #if HAVE_SYS_SYSTEMINFO_H
102 # include <sys/systeminfo.h>
103 #endif /* HAVE_SYS_SYSTEMINFO_H */
105 #if TIME_WITH_SYS_TIME
106 # include <sys/time.h>
110 # include <sys/time.h>
121 # include <sys/wait.h>
126 # define NAMLEN(dirent) strlen((dirent)->d_name)
127 # define HAVE_DIR_STRUCT
129 # define dirent direct
130 # define NAMLEN(dirent) (dirent)->d_namlen
132 # include <sys/ndir.h>
133 # define HAVE_DIR_STRUCT
136 # include <sys/dir.h>
137 # define HAVE_DIR_STRUCT
141 # define HAVE_DIR_STRUCT
149 #include <X11/Intrinsic.h>
150 #include <X11/StringDefs.h>
151 #include <X11/Shell.h>
152 #include <X11/cursorfont.h>
153 #include <X11/Xatom.h>
154 #include <X11/Xmu/Atoms.h>
156 #include <X11/Xaw3d/Dialog.h>
157 #include <X11/Xaw3d/Form.h>
158 #include <X11/Xaw3d/List.h>
159 #include <X11/Xaw3d/Label.h>
160 #include <X11/Xaw3d/SimpleMenu.h>
161 #include <X11/Xaw3d/SmeBSB.h>
162 #include <X11/Xaw3d/SmeLine.h>
163 #include <X11/Xaw3d/Box.h>
164 #include <X11/Xaw3d/MenuButton.h>
165 #include <X11/Xaw3d/Text.h>
166 #include <X11/Xaw3d/AsciiText.h>
168 #include <X11/Xaw/Dialog.h>
169 #include <X11/Xaw/Form.h>
170 #include <X11/Xaw/List.h>
171 #include <X11/Xaw/Label.h>
172 #include <X11/Xaw/SimpleMenu.h>
173 #include <X11/Xaw/SmeBSB.h>
174 #include <X11/Xaw/SmeLine.h>
175 #include <X11/Xaw/Box.h>
176 #include <X11/Xaw/MenuButton.h>
177 #include <X11/Xaw/Text.h>
178 #include <X11/Xaw/AsciiText.h>
181 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
186 #include "pixmaps/pixmaps.h"
187 #define IMAGE_EXT "xpm"
189 #define IMAGE_EXT "xim"
190 #include "bitmaps/bitmaps.h"
193 #include "bitmaps/icon_white.bm"
194 #include "bitmaps/icon_black.bm"
195 #include "bitmaps/checkmark.bm"
197 #include "frontend.h"
199 #include "backendz.h"
203 #include "xgamelist.h"
204 #include "xhistory.h"
205 #include "xedittags.h"
208 // must be moved to xengineoutput.h
210 void EngineOutputProc P((Widget w, XEvent *event,
211 String *prms, Cardinal *nprms));
212 void EvalGraphProc P((Widget w, XEvent *event,
213 String *prms, Cardinal *nprms));
220 #define usleep(t) _sleep2(((t)+500)/1000)
224 # define _(s) gettext (s)
225 # define N_(s) gettext_noop (s)
243 int main P((int argc, char **argv));
244 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
245 char *init_path, char *filter, char *mode, int (*show_entry)(), char **name_return));
246 RETSIGTYPE CmailSigHandler P((int sig));
247 RETSIGTYPE IntSigHandler P((int sig));
248 RETSIGTYPE TermSizeSigHandler P((int sig));
249 void CreateGCs P((int redo));
250 void CreateAnyPieces P((void));
251 void CreateXIMPieces P((void));
252 void CreateXPMPieces P((void));
253 void CreateXPMBoard P((char *s, int n));
254 void CreatePieces P((void));
255 void CreatePieceMenus P((void));
256 Widget CreateMenuBar P((Menu *mb));
257 Widget CreateButtonBar P ((MenuItem *mi));
259 char *InsertPxlSize P((char *pattern, int targetPxlSize));
260 XFontSet CreateFontSet P((char *base_fnt_lst));
262 char *FindFont P((char *pattern, int targetPxlSize));
264 void PieceMenuPopup P((Widget w, XEvent *event,
265 String *params, Cardinal *num_params));
266 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
267 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
268 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
269 u_int wreq, u_int hreq));
270 void CreateGrid P((void));
271 int EventToSquare P((int x, int limit));
272 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
273 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
274 void MoveTypeInProc P((Widget widget, caddr_t unused, XEvent *event));
275 void HandleUserMove P((Widget w, XEvent *event,
276 String *prms, Cardinal *nprms));
277 void AnimateUserMove P((Widget w, XEvent * event,
278 String * params, Cardinal * nParams));
279 void HandlePV P((Widget w, XEvent * event,
280 String * params, Cardinal * nParams));
281 void SelectPV P((Widget w, XEvent * event,
282 String * params, Cardinal * nParams));
283 void StopPV P((Widget w, XEvent * event,
284 String * params, Cardinal * nParams));
285 void WhiteClock P((Widget w, XEvent *event,
286 String *prms, Cardinal *nprms));
287 void BlackClock P((Widget w, XEvent *event,
288 String *prms, Cardinal *nprms));
289 void DrawPositionProc P((Widget w, XEvent *event,
290 String *prms, Cardinal *nprms));
291 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
293 void CommentClick P((Widget w, XEvent * event,
294 String * params, Cardinal * nParams));
295 void CommentPopUp P((char *title, char *label));
296 void CommentPopDown P((void));
297 void ICSInputBoxPopUp P((void));
298 void ICSInputBoxPopDown P((void));
299 void FileNamePopUp P((char *label, char *def, char *filter,
300 FileProc proc, char *openMode));
301 void FileNamePopDown P((void));
302 void FileNameCallback P((Widget w, XtPointer client_data,
303 XtPointer call_data));
304 void FileNameAction P((Widget w, XEvent *event,
305 String *prms, Cardinal *nprms));
306 void AskQuestionReplyAction P((Widget w, XEvent *event,
307 String *prms, Cardinal *nprms));
308 void AskQuestionProc P((Widget w, XEvent *event,
309 String *prms, Cardinal *nprms));
310 void AskQuestionPopDown P((void));
311 void PromotionPopDown P((void));
312 void PromotionCallback P((Widget w, XtPointer client_data,
313 XtPointer call_data));
314 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
315 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
316 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
317 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
319 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
321 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
323 void LoadPositionProc P((Widget w, XEvent *event,
324 String *prms, Cardinal *nprms));
325 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
327 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
329 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
331 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
333 void PastePositionProc P((Widget w, XEvent *event, String *prms,
335 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
336 void CopyGameListProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
337 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
338 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
339 void SavePositionProc P((Widget w, XEvent *event,
340 String *prms, Cardinal *nprms));
341 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
342 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
344 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
345 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
346 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
348 void MachineWhiteProc P((Widget w, XEvent *event,
349 String *prms, Cardinal *nprms));
350 void AnalyzeModeProc P((Widget w, XEvent *event,
351 String *prms, Cardinal *nprms));
352 void AnalyzeFileProc P((Widget w, XEvent *event,
353 String *prms, Cardinal *nprms));
354 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
356 void MatchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
357 void MatchOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
358 void IcsClientProc P((Widget w, XEvent *event, String *prms,
360 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void EditPositionProc P((Widget w, XEvent *event,
362 String *prms, Cardinal *nprms));
363 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void EditCommentProc P((Widget w, XEvent *event,
365 String *prms, Cardinal *nprms));
366 void IcsInputBoxProc P((Widget w, XEvent *event,
367 String *prms, Cardinal *nprms));
368 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
369 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
370 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
371 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
372 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
373 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
374 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
375 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
376 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
377 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
379 void TypeInProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
380 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void StopObservingProc P((Widget w, XEvent *event, String *prms,
385 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
387 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
388 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
389 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
390 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
391 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
392 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
393 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
394 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
396 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
398 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
399 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
401 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
403 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
405 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
406 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
407 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
408 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
410 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
411 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
413 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
415 void HighlightArrowProc P((Widget w, XEvent *event, String *prms,
417 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
418 //void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
419 void OneClickProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
420 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
422 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
424 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
426 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
428 //void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
429 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
431 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
433 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
435 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
437 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
442 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
443 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
444 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
445 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
446 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
447 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
448 void DisplayMove P((int moveNumber));
449 void DisplayTitle P((char *title));
450 void ICSInitScript P((void));
451 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
452 void ErrorPopUp P((char *title, char *text, int modal));
453 void ErrorPopDown P((void));
454 static char *ExpandPathName P((char *path));
455 static void CreateAnimVars P((void));
456 static void DragPieceMove P((int x, int y));
457 static void DrawDragPiece P((void));
458 char *ModeToWidgetName P((GameMode mode));
459 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
460 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
461 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
462 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
463 void OptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
464 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
465 void IcsTextProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
466 void LoadEngineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
467 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
468 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
469 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
470 void IcsOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
471 void SoundOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
472 void BoardOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
473 void LoadOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
474 void SaveOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
475 void EditBookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
476 void SelectMove P((Widget w, XEvent * event, String * params, Cardinal * nParams));
477 void GameListOptionsPopDown P(());
478 void GenericPopDown P(());
479 void update_ics_width P(());
480 int get_term_width P(());
481 int CopyMemoProc P(());
482 void DrawArrowHighlight P((int fromX, int fromY, int toX,int toY));
483 Boolean IsDrawArrowEnabled P(());
486 * XBoard depends on Xt R4 or higher
488 int xtVersion = XtSpecificationRelease;
493 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
494 jailSquareColor, highlightSquareColor, premoveHighlightColor;
495 Pixel lowTimeWarningColor;
496 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
497 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
498 wjPieceGC, bjPieceGC, prelineGC, countGC;
499 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
500 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
501 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
502 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
503 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
504 ICSInputShell, fileNameShell, askQuestionShell;
505 Widget historyShell, evalGraphShell, gameListShell;
506 int hOffset; // [HGM] dual
507 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
508 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
509 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
511 XFontSet fontSet, clockFontSet;
514 XFontStruct *clockFontStruct;
516 Font coordFontID, countFontID;
517 XFontStruct *coordFontStruct, *countFontStruct;
518 XtAppContext appContext;
520 char *oldICSInteractionTitle;
524 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
526 Position commentX = -1, commentY = -1;
527 Dimension commentW, commentH;
528 typedef unsigned int BoardSize;
530 Boolean chessProgram;
532 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
533 int squareSize, smallLayout = 0, tinyLayout = 0,
534 marginW, marginH, // [HGM] for run-time resizing
535 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
536 ICSInputBoxUp = False, askQuestionUp = False,
537 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
538 errorUp = False, errorExitStatus = -1, lineGap, defaultLineGap;
539 Pixel timerForegroundPixel, timerBackgroundPixel;
540 Pixel buttonForegroundPixel, buttonBackgroundPixel;
541 char *chessDir, *programName, *programVersion,
542 *gameCopyFilename, *gamePasteFilename;
543 Boolean alwaysOnTop = False;
544 Boolean saveSettingsOnExit;
545 char *settingsFileName;
546 char *icsTextMenuString;
548 char *firstChessProgramNames;
549 char *secondChessProgramNames;
551 WindowPlacement wpMain;
552 WindowPlacement wpConsole;
553 WindowPlacement wpComment;
554 WindowPlacement wpMoveHistory;
555 WindowPlacement wpEvalGraph;
556 WindowPlacement wpEngineOutput;
557 WindowPlacement wpGameList;
558 WindowPlacement wpTags;
560 extern Widget shells[];
561 extern Boolean shellUp[];
565 Pixmap pieceBitmap[2][(int)BlackPawn];
566 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
567 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
568 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
569 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
570 Pixmap xpmBoardBitmap[2];
571 int useImages, useImageSqs, useTexture, textureW[2], textureH[2];
572 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
573 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
574 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
575 XImage *ximLightSquare, *ximDarkSquare;
578 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
579 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
581 #define White(piece) ((int)(piece) < (int)BlackPawn)
583 /* Variables for doing smooth animation. This whole thing
584 would be much easier if the board was double-buffered,
585 but that would require a fairly major rewrite. */
590 GC blitGC, pieceGC, outlineGC;
591 XPoint startSquare, prevFrame, mouseDelta;
595 int startBoardX, startBoardY;
598 /* There can be two pieces being animated at once: a player
599 can begin dragging a piece before the remote opponent has moved. */
601 static AnimState game, player;
603 /* Bitmaps for use as masks when drawing XPM pieces.
604 Need one for each black and white piece. */
605 static Pixmap xpmMask[BlackKing + 1];
607 /* This magic number is the number of intermediate frames used
608 in each half of the animation. For short moves it's reduced
609 by 1. The total number of frames will be factor * 2 + 1. */
612 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
614 MenuItem fileMenu[] = {
615 {N_("New Game Ctrl+N"), "New Game", ResetProc},
616 {N_("New Shuffle Game ..."), "New Shuffle Game", ShuffleMenuProc},
617 {N_("New Variant ... Alt+Shift+V"), "New Variant", NewVariantProc}, // [HGM] variant: not functional yet
618 {"----", NULL, NothingProc},
619 {N_("Load Game Ctrl+O"), "Load Game", LoadGameProc},
620 {N_("Load Position Ctrl+Shift+O"), "Load Position", LoadPositionProc},
621 // {N_("Load Next Game"), "Load Next Game", LoadNextGameProc},
622 // {N_("Load Previous Game"), "Load Previous Game", LoadPrevGameProc},
623 // {N_("Reload Same Game"), "Reload Same Game", ReloadGameProc},
624 {N_("Next Position Shift+PgDn"), "Load Next Position", LoadNextPositionProc},
625 {N_("Prev Position Shift+PgUp"), "Load Previous Position", LoadPrevPositionProc},
626 {"----", NULL, NothingProc},
627 // {N_("Reload Same Position"), "Reload Same Position", ReloadPositionProc},
628 {N_("Save Game Ctrl+S"), "Save Game", SaveGameProc},
629 {N_("Save Position Ctrl+Shift+S"), "Save Position", SavePositionProc},
630 {"----", NULL, NothingProc},
631 {N_("Mail Move"), "Mail Move", MailMoveProc},
632 {N_("Reload CMail Message"), "Reload CMail Message", ReloadCmailMsgProc},
633 {"----", NULL, NothingProc},
634 {N_("Quit Ctr+Q"), "Exit", QuitProc},
638 MenuItem editMenu[] = {
639 {N_("Copy Game Ctrl+C"), "Copy Game", CopyGameProc},
640 {N_("Copy Position Ctrl+Shift+C"), "Copy Position", CopyPositionProc},
641 {N_("Copy Game List"), "Copy Game List", CopyGameListProc},
642 {"----", NULL, NothingProc},
643 {N_("Paste Game Ctrl+V"), "Paste Game", PasteGameProc},
644 {N_("Paste Position Ctrl+Shift+V"), "Paste Position", PastePositionProc},
645 {"----", NULL, NothingProc},
646 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
647 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
648 {N_("Edit Tags"), "Edit Tags", EditTagsProc},
649 {N_("Edit Comment"), "Edit Comment", EditCommentProc},
650 {N_("Edit Book"), "Edit Book", EditBookProc},
651 {"----", NULL, NothingProc},
652 {N_("Revert Home"), "Revert", RevertProc},
653 {N_("Annotate"), "Annotate", AnnotateProc},
654 {N_("Truncate Game End"), "Truncate Game", TruncateGameProc},
655 {"----", NULL, NothingProc},
656 {N_("Backward Alt+Left"), "Backward", BackwardProc},
657 {N_("Forward Alt+Right"), "Forward", ForwardProc},
658 {N_("Back to Start Alt+Home"), "Back to Start", ToStartProc},
659 {N_("Forward to End Alt+End"), "Forward to End", ToEndProc},
663 MenuItem viewMenu[] = {
664 {N_("Flip View F2"), "Flip View", FlipViewProc},
665 {"----", NULL, NothingProc},
666 {N_("Engine Output Alt+Shift+O"), "Show Engine Output", EngineOutputProc},
667 {N_("Move History Alt+Shift+H"), "Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
668 {N_("Evaluation Graph Alt+Shift+E"), "Show Evaluation Graph", EvalGraphProc},
669 {N_("Game List Alt+Shift+G"), "Show Game List", ShowGameListProc},
670 {N_("ICS text menu"), "ICStex", IcsTextProc},
671 {"----", NULL, NothingProc},
672 {N_("Tags"), "Show Tags", EditTagsProc},
673 {N_("Comments"), "Show Comments", EditCommentProc},
674 {N_("ICS Input Box"), "ICS Input Box", IcsInputBoxProc},
675 {"----", NULL, NothingProc},
676 {N_("Board..."), "Board Options", BoardOptionsProc},
677 {N_("Game List Tags..."), "Game List", GameListOptionsPopUp},
681 MenuItem modeMenu[] = {
682 {N_("Machine White Ctrl+W"), "Machine White", MachineWhiteProc},
683 {N_("Machine Black Ctrl+B"), "Machine Black", MachineBlackProc},
684 {N_("Two Machines Ctrl+T"), "Two Machines", TwoMachinesProc},
685 {N_("Analysis Mode Ctrl+A"), "Analysis Mode", AnalyzeModeProc},
686 {N_("Analyze File Ctrl+F"), "Analyze File", AnalyzeFileProc },
687 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
688 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
689 {N_("Training"), "Training", TrainingProc},
690 {N_("ICS Client"), "ICS Client", IcsClientProc},
691 {"----", NULL, NothingProc},
692 {N_("Machine Match"), "Machine Match", MatchProc},
693 {N_("Pause Pause"), "Pause", PauseProc},
697 MenuItem actionMenu[] = {
698 {N_("Accept F3"), "Accept", AcceptProc},
699 {N_("Decline F4"), "Decline", DeclineProc},
700 {N_("Rematch F12"), "Rematch", RematchProc},
701 {"----", NULL, NothingProc},
702 {N_("Call Flag F5"), "Call Flag", CallFlagProc},
703 {N_("Draw F6"), "Draw", DrawProc},
704 {N_("Adjourn F7"), "Adjourn", AdjournProc},
705 {N_("Abort F8"),"Abort", AbortProc},
706 {N_("Resign F9"), "Resign", ResignProc},
707 {"----", NULL, NothingProc},
708 {N_("Stop Observing F10"), "Stop Observing", StopObservingProc},
709 {N_("Stop Examining F11"), "Stop Examining", StopExaminingProc},
710 {N_("Upload to Examine"), "Upload to Examine", UploadProc},
711 {"----", NULL, NothingProc},
712 {N_("Adjudicate to White"), "Adjudicate to White", AdjuWhiteProc},
713 {N_("Adjudicate to Black"), "Adjudicate to Black", AdjuBlackProc},
714 {N_("Adjudicate Draw"), "Adjudicate Draw", AdjuDrawProc},
718 MenuItem engineMenu[] = {
719 {N_("Load New Engine ..."), "Load Engine", LoadEngineProc},
720 {"----", NULL, NothingProc},
721 {N_("Engine #1 Settings ..."), "Engine #1 Settings", FirstSettingsProc},
722 {N_("Engine #2 Settings ..."), "Engine #2 Settings", SecondSettingsProc},
723 {"----", NULL, NothingProc},
724 {N_("Hint"), "Hint", HintProc},
725 {N_("Book"), "Book", BookProc},
726 {"----", NULL, NothingProc},
727 {N_("Move Now Ctrl+M"), "Move Now", MoveNowProc},
728 {N_("Retract Move Ctrl+X"), "Retract Move", RetractMoveProc},
732 MenuItem optionsMenu[] = {
733 #define OPTIONSDIALOG
735 {N_("General ..."), "General", OptionsProc},
737 {N_("Time Control ... Alt+Shift+T"), "Time Control", TimeControlProc},
738 {N_("Common Engine ... Alt+Shift+U"), "Common Engine", UciMenuProc},
739 {N_("Adjudications ... Alt+Shift+J"), "Adjudications", EngineMenuProc},
740 {N_("ICS ..."), "ICS", IcsOptionsProc},
741 {N_("Match ..."), "Match", MatchOptionsProc},
742 {N_("Load Game ..."), "Load Game", LoadOptionsProc},
743 {N_("Save Game ..."), "Save Game", SaveOptionsProc},
744 // {N_(" ..."), "", OptionsProc},
745 {N_("Game List ..."), "Game List", GameListOptionsPopUp},
746 {N_("Sounds ..."), "Sounds", SoundOptionsProc},
747 {"----", NULL, NothingProc},
748 #ifndef OPTIONSDIALOG
749 {N_("Always Queen Ctrl+Shift+Q"), "Always Queen", AlwaysQueenProc},
750 {N_("Animate Dragging"), "Animate Dragging", AnimateDraggingProc},
751 {N_("Animate Moving Ctrl+Shift+A"), "Animate Moving", AnimateMovingProc},
752 {N_("Auto Flag Ctrl+Shift+F"), "Auto Flag", AutoflagProc},
753 {N_("Auto Flip View"), "Auto Flip View", AutoflipProc},
754 {N_("Blindfold"), "Blindfold", BlindfoldProc},
755 {N_("Flash Moves"), "Flash Moves", FlashMovesProc},
757 {N_("Highlight Dragging"), "Highlight Dragging", HighlightDraggingProc},
759 {N_("Highlight Last Move"), "Highlight Last Move", HighlightLastMoveProc},
760 {N_("Highlight With Arrow"), "Arrow", HighlightArrowProc},
761 {N_("Move Sound"), "Move Sound", MoveSoundProc},
762 // {N_("ICS Alarm"), "ICS Alarm", IcsAlarmProc},
763 {N_("One-Click Moving"), "OneClick", OneClickProc},
764 {N_("Periodic Updates"), "Periodic Updates", PeriodicUpdatesProc},
765 {N_("Ponder Next Move Ctrl+Shift+P"), "Ponder Next Move", PonderNextMoveProc},
766 {N_("Popup Exit Message"), "Popup Exit Message", PopupExitMessageProc},
767 {N_("Popup Move Errors"), "Popup Move Errors", PopupMoveErrorsProc},
768 // {N_("Premove"), "Premove", PremoveProc},
769 {N_("Show Coords"), "Show Coords", ShowCoordsProc},
770 {N_("Hide Thinking Ctrl+Shift+H"), "Hide Thinking", HideThinkingProc},
771 {N_("Test Legality Ctrl+Shift+L"), "Test Legality", TestLegalityProc},
772 {"----", NULL, NothingProc},
774 {N_("Save Settings Now"), "Save Settings Now", SaveSettingsProc},
775 {N_("Save Settings on Exit"), "Save Settings on Exit", SaveOnExitProc},
779 MenuItem helpMenu[] = {
780 {N_("Info XBoard"), "Info XBoard", InfoProc},
781 {N_("Man XBoard F1"), "Man XBoard", ManProc},
782 {"----", NULL, NothingProc},
783 {N_("About XBoard"), "About XBoard", AboutProc},
788 {N_("File"), "File", fileMenu},
789 {N_("Edit"), "Edit", editMenu},
790 {N_("View"), "View", viewMenu},
791 {N_("Mode"), "Mode", modeMenu},
792 {N_("Action"), "Action", actionMenu},
793 {N_("Engine"), "Engine", engineMenu},
794 {N_("Options"), "Options", optionsMenu},
795 {N_("Help"), "Help", helpMenu},
799 #define PAUSE_BUTTON "P"
800 MenuItem buttonBar[] = {
801 {"<<", "<<", ToStartProc},
802 {"<", "<", BackwardProc},
803 {PAUSE_BUTTON, PAUSE_BUTTON, PauseProc},
804 {">", ">", ForwardProc},
805 {">>", ">>", ToEndProc},
809 #define PIECE_MENU_SIZE 18
810 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
811 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
812 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
813 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
814 N_("Empty square"), N_("Clear board") },
815 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
816 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
817 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
818 N_("Empty square"), N_("Clear board") }
820 /* must be in same order as pieceMenuStrings! */
821 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
822 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
823 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
824 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
825 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
826 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
827 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
828 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
829 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
832 #define DROP_MENU_SIZE 6
833 String dropMenuStrings[DROP_MENU_SIZE] = {
834 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
836 /* must be in same order as dropMenuStrings! */
837 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
838 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
839 WhiteRook, WhiteQueen
847 DropMenuEnables dmEnables[] = {
865 { XtNborderWidth, 0 },
866 { XtNdefaultDistance, 0 },
870 { XtNborderWidth, 0 },
871 { XtNresizable, (XtArgVal) True },
875 { XtNborderWidth, 0 },
881 { XtNjustify, (XtArgVal) XtJustifyRight },
882 { XtNlabel, (XtArgVal) "..." },
883 { XtNresizable, (XtArgVal) True },
884 { XtNresize, (XtArgVal) False }
887 Arg messageArgs[] = {
888 { XtNjustify, (XtArgVal) XtJustifyLeft },
889 { XtNlabel, (XtArgVal) "..." },
890 { XtNresizable, (XtArgVal) True },
891 { XtNresize, (XtArgVal) False }
895 { XtNborderWidth, 0 },
896 { XtNjustify, (XtArgVal) XtJustifyLeft }
899 XtResource clientResources[] = {
900 { "flashCount", "flashCount", XtRInt, sizeof(int),
901 XtOffset(AppDataPtr, flashCount), XtRImmediate,
902 (XtPointer) FLASH_COUNT },
905 XrmOptionDescRec shellOptions[] = {
906 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
907 { "-flash", "flashCount", XrmoptionNoArg, "3" },
908 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
911 XtActionsRec boardActions[] = {
912 { "DrawPosition", DrawPositionProc },
913 { "HandleUserMove", HandleUserMove },
914 { "AnimateUserMove", AnimateUserMove },
915 { "HandlePV", HandlePV },
916 { "SelectPV", SelectPV },
917 { "StopPV", StopPV },
918 { "FileNameAction", FileNameAction },
919 { "AskQuestionProc", AskQuestionProc },
920 { "AskQuestionReplyAction", AskQuestionReplyAction },
921 { "PieceMenuPopup", PieceMenuPopup },
922 { "WhiteClock", WhiteClock },
923 { "BlackClock", BlackClock },
924 { "Iconify", Iconify },
925 { "ResetProc", ResetProc },
926 { "NewVariantProc", NewVariantProc },
927 { "LoadGameProc", LoadGameProc },
928 { "LoadNextGameProc", LoadNextGameProc },
929 { "LoadPrevGameProc", LoadPrevGameProc },
930 { "LoadSelectedProc", LoadSelectedProc },
931 { "SetFilterProc", SetFilterProc },
932 { "ReloadGameProc", ReloadGameProc },
933 { "LoadPositionProc", LoadPositionProc },
934 { "LoadNextPositionProc", LoadNextPositionProc },
935 { "LoadPrevPositionProc", LoadPrevPositionProc },
936 { "ReloadPositionProc", ReloadPositionProc },
937 { "CopyPositionProc", CopyPositionProc },
938 { "PastePositionProc", PastePositionProc },
939 { "CopyGameProc", CopyGameProc },
940 { "CopyGameListProc", CopyGameListProc },
941 { "PasteGameProc", PasteGameProc },
942 { "SaveGameProc", SaveGameProc },
943 { "SavePositionProc", SavePositionProc },
944 { "MailMoveProc", MailMoveProc },
945 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
946 { "QuitProc", QuitProc },
947 { "MachineWhiteProc", MachineWhiteProc },
948 { "MachineBlackProc", MachineBlackProc },
949 { "AnalysisModeProc", AnalyzeModeProc },
950 { "AnalyzeFileProc", AnalyzeFileProc },
951 { "TwoMachinesProc", TwoMachinesProc },
952 { "IcsClientProc", IcsClientProc },
953 { "EditGameProc", EditGameProc },
954 { "EditPositionProc", EditPositionProc },
955 { "TrainingProc", EditPositionProc },
956 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
957 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
958 { "ShowGameListProc", ShowGameListProc },
959 { "ShowMoveListProc", HistoryShowProc},
960 { "EditTagsProc", EditCommentProc },
961 { "EditBookProc", EditBookProc },
962 { "EditCommentProc", EditCommentProc },
963 { "IcsInputBoxProc", IcsInputBoxProc },
964 { "PauseProc", PauseProc },
965 { "AcceptProc", AcceptProc },
966 { "DeclineProc", DeclineProc },
967 { "RematchProc", RematchProc },
968 { "CallFlagProc", CallFlagProc },
969 { "DrawProc", DrawProc },
970 { "AdjournProc", AdjournProc },
971 { "AbortProc", AbortProc },
972 { "ResignProc", ResignProc },
973 { "AdjuWhiteProc", AdjuWhiteProc },
974 { "AdjuBlackProc", AdjuBlackProc },
975 { "AdjuDrawProc", AdjuDrawProc },
976 { "TypeInProc", TypeInProc },
977 { "EnterKeyProc", EnterKeyProc },
978 { "UpKeyProc", UpKeyProc },
979 { "DownKeyProc", DownKeyProc },
980 { "StopObservingProc", StopObservingProc },
981 { "StopExaminingProc", StopExaminingProc },
982 { "UploadProc", UploadProc },
983 { "BackwardProc", BackwardProc },
984 { "ForwardProc", ForwardProc },
985 { "ToStartProc", ToStartProc },
986 { "ToEndProc", ToEndProc },
987 { "RevertProc", RevertProc },
988 { "AnnotateProc", AnnotateProc },
989 { "TruncateGameProc", TruncateGameProc },
990 { "MoveNowProc", MoveNowProc },
991 { "RetractMoveProc", RetractMoveProc },
992 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
993 { "UciMenuProc", (XtActionProc) UciMenuProc },
994 { "TimeControlProc", (XtActionProc) TimeControlProc },
995 { "FlipViewProc", FlipViewProc },
996 { "PonderNextMoveProc", PonderNextMoveProc },
997 #ifndef OPTIONSDIALOG
998 { "AlwaysQueenProc", AlwaysQueenProc },
999 { "AnimateDraggingProc", AnimateDraggingProc },
1000 { "AnimateMovingProc", AnimateMovingProc },
1001 { "AutoflagProc", AutoflagProc },
1002 { "AutoflipProc", AutoflipProc },
1003 { "BlindfoldProc", BlindfoldProc },
1004 { "FlashMovesProc", FlashMovesProc },
1006 { "HighlightDraggingProc", HighlightDraggingProc },
1008 { "HighlightLastMoveProc", HighlightLastMoveProc },
1009 // { "IcsAlarmProc", IcsAlarmProc },
1010 { "MoveSoundProc", MoveSoundProc },
1011 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
1012 { "PopupExitMessageProc", PopupExitMessageProc },
1013 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
1014 // { "PremoveProc", PremoveProc },
1015 { "ShowCoordsProc", ShowCoordsProc },
1016 { "ShowThinkingProc", ShowThinkingProc },
1017 { "HideThinkingProc", HideThinkingProc },
1018 { "TestLegalityProc", TestLegalityProc },
1020 { "SaveSettingsProc", SaveSettingsProc },
1021 { "SaveOnExitProc", SaveOnExitProc },
1022 { "InfoProc", InfoProc },
1023 { "ManProc", ManProc },
1024 { "HintProc", HintProc },
1025 { "BookProc", BookProc },
1026 { "AboutGameProc", AboutGameProc },
1027 { "AboutProc", AboutProc },
1028 { "DebugProc", DebugProc },
1029 { "NothingProc", NothingProc },
1030 { "CommentClick", (XtActionProc) CommentClick },
1031 { "CommentPopDown", (XtActionProc) CommentPopDown },
1032 { "TagsPopDown", (XtActionProc) TagsPopDown },
1033 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
1034 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
1035 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
1036 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
1037 { "GameListPopDown", (XtActionProc) GameListPopDown },
1038 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
1039 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1040 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1041 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1042 { "GenericPopDown", (XtActionProc) GenericPopDown },
1043 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1044 { "SelectMove", (XtActionProc) SelectMove },
1047 char globalTranslations[] =
1048 ":<Key>F9: ResignProc() \n \
1049 :Ctrl<Key>n: ResetProc() \n \
1050 :Meta<Key>V: NewVariantProc() \n \
1051 :Ctrl<Key>o: LoadGameProc() \n \
1052 :Meta<Key>Next: LoadNextGameProc() \n \
1053 :Meta<Key>Prior: LoadPrevGameProc() \n \
1054 :Ctrl<Key>s: SaveGameProc() \n \
1055 :Ctrl<Key>c: CopyGameProc() \n \
1056 :Ctrl<Key>v: PasteGameProc() \n \
1057 :Ctrl<Key>O: LoadPositionProc() \n \
1058 :Shift<Key>Next: LoadNextPositionProc() \n \
1059 :Shift<Key>Prior: LoadPrevPositionProc() \n \
1060 :Ctrl<Key>S: SavePositionProc() \n \
1061 :Ctrl<Key>C: CopyPositionProc() \n \
1062 :Ctrl<Key>V: PastePositionProc() \n \
1063 :Ctrl<Key>q: QuitProc() \n \
1064 :Ctrl<Key>w: MachineWhiteProc() \n \
1065 :Ctrl<Key>b: MachineBlackProc() \n \
1066 :Ctrl<Key>t: TwoMachinesProc() \n \
1067 :Ctrl<Key>a: AnalysisModeProc() \n \
1068 :Ctrl<Key>f: AnalyzeFileProc() \n \
1069 :Ctrl<Key>e: EditGameProc() \n \
1070 :Ctrl<Key>E: EditPositionProc() \n \
1071 :Meta<Key>O: EngineOutputProc() \n \
1072 :Meta<Key>E: EvalGraphProc() \n \
1073 :Meta<Key>G: ShowGameListProc() \n \
1074 :Meta<Key>H: ShowMoveListProc() \n \
1075 :<Key>Pause: PauseProc() \n \
1076 :<Key>F3: AcceptProc() \n \
1077 :<Key>F4: DeclineProc() \n \
1078 :<Key>F12: RematchProc() \n \
1079 :<Key>F5: CallFlagProc() \n \
1080 :<Key>F6: DrawProc() \n \
1081 :<Key>F7: AdjournProc() \n \
1082 :<Key>F8: AbortProc() \n \
1083 :<Key>F10: StopObservingProc() \n \
1084 :<Key>F11: StopExaminingProc() \n \
1085 :Meta Ctrl<Key>F12: DebugProc() \n \
1086 :Meta<Key>End: ToEndProc() \n \
1087 :Meta<Key>Right: ForwardProc() \n \
1088 :Meta<Key>Home: ToStartProc() \n \
1089 :Meta<Key>Left: BackwardProc() \n \
1090 :<Key>Home: RevertProc() \n \
1091 :<Key>End: TruncateGameProc() \n \
1092 :Ctrl<Key>m: MoveNowProc() \n \
1093 :Ctrl<Key>x: RetractMoveProc() \n \
1094 :Meta<Key>J: EngineMenuProc() \n \
1095 :Meta<Key>U: UciMenuProc() \n \
1096 :Meta<Key>T: TimeControlProc() \n \
1097 :Ctrl<Key>P: PonderNextMoveProc() \n "
1098 #ifndef OPTIONSDIALOG
1100 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1101 :Ctrl<Key>F: AutoflagProc() \n \
1102 :Ctrl<Key>A: AnimateMovingProc() \n \
1103 :Ctrl<Key>L: TestLegalityProc() \n \
1104 :Ctrl<Key>H: HideThinkingProc() \n "
1107 :<Key>-: Iconify() \n \
1108 :<Key>F1: ManProc() \n \
1109 :<Key>F2: FlipViewProc() \n \
1110 <KeyDown>.: BackwardProc() \n \
1111 <KeyUp>.: ForwardProc() \n \
1112 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1113 \"Send to chess program:\",,1) \n \
1114 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1115 \"Send to second chess program:\",,2) \n";
1117 char boardTranslations[] =
1118 "<Btn1Down>: HandleUserMove(0) \n \
1119 Shift<Btn1Up>: HandleUserMove(1) \n \
1120 <Btn1Up>: HandleUserMove(0) \n \
1121 <Btn1Motion>: AnimateUserMove() \n \
1122 <Btn3Motion>: HandlePV() \n \
1123 <Btn3Up>: PieceMenuPopup(menuB) \n \
1124 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1125 PieceMenuPopup(menuB) \n \
1126 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1127 PieceMenuPopup(menuW) \n \
1128 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1129 PieceMenuPopup(menuW) \n \
1130 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1131 PieceMenuPopup(menuB) \n";
1133 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1134 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1136 char ICSInputTranslations[] =
1137 "<Key>Up: UpKeyProc() \n "
1138 "<Key>Down: DownKeyProc() \n "
1139 "<Key>Return: EnterKeyProc() \n";
1141 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1142 // as the widget is destroyed before the up-click can call extend-end
1143 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1145 String xboardResources[] = {
1146 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1147 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1148 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1153 /* Max possible square size */
1154 #define MAXSQSIZE 256
1156 static int xpm_avail[MAXSQSIZE];
1158 #ifdef HAVE_DIR_STRUCT
1160 /* Extract piece size from filename */
1162 xpm_getsize(name, len, ext)
1173 if ((p=strchr(name, '.')) == NULL ||
1174 StrCaseCmp(p+1, ext) != 0)
1180 while (*p && isdigit(*p))
1187 /* Setup xpm_avail */
1189 xpm_getavail(dirname, ext)
1197 for (i=0; i<MAXSQSIZE; ++i)
1200 if (appData.debugMode)
1201 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1203 dir = opendir(dirname);
1206 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1207 programName, dirname);
1211 while ((ent=readdir(dir)) != NULL) {
1212 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1213 if (i > 0 && i < MAXSQSIZE)
1223 xpm_print_avail(fp, ext)
1229 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1230 for (i=1; i<MAXSQSIZE; ++i) {
1236 /* Return XPM piecesize closest to size */
1238 xpm_closest_to(dirname, size, ext)
1244 int sm_diff = MAXSQSIZE;
1248 xpm_getavail(dirname, ext);
1250 if (appData.debugMode)
1251 xpm_print_avail(stderr, ext);
1253 for (i=1; i<MAXSQSIZE; ++i) {
1256 diff = (diff<0) ? -diff : diff;
1257 if (diff < sm_diff) {
1265 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1271 #else /* !HAVE_DIR_STRUCT */
1272 /* If we are on a system without a DIR struct, we can't
1273 read the directory, so we can't collect a list of
1274 filenames, etc., so we can't do any size-fitting. */
1276 xpm_closest_to(dirname, size, ext)
1281 fprintf(stderr, _("\
1282 Warning: No DIR structure found on this system --\n\
1283 Unable to autosize for XPM/XIM pieces.\n\
1284 Please report this error to %s.\n\
1285 Include system type & operating system in message.\n"), PACKAGE_BUGREPORT););
1288 #endif /* HAVE_DIR_STRUCT */
1290 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1291 "magenta", "cyan", "white" };
1295 TextColors textColors[(int)NColorClasses];
1297 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1299 parse_color(str, which)
1303 char *p, buf[100], *d;
1306 if (strlen(str) > 99) /* watch bounds on buf */
1311 for (i=0; i<which; ++i) {
1318 /* Could be looking at something like:
1320 .. in which case we want to stop on a comma also */
1321 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1325 return -1; /* Use default for empty field */
1328 if (which == 2 || isdigit(*p))
1331 while (*p && isalpha(*p))
1336 for (i=0; i<8; ++i) {
1337 if (!StrCaseCmp(buf, cnames[i]))
1338 return which? (i+40) : (i+30);
1340 if (!StrCaseCmp(buf, "default")) return -1;
1342 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1347 parse_cpair(cc, str)
1351 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1352 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1357 /* bg and attr are optional */
1358 textColors[(int)cc].bg = parse_color(str, 1);
1359 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1360 textColors[(int)cc].attr = 0;
1366 /* Arrange to catch delete-window events */
1367 Atom wm_delete_window;
1369 CatchDeleteWindow(Widget w, String procname)
1372 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1373 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1374 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1381 XtSetArg(args[0], XtNiconic, False);
1382 XtSetValues(shellWidget, args, 1);
1384 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1387 //---------------------------------------------------------------------------------------------------------
1388 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1391 #define CW_USEDEFAULT (1<<31)
1392 #define ICS_TEXT_MENU_SIZE 90
1393 #define DEBUG_FILE "xboard.debug"
1394 #define SetCurrentDirectory chdir
1395 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1399 // these two must some day move to frontend.h, when they are implemented
1400 Boolean GameListIsUp();
1402 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1405 // front-end part of option handling
1407 // [HGM] This platform-dependent table provides the location for storing the color info
1408 extern char *crWhite, * crBlack;
1412 &appData.whitePieceColor,
1413 &appData.blackPieceColor,
1414 &appData.lightSquareColor,
1415 &appData.darkSquareColor,
1416 &appData.highlightSquareColor,
1417 &appData.premoveHighlightColor,
1418 &appData.lowTimeWarningColor,
1429 // [HGM] font: keep a font for each square size, even non-stndard ones
1430 #define NUM_SIZES 18
1431 #define MAX_SIZE 130
1432 Boolean fontIsSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1433 char *fontTable[NUM_FONTS][MAX_SIZE];
1436 ParseFont(char *name, int number)
1437 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1439 if(sscanf(name, "size%d:", &size)) {
1440 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1441 // defer processing it until we know if it matches our board size
1442 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1443 fontTable[number][size] = strdup(strchr(name, ':')+1);
1444 fontValid[number][size] = True;
1449 case 0: // CLOCK_FONT
1450 appData.clockFont = strdup(name);
1452 case 1: // MESSAGE_FONT
1453 appData.font = strdup(name);
1455 case 2: // COORD_FONT
1456 appData.coordFont = strdup(name);
1461 fontIsSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1466 { // only 2 fonts currently
1467 appData.clockFont = CLOCK_FONT_NAME;
1468 appData.coordFont = COORD_FONT_NAME;
1469 appData.font = DEFAULT_FONT_NAME;
1474 { // no-op, until we identify the code for this already in XBoard and move it here
1478 ParseColor(int n, char *name)
1479 { // in XBoard, just copy the color-name string
1480 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1484 ParseTextAttribs(ColorClass cc, char *s)
1486 (&appData.colorShout)[cc] = strdup(s);
1490 ParseBoardSize(void *addr, char *name)
1492 appData.boardSize = strdup(name);
1497 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1501 SetCommPortDefaults()
1502 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1505 // [HGM] args: these three cases taken out to stay in front-end
1507 SaveFontArg(FILE *f, ArgDescriptor *ad)
1510 int i, n = (int)(intptr_t)ad->argLoc;
1512 case 0: // CLOCK_FONT
1513 name = appData.clockFont;
1515 case 1: // MESSAGE_FONT
1516 name = appData.font;
1518 case 2: // COORD_FONT
1519 name = appData.coordFont;
1524 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1525 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1526 fontTable[n][squareSize] = strdup(name);
1527 fontValid[n][squareSize] = True;
1530 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1531 fprintf(f, OPTCHAR "%s" SEPCHAR "\"size%d:%s\"\n", ad->argName, i, fontTable[n][i]);
1536 { // nothing to do, as the sounds are at all times represented by their text-string names already
1540 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1541 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1542 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
1546 SaveColor(FILE *f, ArgDescriptor *ad)
1547 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1548 if(colorVariable[(int)(intptr_t)ad->argLoc])
1549 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
1553 SaveBoardSize(FILE *f, char *name, void *addr)
1554 { // wrapper to shield back-end from BoardSize & sizeInfo
1555 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1559 ParseCommPortSettings(char *s)
1560 { // no such option in XBoard (yet)
1563 extern Widget engineOutputShell;
1566 GetActualPlacement(Widget wg, WindowPlacement *wp)
1576 XtSetArg(args[i], XtNx, &x); i++;
1577 XtSetArg(args[i], XtNy, &y); i++;
1578 XtSetArg(args[i], XtNwidth, &w); i++;
1579 XtSetArg(args[i], XtNheight, &h); i++;
1580 XtGetValues(wg, args, i);
1589 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1590 // In XBoard this will have to wait until awareness of window parameters is implemented
1591 GetActualPlacement(shellWidget, &wpMain);
1592 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput);
1593 if(MoveHistoryIsUp()) GetActualPlacement(shells[7], &wpMoveHistory);
1594 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1595 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1596 if(shellUp[1]) GetActualPlacement(shells[1], &wpComment);
1597 if(shellUp[2]) GetActualPlacement(shells[2], &wpTags);
1601 PrintCommPortSettings(FILE *f, char *name)
1602 { // This option does not exist in XBoard
1606 MySearchPath(char *installDir, char *name, char *fullname)
1607 { // just append installDir and name. Perhaps ExpandPath should be used here?
1608 name = ExpandPathName(name);
1609 if(name && name[0] == '/')
1610 safeStrCpy(fullname, name, MSG_SIZ );
1612 sprintf(fullname, "%s%c%s", installDir, '/', name);
1618 MyGetFullPathName(char *name, char *fullname)
1619 { // should use ExpandPath?
1620 name = ExpandPathName(name);
1621 safeStrCpy(fullname, name, MSG_SIZ );
1626 EnsureOnScreen(int *x, int *y, int minX, int minY)
1633 { // [HGM] args: allows testing if main window is realized from back-end
1634 return xBoardWindow != 0;
1638 PopUpStartupDialog()
1639 { // start menu not implemented in XBoard
1643 ConvertToLine(int argc, char **argv)
1645 static char line[128*1024], buf[1024];
1649 for(i=1; i<argc; i++)
1651 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') || argv[i][0] == NULLCHAR)
1652 && argv[i][0] != '{' )
1653 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1655 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1656 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1659 line[strlen(line)-1] = NULLCHAR;
1663 //--------------------------------------------------------------------------------------------
1665 extern Boolean twoBoards, partnerUp;
1668 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1670 #define BoardSize int
1671 void InitDrawingSizes(BoardSize boardSize, int flags)
1672 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1673 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1675 XtGeometryResult gres;
1678 if(!formWidget) return;
1681 * Enable shell resizing.
1683 shellArgs[0].value = (XtArgVal) &w;
1684 shellArgs[1].value = (XtArgVal) &h;
1685 XtGetValues(shellWidget, shellArgs, 2);
1687 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1688 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1689 XtSetValues(shellWidget, &shellArgs[2], 4);
1691 XtSetArg(args[0], XtNdefaultDistance, &sep);
1692 XtGetValues(formWidget, args, 1);
1694 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1695 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1696 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1698 hOffset = boardWidth + 10;
1699 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1700 secondSegments[i] = gridSegments[i];
1701 secondSegments[i].x1 += hOffset;
1702 secondSegments[i].x2 += hOffset;
1705 XtSetArg(args[0], XtNwidth, boardWidth);
1706 XtSetArg(args[1], XtNheight, boardHeight);
1707 XtSetValues(boardWidget, args, 2);
1709 timerWidth = (boardWidth - sep) / 2;
1710 XtSetArg(args[0], XtNwidth, timerWidth);
1711 XtSetValues(whiteTimerWidget, args, 1);
1712 XtSetValues(blackTimerWidget, args, 1);
1714 XawFormDoLayout(formWidget, False);
1716 if (appData.titleInWindow) {
1718 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1719 XtSetArg(args[i], XtNheight, &h); i++;
1720 XtGetValues(titleWidget, args, i);
1722 w = boardWidth - 2*bor;
1724 XtSetArg(args[0], XtNwidth, &w);
1725 XtGetValues(menuBarWidget, args, 1);
1726 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1729 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1730 if (gres != XtGeometryYes && appData.debugMode) {
1732 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1733 programName, gres, w, h, wr, hr);
1737 XawFormDoLayout(formWidget, True);
1740 * Inhibit shell resizing.
1742 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1743 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1744 shellArgs[4].value = shellArgs[2].value = w;
1745 shellArgs[5].value = shellArgs[3].value = h;
1746 XtSetValues(shellWidget, &shellArgs[0], 6);
1748 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1751 for(i=0; i<4; i++) {
1753 for(p=0; p<=(int)WhiteKing; p++)
1754 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1755 if(gameInfo.variant == VariantShogi) {
1756 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1757 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1758 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1759 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1760 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1763 if(gameInfo.variant == VariantGothic) {
1764 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1767 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1768 xpmPieceBitmap[i][(int)WhiteAngel] = xpmPieceBitmap2[i][(int)WhiteFalcon];
1769 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1772 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1773 for(p=0; p<=(int)WhiteKing; p++)
1774 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1775 if(gameInfo.variant == VariantShogi) {
1776 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1777 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1778 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1779 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1780 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1783 if(gameInfo.variant == VariantGothic) {
1784 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1787 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1788 ximMaskPm[(int)WhiteAngel] = ximMaskPm2[(int)WhiteFalcon];
1789 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1794 for(i=0; i<2; i++) {
1796 for(p=0; p<=(int)WhiteKing; p++)
1797 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1798 if(gameInfo.variant == VariantShogi) {
1799 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1800 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1801 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1802 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1803 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1806 if(gameInfo.variant == VariantGothic) {
1807 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1810 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1811 pieceBitmap[i][(int)WhiteAngel] = pieceBitmap2[i][(int)WhiteFalcon];
1812 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1822 void ParseIcsTextColors()
1823 { // [HGM] tken out of main(), so it can be called from ICS-Options dialog
1824 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1825 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1826 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1827 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1828 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1829 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1830 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1831 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1832 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1833 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1835 if (appData.colorize) {
1837 _("%s: can't parse color names; disabling colorization\n"),
1840 appData.colorize = FALSE;
1845 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
1846 XrmValue vFrom, vTo;
1847 int forceMono = False;
1849 if (!appData.monoMode) {
1850 vFrom.addr = (caddr_t) appData.lightSquareColor;
1851 vFrom.size = strlen(appData.lightSquareColor);
1852 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1853 if (vTo.addr == NULL) {
1854 appData.monoMode = True;
1857 lightSquareColor = *(Pixel *) vTo.addr;
1860 if (!appData.monoMode) {
1861 vFrom.addr = (caddr_t) appData.darkSquareColor;
1862 vFrom.size = strlen(appData.darkSquareColor);
1863 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1864 if (vTo.addr == NULL) {
1865 appData.monoMode = True;
1868 darkSquareColor = *(Pixel *) vTo.addr;
1871 if (!appData.monoMode) {
1872 vFrom.addr = (caddr_t) appData.whitePieceColor;
1873 vFrom.size = strlen(appData.whitePieceColor);
1874 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1875 if (vTo.addr == NULL) {
1876 appData.monoMode = True;
1879 whitePieceColor = *(Pixel *) vTo.addr;
1882 if (!appData.monoMode) {
1883 vFrom.addr = (caddr_t) appData.blackPieceColor;
1884 vFrom.size = strlen(appData.blackPieceColor);
1885 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1886 if (vTo.addr == NULL) {
1887 appData.monoMode = True;
1890 blackPieceColor = *(Pixel *) vTo.addr;
1894 if (!appData.monoMode) {
1895 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1896 vFrom.size = strlen(appData.highlightSquareColor);
1897 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1898 if (vTo.addr == NULL) {
1899 appData.monoMode = True;
1902 highlightSquareColor = *(Pixel *) vTo.addr;
1906 if (!appData.monoMode) {
1907 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1908 vFrom.size = strlen(appData.premoveHighlightColor);
1909 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1910 if (vTo.addr == NULL) {
1911 appData.monoMode = True;
1914 premoveHighlightColor = *(Pixel *) vTo.addr;
1922 { // [HGM] taken out of main
1924 if (appData.monoMode && // [HGM] no sense to go on to certain doom
1925 (appData.bitmapDirectory == NULL || appData.bitmapDirectory[0] == NULLCHAR))
1926 appData.bitmapDirectory = DEF_BITMAP_DIR;
1928 if (appData.bitmapDirectory[0] != NULLCHAR) {
1932 CreateXPMBoard(appData.liteBackTextureFile, 1);
1933 CreateXPMBoard(appData.darkBackTextureFile, 0);
1937 /* Create regular pieces */
1938 if (!useImages) CreatePieces();
1947 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1948 XSetWindowAttributes window_attributes;
1950 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1951 XrmValue vFrom, vTo;
1952 XtGeometryResult gres;
1955 int forceMono = False;
1957 srandom(time(0)); // [HGM] book: make random truly random
1959 setbuf(stdout, NULL);
1960 setbuf(stderr, NULL);
1963 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1964 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1968 programName = strrchr(argv[0], '/');
1969 if (programName == NULL)
1970 programName = argv[0];
1975 XtSetLanguageProc(NULL, NULL, NULL);
1976 bindtextdomain(PACKAGE, LOCALEDIR);
1977 textdomain(PACKAGE);
1981 XtAppInitialize(&appContext, "XBoard", shellOptions,
1982 XtNumber(shellOptions),
1983 &argc, argv, xboardResources, NULL, 0);
1984 appData.boardSize = "";
1985 InitAppData(ConvertToLine(argc, argv));
1987 if (p == NULL) p = "/tmp";
1988 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1989 gameCopyFilename = (char*) malloc(i);
1990 gamePasteFilename = (char*) malloc(i);
1991 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1992 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1994 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1995 clientResources, XtNumber(clientResources),
1998 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1999 static char buf[MSG_SIZ];
2000 EscapeExpand(buf, appData.firstInitString);
2001 appData.firstInitString = strdup(buf);
2002 EscapeExpand(buf, appData.secondInitString);
2003 appData.secondInitString = strdup(buf);
2004 EscapeExpand(buf, appData.firstComputerString);
2005 appData.firstComputerString = strdup(buf);
2006 EscapeExpand(buf, appData.secondComputerString);
2007 appData.secondComputerString = strdup(buf);
2010 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
2013 if (chdir(chessDir) != 0) {
2014 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
2020 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
2021 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
2022 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
2023 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
2026 setbuf(debugFP, NULL);
2030 if (appData.debugMode) {
2031 fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
2035 /* [HGM,HR] make sure board size is acceptable */
2036 if(appData.NrFiles > BOARD_FILES ||
2037 appData.NrRanks > BOARD_RANKS )
2038 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
2041 /* This feature does not work; animation needs a rewrite */
2042 appData.highlightDragging = FALSE;
2046 xDisplay = XtDisplay(shellWidget);
2047 xScreen = DefaultScreen(xDisplay);
2048 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
2050 gameInfo.variant = StringToVariant(appData.variant);
2051 InitPosition(FALSE);
2054 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
2056 if (isdigit(appData.boardSize[0])) {
2057 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
2058 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
2059 &fontPxlSize, &smallLayout, &tinyLayout);
2061 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
2062 programName, appData.boardSize);
2066 /* Find some defaults; use the nearest known size */
2067 SizeDefaults *szd, *nearest;
2068 int distance = 99999;
2069 nearest = szd = sizeDefaults;
2070 while (szd->name != NULL) {
2071 if (abs(szd->squareSize - squareSize) < distance) {
2073 distance = abs(szd->squareSize - squareSize);
2074 if (distance == 0) break;
2078 if (i < 2) lineGap = nearest->lineGap;
2079 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
2080 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
2081 if (i < 5) fontPxlSize = nearest->fontPxlSize;
2082 if (i < 6) smallLayout = nearest->smallLayout;
2083 if (i < 7) tinyLayout = nearest->tinyLayout;
2086 SizeDefaults *szd = sizeDefaults;
2087 if (*appData.boardSize == NULLCHAR) {
2088 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
2089 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
2092 if (szd->name == NULL) szd--;
2093 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
2095 while (szd->name != NULL &&
2096 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
2097 if (szd->name == NULL) {
2098 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
2099 programName, appData.boardSize);
2103 squareSize = szd->squareSize;
2104 lineGap = szd->lineGap;
2105 clockFontPxlSize = szd->clockFontPxlSize;
2106 coordFontPxlSize = szd->coordFontPxlSize;
2107 fontPxlSize = szd->fontPxlSize;
2108 smallLayout = szd->smallLayout;
2109 tinyLayout = szd->tinyLayout;
2110 // [HGM] font: use defaults from settings file if available and not overruled
2112 if(!fontIsSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
2113 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
2114 if(!fontIsSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
2115 appData.font = fontTable[MESSAGE_FONT][squareSize];
2116 if(!fontIsSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
2117 appData.coordFont = fontTable[COORD_FONT][squareSize];
2119 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
2120 if (strlen(appData.pixmapDirectory) > 0) {
2121 p = ExpandPathName(appData.pixmapDirectory);
2123 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
2124 appData.pixmapDirectory);
2127 if (appData.debugMode) {
2128 fprintf(stderr, _("\
2129 XBoard square size (hint): %d\n\
2130 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
2132 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
2133 if (appData.debugMode) {
2134 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
2137 defaultLineGap = lineGap;
2138 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
2140 /* [HR] height treated separately (hacked) */
2141 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
2142 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
2143 if (appData.showJail == 1) {
2144 /* Jail on top and bottom */
2145 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2146 XtSetArg(boardArgs[2], XtNheight,
2147 boardHeight + 2*(lineGap + squareSize));
2148 } else if (appData.showJail == 2) {
2150 XtSetArg(boardArgs[1], XtNwidth,
2151 boardWidth + 2*(lineGap + squareSize));
2152 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2155 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2156 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2160 * Determine what fonts to use.
2163 appData.font = InsertPxlSize(appData.font, fontPxlSize);
2164 appData.clockFont = InsertPxlSize(appData.clockFont, clockFontPxlSize);
2165 appData.coordFont = InsertPxlSize(appData.coordFont, coordFontPxlSize);
2166 fontSet = CreateFontSet(appData.font);
2167 clockFontSet = CreateFontSet(appData.clockFont);
2169 /* For the coordFont, use the 0th font of the fontset. */
2170 XFontSet coordFontSet = CreateFontSet(appData.coordFont);
2171 XFontStruct **font_struct_list;
2172 char **font_name_list;
2173 XFontsOfFontSet(coordFontSet, &font_struct_list, &font_name_list);
2174 coordFontID = XLoadFont(xDisplay, font_name_list[0]);
2175 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2178 appData.font = FindFont(appData.font, fontPxlSize);
2179 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2180 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2181 clockFontID = XLoadFont(xDisplay, appData.clockFont);
2182 clockFontStruct = XQueryFont(xDisplay, clockFontID);
2183 coordFontID = XLoadFont(xDisplay, appData.coordFont);
2184 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2186 countFontID = coordFontID; // [HGM] holdings
2187 countFontStruct = coordFontStruct;
2189 xdb = XtDatabase(xDisplay);
2191 XrmPutLineResource(&xdb, "*international: True");
2192 vTo.size = sizeof(XFontSet);
2193 vTo.addr = (XtPointer) &fontSet;
2194 XrmPutResource(&xdb, "*fontSet", XtRFontSet, &vTo);
2196 XrmPutStringResource(&xdb, "*font", appData.font);
2200 * Detect if there are not enough colors available and adapt.
2202 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2203 appData.monoMode = True;
2206 forceMono = MakeColors();
2209 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2211 appData.monoMode = True;
2214 if (appData.lowTimeWarning && !appData.monoMode) {
2215 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2216 vFrom.size = strlen(appData.lowTimeWarningColor);
2217 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2218 if (vTo.addr == NULL)
2219 appData.monoMode = True;
2221 lowTimeWarningColor = *(Pixel *) vTo.addr;
2224 if (appData.monoMode && appData.debugMode) {
2225 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2226 (unsigned long) XWhitePixel(xDisplay, xScreen),
2227 (unsigned long) XBlackPixel(xDisplay, xScreen));
2230 ParseIcsTextColors();
2231 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2232 textColors[ColorNone].attr = 0;
2234 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2240 layoutName = "tinyLayout";
2241 } else if (smallLayout) {
2242 layoutName = "smallLayout";
2244 layoutName = "normalLayout";
2246 /* Outer layoutWidget is there only to provide a name for use in
2247 resources that depend on the layout style */
2249 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2250 layoutArgs, XtNumber(layoutArgs));
2252 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2253 formArgs, XtNumber(formArgs));
2254 XtSetArg(args[0], XtNdefaultDistance, &sep);
2255 XtGetValues(formWidget, args, 1);
2258 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2259 XtSetArg(args[0], XtNtop, XtChainTop);
2260 XtSetArg(args[1], XtNbottom, XtChainTop);
2261 XtSetArg(args[2], XtNright, XtChainLeft);
2262 XtSetValues(menuBarWidget, args, 3);
2264 widgetList[j++] = whiteTimerWidget =
2265 XtCreateWidget("whiteTime", labelWidgetClass,
2266 formWidget, timerArgs, XtNumber(timerArgs));
2268 XtSetArg(args[0], XtNfontSet, clockFontSet);
2270 XtSetArg(args[0], XtNfont, clockFontStruct);
2272 XtSetArg(args[1], XtNtop, XtChainTop);
2273 XtSetArg(args[2], XtNbottom, XtChainTop);
2274 XtSetValues(whiteTimerWidget, args, 3);
2276 widgetList[j++] = blackTimerWidget =
2277 XtCreateWidget("blackTime", labelWidgetClass,
2278 formWidget, timerArgs, XtNumber(timerArgs));
2280 XtSetArg(args[0], XtNfontSet, clockFontSet);
2282 XtSetArg(args[0], XtNfont, clockFontStruct);
2284 XtSetArg(args[1], XtNtop, XtChainTop);
2285 XtSetArg(args[2], XtNbottom, XtChainTop);
2286 XtSetValues(blackTimerWidget, args, 3);
2288 if (appData.titleInWindow) {
2289 widgetList[j++] = titleWidget =
2290 XtCreateWidget("title", labelWidgetClass, formWidget,
2291 titleArgs, XtNumber(titleArgs));
2292 XtSetArg(args[0], XtNtop, XtChainTop);
2293 XtSetArg(args[1], XtNbottom, XtChainTop);
2294 XtSetValues(titleWidget, args, 2);
2297 if (appData.showButtonBar) {
2298 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2299 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2300 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2301 XtSetArg(args[2], XtNtop, XtChainTop);
2302 XtSetArg(args[3], XtNbottom, XtChainTop);
2303 XtSetValues(buttonBarWidget, args, 4);
2306 widgetList[j++] = messageWidget =
2307 XtCreateWidget("message", labelWidgetClass, formWidget,
2308 messageArgs, XtNumber(messageArgs));
2309 XtSetArg(args[0], XtNtop, XtChainTop);
2310 XtSetArg(args[1], XtNbottom, XtChainTop);
2311 XtSetValues(messageWidget, args, 2);
2313 widgetList[j++] = boardWidget =
2314 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2315 XtNumber(boardArgs));
2317 XtManageChildren(widgetList, j);
2319 timerWidth = (boardWidth - sep) / 2;
2320 XtSetArg(args[0], XtNwidth, timerWidth);
2321 XtSetValues(whiteTimerWidget, args, 1);
2322 XtSetValues(blackTimerWidget, args, 1);
2324 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2325 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2326 XtGetValues(whiteTimerWidget, args, 2);
2328 if (appData.showButtonBar) {
2329 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2330 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2331 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2335 * formWidget uses these constraints but they are stored
2339 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2340 XtSetValues(menuBarWidget, args, i);
2341 if (appData.titleInWindow) {
2344 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2345 XtSetValues(whiteTimerWidget, args, i);
2347 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2348 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2349 XtSetValues(blackTimerWidget, args, i);
2351 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2352 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2353 XtSetValues(titleWidget, args, i);
2355 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2356 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2357 XtSetValues(messageWidget, args, i);
2358 if (appData.showButtonBar) {
2360 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2361 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2362 XtSetValues(buttonBarWidget, args, i);
2366 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2367 XtSetValues(whiteTimerWidget, args, i);
2369 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2370 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2371 XtSetValues(blackTimerWidget, args, i);
2373 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2374 XtSetValues(titleWidget, args, i);
2376 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2377 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2378 XtSetValues(messageWidget, args, i);
2379 if (appData.showButtonBar) {
2381 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2382 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2383 XtSetValues(buttonBarWidget, args, i);
2388 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2389 XtSetValues(whiteTimerWidget, args, i);
2391 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2392 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2393 XtSetValues(blackTimerWidget, args, i);
2395 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2396 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2397 XtSetValues(messageWidget, args, i);
2398 if (appData.showButtonBar) {
2400 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2401 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2402 XtSetValues(buttonBarWidget, args, i);
2406 XtSetArg(args[0], XtNfromVert, messageWidget);
2407 XtSetArg(args[1], XtNtop, XtChainTop);
2408 XtSetArg(args[2], XtNbottom, XtChainBottom);
2409 XtSetArg(args[3], XtNleft, XtChainLeft);
2410 XtSetArg(args[4], XtNright, XtChainRight);
2411 XtSetValues(boardWidget, args, 5);
2413 XtRealizeWidget(shellWidget);
2416 XtSetArg(args[0], XtNx, wpMain.x);
2417 XtSetArg(args[1], XtNy, wpMain.y);
2418 XtSetValues(shellWidget, args, 2);
2422 * Correct the width of the message and title widgets.
2423 * It is not known why some systems need the extra fudge term.
2424 * The value "2" is probably larger than needed.
2426 XawFormDoLayout(formWidget, False);
2428 #define WIDTH_FUDGE 2
2430 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2431 XtSetArg(args[i], XtNheight, &h); i++;
2432 XtGetValues(messageWidget, args, i);
2433 if (appData.showButtonBar) {
2435 XtSetArg(args[i], XtNwidth, &w); i++;
2436 XtGetValues(buttonBarWidget, args, i);
2437 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2439 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2442 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2443 if (gres != XtGeometryYes && appData.debugMode) {
2444 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2445 programName, gres, w, h, wr, hr);
2448 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2449 /* The size used for the child widget in layout lags one resize behind
2450 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2452 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2453 if (gres != XtGeometryYes && appData.debugMode) {
2454 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2455 programName, gres, w, h, wr, hr);
2458 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2459 XtSetArg(args[1], XtNright, XtChainRight);
2460 XtSetValues(messageWidget, args, 2);
2462 if (appData.titleInWindow) {
2464 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2465 XtSetArg(args[i], XtNheight, &h); i++;
2466 XtGetValues(titleWidget, args, i);
2468 w = boardWidth - 2*bor;
2470 XtSetArg(args[0], XtNwidth, &w);
2471 XtGetValues(menuBarWidget, args, 1);
2472 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2475 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2476 if (gres != XtGeometryYes && appData.debugMode) {
2478 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2479 programName, gres, w, h, wr, hr);
2482 XawFormDoLayout(formWidget, True);
2484 xBoardWindow = XtWindow(boardWidget);
2486 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2487 // not need to go into InitDrawingSizes().
2491 * Create X checkmark bitmap and initialize option menu checks.
2493 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2494 checkmark_bits, checkmark_width, checkmark_height);
2495 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2496 #ifndef OPTIONSDIALOG
2497 if (appData.alwaysPromoteToQueen) {
2498 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2501 if (appData.animateDragging) {
2502 XtSetValues(XtNameToWidget(menuBarWidget,
2503 "menuOptions.Animate Dragging"),
2506 if (appData.animate) {
2507 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2510 if (appData.autoCallFlag) {
2511 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2514 if (appData.autoFlipView) {
2515 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2518 if (appData.blindfold) {
2519 XtSetValues(XtNameToWidget(menuBarWidget,
2520 "menuOptions.Blindfold"), args, 1);
2522 if (appData.flashCount > 0) {
2523 XtSetValues(XtNameToWidget(menuBarWidget,
2524 "menuOptions.Flash Moves"),
2528 if (appData.highlightDragging) {
2529 XtSetValues(XtNameToWidget(menuBarWidget,
2530 "menuOptions.Highlight Dragging"),
2534 if (appData.highlightLastMove) {
2535 XtSetValues(XtNameToWidget(menuBarWidget,
2536 "menuOptions.Highlight Last Move"),
2539 if (appData.highlightMoveWithArrow) {
2540 XtSetValues(XtNameToWidget(menuBarWidget,
2541 "menuOptions.Arrow"),
2544 // if (appData.icsAlarm) {
2545 // XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2548 if (appData.ringBellAfterMoves) {
2549 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2552 if (appData.oneClick) {
2553 XtSetValues(XtNameToWidget(menuBarWidget,
2554 "menuOptions.OneClick"), args, 1);
2556 if (appData.periodicUpdates) {
2557 XtSetValues(XtNameToWidget(menuBarWidget,
2558 "menuOptions.Periodic Updates"), args, 1);
2560 if (appData.ponderNextMove) {
2561 XtSetValues(XtNameToWidget(menuBarWidget,
2562 "menuOptions.Ponder Next Move"), args, 1);
2564 if (appData.popupExitMessage) {
2565 XtSetValues(XtNameToWidget(menuBarWidget,
2566 "menuOptions.Popup Exit Message"), args, 1);
2568 if (appData.popupMoveErrors) {
2569 XtSetValues(XtNameToWidget(menuBarWidget,
2570 "menuOptions.Popup Move Errors"), args, 1);
2572 // if (appData.premove) {
2573 // XtSetValues(XtNameToWidget(menuBarWidget,
2574 // "menuOptions.Premove"), args, 1);
2576 if (appData.showCoords) {
2577 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2580 if (appData.hideThinkingFromHuman) {
2581 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2584 if (appData.testLegality) {
2585 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2589 if (saveSettingsOnExit) {
2590 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2597 ReadBitmap(&wIconPixmap, "icon_white.bm",
2598 icon_white_bits, icon_white_width, icon_white_height);
2599 ReadBitmap(&bIconPixmap, "icon_black.bm",
2600 icon_black_bits, icon_black_width, icon_black_height);
2601 iconPixmap = wIconPixmap;
2603 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2604 XtSetValues(shellWidget, args, i);
2607 * Create a cursor for the board widget.
2609 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2610 XChangeWindowAttributes(xDisplay, xBoardWindow,
2611 CWCursor, &window_attributes);
2614 * Inhibit shell resizing.
2616 shellArgs[0].value = (XtArgVal) &w;
2617 shellArgs[1].value = (XtArgVal) &h;
2618 XtGetValues(shellWidget, shellArgs, 2);
2619 shellArgs[4].value = shellArgs[2].value = w;
2620 shellArgs[5].value = shellArgs[3].value = h;
2621 XtSetValues(shellWidget, &shellArgs[2], 4);
2622 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2623 marginH = h - boardHeight;
2625 CatchDeleteWindow(shellWidget, "QuitProc");
2633 if (appData.animate || appData.animateDragging)
2636 XtAugmentTranslations(formWidget,
2637 XtParseTranslationTable(globalTranslations));
2638 XtAugmentTranslations(boardWidget,
2639 XtParseTranslationTable(boardTranslations));
2640 XtAugmentTranslations(whiteTimerWidget,
2641 XtParseTranslationTable(whiteTranslations));
2642 XtAugmentTranslations(blackTimerWidget,
2643 XtParseTranslationTable(blackTranslations));
2645 /* Why is the following needed on some versions of X instead
2646 * of a translation? */
2647 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2648 (XtEventHandler) EventProc, NULL);
2650 XtAddEventHandler(formWidget, KeyPressMask, False,
2651 (XtEventHandler) MoveTypeInProc, NULL);
2653 /* [AS] Restore layout */
2654 if( wpMoveHistory.visible ) {
2658 if( wpEvalGraph.visible )
2663 if( wpEngineOutput.visible ) {
2664 EngineOutputPopUp();
2669 if (errorExitStatus == -1) {
2670 if (appData.icsActive) {
2671 /* We now wait until we see "login:" from the ICS before
2672 sending the logon script (problems with timestamp otherwise) */
2673 /*ICSInitScript();*/
2674 if (appData.icsInputBox) ICSInputBoxPopUp();
2678 signal(SIGWINCH, TermSizeSigHandler);
2680 signal(SIGINT, IntSigHandler);
2681 signal(SIGTERM, IntSigHandler);
2682 if (*appData.cmailGameName != NULLCHAR) {
2683 signal(SIGUSR1, CmailSigHandler);
2686 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2688 // XtSetKeyboardFocus(shellWidget, formWidget);
2689 XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
2691 XtAppMainLoop(appContext);
2692 if (appData.debugMode) fclose(debugFP); // [DM] debug
2699 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2700 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2702 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2703 unlink(gameCopyFilename);
2704 unlink(gamePasteFilename);
2707 RETSIGTYPE TermSizeSigHandler(int sig)
2720 CmailSigHandler(sig)
2726 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2728 /* Activate call-back function CmailSigHandlerCallBack() */
2729 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2731 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2735 CmailSigHandlerCallBack(isr, closure, message, count, error)
2743 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2745 /**** end signal code ****/
2751 /* try to open the icsLogon script, either in the location given
2752 * or in the users HOME directory
2759 f = fopen(appData.icsLogon, "r");
2762 homedir = getenv("HOME");
2763 if (homedir != NULL)
2765 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2766 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2767 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2768 f = fopen(buf, "r");
2773 ProcessICSInitScript(f);
2775 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2798 if (!menuBarWidget) return;
2799 w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2801 DisplayError("menuEdit.Revert", 0);
2803 XtSetSensitive(w, !grey);
2805 w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2807 DisplayError("menuEdit.Annotate", 0);
2809 XtSetSensitive(w, !grey);
2814 SetMenuEnables(enab)
2818 if (!menuBarWidget) return;
2819 while (enab->name != NULL) {
2820 w = XtNameToWidget(menuBarWidget, enab->name);
2822 DisplayError(enab->name, 0);
2824 XtSetSensitive(w, enab->value);
2830 Enables icsEnables[] = {
2831 { "menuFile.Mail Move", False },
2832 { "menuFile.Reload CMail Message", False },
2833 { "menuMode.Machine Black", False },
2834 { "menuMode.Machine White", False },
2835 { "menuMode.Analysis Mode", False },
2836 { "menuMode.Analyze File", False },
2837 { "menuMode.Two Machines", False },
2838 { "menuMode.Machine Match", False },
2840 { "menuEngine.Hint", False },
2841 { "menuEngine.Book", False },
2842 { "menuEngine.Move Now", False },
2843 #ifndef OPTIONSDIALOG
2844 { "menuOptions.Periodic Updates", False },
2845 { "menuOptions.Hide Thinking", False },
2846 { "menuOptions.Ponder Next Move", False },
2849 { "menuEngine.Engine #1 Settings", False },
2850 { "menuEngine.Engine #2 Settings", False },
2851 { "menuEngine.Load Engine", False },
2852 { "menuEdit.Annotate", False },
2853 { "menuOptions.Match", False },
2857 Enables ncpEnables[] = {
2858 { "menuFile.Mail Move", False },
2859 { "menuFile.Reload CMail Message", False },
2860 { "menuMode.Machine White", False },
2861 { "menuMode.Machine Black", False },
2862 { "menuMode.Analysis Mode", False },
2863 { "menuMode.Analyze File", False },
2864 { "menuMode.Two Machines", False },
2865 { "menuMode.Machine Match", False },
2866 { "menuMode.ICS Client", False },
2867 { "menuView.ICStex", False },
2868 { "menuView.ICS Input Box", False },
2869 { "Action", False },
2870 { "menuEdit.Revert", False },
2871 { "menuEdit.Annotate", False },
2872 { "menuEngine.Engine #1 Settings", False },
2873 { "menuEngine.Engine #2 Settings", False },
2874 { "menuEngine.Move Now", False },
2875 { "menuEngine.Retract Move", False },
2876 { "menuOptions.ICS", False },
2877 #ifndef OPTIONSDIALOG
2878 { "menuOptions.Auto Flag", False },
2879 { "menuOptions.Auto Flip View", False },
2880 // { "menuOptions.ICS Alarm", False },
2881 { "menuOptions.Move Sound", False },
2882 { "menuOptions.Hide Thinking", False },
2883 { "menuOptions.Periodic Updates", False },
2884 { "menuOptions.Ponder Next Move", False },
2886 { "menuEngine.Hint", False },
2887 { "menuEngine.Book", False },
2891 Enables gnuEnables[] = {
2892 { "menuMode.ICS Client", False },
2893 { "menuView.ICStex", False },
2894 { "menuView.ICS Input Box", False },
2895 { "menuAction.Accept", False },
2896 { "menuAction.Decline", False },
2897 { "menuAction.Rematch", False },
2898 { "menuAction.Adjourn", False },
2899 { "menuAction.Stop Examining", False },
2900 { "menuAction.Stop Observing", False },
2901 { "menuAction.Upload to Examine", False },
2902 { "menuEdit.Revert", False },
2903 { "menuEdit.Annotate", False },
2904 { "menuOptions.ICS", False },
2906 /* The next two options rely on SetCmailMode being called *after* */
2907 /* SetGNUMode so that when GNU is being used to give hints these */
2908 /* menu options are still available */
2910 { "menuFile.Mail Move", False },
2911 { "menuFile.Reload CMail Message", False },
2912 // [HGM] The following have been added to make a switch from ncp to GNU mode possible
2913 { "menuMode.Machine White", True },
2914 { "menuMode.Machine Black", True },
2915 { "menuMode.Analysis Mode", True },
2916 { "menuMode.Analyze File", True },
2917 { "menuMode.Two Machines", True },
2918 { "menuMode.Machine Match", True },
2919 { "menuEngine.Engine #1 Settings", True },
2920 { "menuEngine.Engine #2 Settings", True },
2921 { "menuEngine.Hint", True },
2922 { "menuEngine.Book", True },
2923 { "menuEngine.Move Now", True },
2924 { "menuEngine.Retract Move", True },
2929 Enables cmailEnables[] = {
2931 { "menuAction.Call Flag", False },
2932 { "menuAction.Draw", True },
2933 { "menuAction.Adjourn", False },
2934 { "menuAction.Abort", False },
2935 { "menuAction.Stop Observing", False },
2936 { "menuAction.Stop Examining", False },
2937 { "menuFile.Mail Move", True },
2938 { "menuFile.Reload CMail Message", True },
2942 Enables trainingOnEnables[] = {
2943 { "menuMode.Edit Comment", False },
2944 { "menuMode.Pause", False },
2945 { "menuEdit.Forward", False },
2946 { "menuEdit.Backward", False },
2947 { "menuEdit.Forward to End", False },
2948 { "menuEdit.Back to Start", False },
2949 { "menuEngine.Move Now", False },
2950 { "menuEdit.Truncate Game", False },
2954 Enables trainingOffEnables[] = {
2955 { "menuMode.Edit Comment", True },
2956 { "menuMode.Pause", True },
2957 { "menuEdit.Forward", True },
2958 { "menuEdit.Backward", True },
2959 { "menuEdit.Forward to End", True },
2960 { "menuEdit.Back to Start", True },
2961 { "menuEngine.Move Now", True },
2962 { "menuEdit.Truncate Game", True },
2966 Enables machineThinkingEnables[] = {
2967 { "menuFile.Load Game", False },
2968 // { "menuFile.Load Next Game", False },
2969 // { "menuFile.Load Previous Game", False },
2970 // { "menuFile.Reload Same Game", False },
2971 { "menuEdit.Paste Game", False },
2972 { "menuFile.Load Position", False },
2973 // { "menuFile.Load Next Position", False },
2974 // { "menuFile.Load Previous Position", False },
2975 // { "menuFile.Reload Same Position", False },
2976 { "menuEdit.Paste Position", False },
2977 { "menuMode.Machine White", False },
2978 { "menuMode.Machine Black", False },
2979 { "menuMode.Two Machines", False },
2980 // { "menuMode.Machine Match", False },
2981 { "menuEngine.Retract Move", False },
2985 Enables userThinkingEnables[] = {
2986 { "menuFile.Load Game", True },
2987 // { "menuFile.Load Next Game", True },
2988 // { "menuFile.Load Previous Game", True },
2989 // { "menuFile.Reload Same Game", True },
2990 { "menuEdit.Paste Game", True },
2991 { "menuFile.Load Position", True },
2992 // { "menuFile.Load Next Position", True },
2993 // { "menuFile.Load Previous Position", True },
2994 // { "menuFile.Reload Same Position", True },
2995 { "menuEdit.Paste Position", True },
2996 { "menuMode.Machine White", True },
2997 { "menuMode.Machine Black", True },
2998 { "menuMode.Two Machines", True },
2999 // { "menuMode.Machine Match", True },
3000 { "menuEngine.Retract Move", True },
3006 SetMenuEnables(icsEnables);
3009 if (appData.zippyPlay && !appData.noChessProgram) { /* [DM] icsEngineAnalyze */
3010 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
3011 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuEngine.Engine #1 Settings"), True);
3019 SetMenuEnables(ncpEnables);
3025 SetMenuEnables(gnuEnables);
3031 SetMenuEnables(cmailEnables);
3037 SetMenuEnables(trainingOnEnables);
3038 if (appData.showButtonBar) {
3039 XtSetSensitive(buttonBarWidget, False);
3045 SetTrainingModeOff()
3047 SetMenuEnables(trainingOffEnables);
3048 if (appData.showButtonBar) {
3049 XtSetSensitive(buttonBarWidget, True);
3054 SetUserThinkingEnables()
3056 if (appData.noChessProgram) return;
3057 SetMenuEnables(userThinkingEnables);
3061 SetMachineThinkingEnables()
3063 if (appData.noChessProgram) return;
3064 SetMenuEnables(machineThinkingEnables);
3066 case MachinePlaysBlack:
3067 case MachinePlaysWhite:
3068 case TwoMachinesPlay:
3069 XtSetSensitive(XtNameToWidget(menuBarWidget,
3070 ModeToWidgetName(gameMode)), True);
3077 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
3078 #define HISTORY_SIZE 64
3079 static char *history[HISTORY_SIZE];
3080 int histIn = 0, histP = 0;
3083 SaveInHistory(char *cmd)
3085 if (history[histIn] != NULL) {
3086 free(history[histIn]);
3087 history[histIn] = NULL;
3089 if (*cmd == NULLCHAR) return;
3090 history[histIn] = StrSave(cmd);
3091 histIn = (histIn + 1) % HISTORY_SIZE;
3092 if (history[histIn] != NULL) {
3093 free(history[histIn]);
3094 history[histIn] = NULL;
3100 PrevInHistory(char *cmd)
3103 if (histP == histIn) {
3104 if (history[histIn] != NULL) free(history[histIn]);
3105 history[histIn] = StrSave(cmd);
3107 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
3108 if (newhp == histIn || history[newhp] == NULL) return NULL;
3110 return history[histP];
3116 if (histP == histIn) return NULL;
3117 histP = (histP + 1) % HISTORY_SIZE;
3118 return history[histP];
3120 // end of borrowed code
3122 #define Abs(n) ((n)<0 ? -(n) : (n))
3126 InsertPxlSize(pattern, targetPxlSize)
3130 char *base_fnt_lst, strInt[12], *p, *q;
3131 int alternatives, i, len, strIntLen;
3134 * Replace the "*" (if present) in the pixel-size slot of each
3135 * alternative with the targetPxlSize.
3139 while ((p = strchr(p, ',')) != NULL) {
3143 snprintf(strInt, sizeof(strInt), "%d", targetPxlSize);
3144 strIntLen = strlen(strInt);
3145 base_fnt_lst = calloc(1, strlen(pattern) + strIntLen * alternatives + 1);
3149 while (alternatives--) {
3150 char *comma = strchr(p, ',');
3151 for (i=0; i<14; i++) {
3152 char *hyphen = strchr(p, '-');
3154 if (comma && hyphen > comma) break;
3155 len = hyphen + 1 - p;
3156 if (i == 7 && *p == '*' && len == 2) {
3158 memcpy(q, strInt, strIntLen);
3168 len = comma + 1 - p;
3175 return base_fnt_lst;
3179 CreateFontSet(base_fnt_lst)
3183 char **missing_list;
3187 fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
3188 &missing_list, &missing_count, &def_string);
3189 if (appData.debugMode) {
3191 XFontStruct **font_struct_list;
3192 char **font_name_list;
3193 fprintf(debugFP, "Requested font set for list %s\n", base_fnt_lst);
3195 fprintf(debugFP, " got list %s, locale %s\n",
3196 XBaseFontNameListOfFontSet(fntSet),
3197 XLocaleOfFontSet(fntSet));
3198 count = XFontsOfFontSet(fntSet, &font_struct_list, &font_name_list);
3199 for (i = 0; i < count; i++) {
3200 fprintf(debugFP, " got charset %s\n", font_name_list[i]);
3203 for (i = 0; i < missing_count; i++) {
3204 fprintf(debugFP, " missing charset %s\n", missing_list[i]);
3207 if (fntSet == NULL) {
3208 fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
3213 #else // not ENABLE_NLS
3215 * Find a font that matches "pattern" that is as close as
3216 * possible to the targetPxlSize. Prefer fonts that are k
3217 * pixels smaller to fonts that are k pixels larger. The
3218 * pattern must be in the X Consortium standard format,
3219 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3220 * The return value should be freed with XtFree when no
3224 FindFont(pattern, targetPxlSize)
3228 char **fonts, *p, *best, *scalable, *scalableTail;
3229 int i, j, nfonts, minerr, err, pxlSize;
3231 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3233 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3234 programName, pattern);
3241 for (i=0; i<nfonts; i++) {
3244 if (*p != '-') continue;
3246 if (*p == NULLCHAR) break;
3247 if (*p++ == '-') j++;
3249 if (j < 7) continue;
3252 scalable = fonts[i];
3255 err = pxlSize - targetPxlSize;
3256 if (Abs(err) < Abs(minerr) ||
3257 (minerr > 0 && err < 0 && -err == minerr)) {
3263 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3264 /* If the error is too big and there is a scalable font,
3265 use the scalable font. */
3266 int headlen = scalableTail - scalable;
3267 p = (char *) XtMalloc(strlen(scalable) + 10);
3268 while (isdigit(*scalableTail)) scalableTail++;
3269 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3271 p = (char *) XtMalloc(strlen(best) + 2);
3272 safeStrCpy(p, best, strlen(best)+1 );
3274 if (appData.debugMode) {
3275 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3276 pattern, targetPxlSize, p);
3278 XFreeFontNames(fonts);
3284 { // [HGM] deletes GCs that are to be remade, to prevent resource leak;
3285 // must be called before all non-first callse to CreateGCs()
3286 XtReleaseGC(shellWidget, highlineGC);
3287 XtReleaseGC(shellWidget, lightSquareGC);
3288 XtReleaseGC(shellWidget, darkSquareGC);
3289 XtReleaseGC(shellWidget, lineGC);
3290 if (appData.monoMode) {
3291 if (DefaultDepth(xDisplay, xScreen) == 1) {
3292 XtReleaseGC(shellWidget, wbPieceGC);
3294 XtReleaseGC(shellWidget, bwPieceGC);
3297 XtReleaseGC(shellWidget, prelineGC);
3298 XtReleaseGC(shellWidget, jailSquareGC);
3299 XtReleaseGC(shellWidget, wdPieceGC);
3300 XtReleaseGC(shellWidget, wlPieceGC);
3301 XtReleaseGC(shellWidget, wjPieceGC);
3302 XtReleaseGC(shellWidget, bdPieceGC);
3303 XtReleaseGC(shellWidget, blPieceGC);
3304 XtReleaseGC(shellWidget, bjPieceGC);
3308 void CreateGCs(int redo)
3310 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3311 | GCBackground | GCFunction | GCPlaneMask;
3312 XGCValues gc_values;
3315 gc_values.plane_mask = AllPlanes;
3316 gc_values.line_width = lineGap;
3317 gc_values.line_style = LineSolid;
3318 gc_values.function = GXcopy;
3321 DeleteGCs(); // called a second time; clean up old GCs first
3322 } else { // [HGM] grid and font GCs created on first call only
3323 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3324 gc_values.background = XWhitePixel(xDisplay, xScreen);
3325 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3326 XSetFont(xDisplay, coordGC, coordFontID);
3328 // [HGM] make font for holdings counts (white on black)
3329 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3330 gc_values.background = XBlackPixel(xDisplay, xScreen);
3331 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3332 XSetFont(xDisplay, countGC, countFontID);
3334 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3335 gc_values.background = XBlackPixel(xDisplay, xScreen);
3336 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3338 if (appData.monoMode) {
3339 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3340 gc_values.background = XWhitePixel(xDisplay, xScreen);
3341 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3343 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3344 gc_values.background = XBlackPixel(xDisplay, xScreen);
3345 lightSquareGC = wbPieceGC
3346 = XtGetGC(shellWidget, value_mask, &gc_values);
3348 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3349 gc_values.background = XWhitePixel(xDisplay, xScreen);
3350 darkSquareGC = bwPieceGC
3351 = XtGetGC(shellWidget, value_mask, &gc_values);
3353 if (DefaultDepth(xDisplay, xScreen) == 1) {
3354 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3355 gc_values.function = GXcopyInverted;
3356 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3357 gc_values.function = GXcopy;
3358 if (XBlackPixel(xDisplay, xScreen) == 1) {
3359 bwPieceGC = darkSquareGC;
3360 wbPieceGC = copyInvertedGC;
3362 bwPieceGC = copyInvertedGC;
3363 wbPieceGC = lightSquareGC;
3367 gc_values.foreground = highlightSquareColor;
3368 gc_values.background = highlightSquareColor;
3369 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3371 gc_values.foreground = premoveHighlightColor;
3372 gc_values.background = premoveHighlightColor;
3373 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3375 gc_values.foreground = lightSquareColor;
3376 gc_values.background = darkSquareColor;
3377 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3379 gc_values.foreground = darkSquareColor;
3380 gc_values.background = lightSquareColor;
3381 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3383 gc_values.foreground = jailSquareColor;
3384 gc_values.background = jailSquareColor;
3385 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3387 gc_values.foreground = whitePieceColor;
3388 gc_values.background = darkSquareColor;
3389 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3391 gc_values.foreground = whitePieceColor;
3392 gc_values.background = lightSquareColor;
3393 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3395 gc_values.foreground = whitePieceColor;
3396 gc_values.background = jailSquareColor;
3397 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3399 gc_values.foreground = blackPieceColor;
3400 gc_values.background = darkSquareColor;
3401 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3403 gc_values.foreground = blackPieceColor;
3404 gc_values.background = lightSquareColor;
3405 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3407 gc_values.foreground = blackPieceColor;
3408 gc_values.background = jailSquareColor;
3409 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3413 void loadXIM(xim, xmask, filename, dest, mask)
3426 fp = fopen(filename, "rb");
3428 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3435 for (y=0; y<h; ++y) {
3436 for (x=0; x<h; ++x) {
3441 XPutPixel(xim, x, y, blackPieceColor);
3443 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3446 XPutPixel(xim, x, y, darkSquareColor);
3448 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3451 XPutPixel(xim, x, y, whitePieceColor);
3453 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3456 XPutPixel(xim, x, y, lightSquareColor);
3458 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3466 /* create Pixmap of piece */
3467 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3469 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3472 /* create Pixmap of clipmask
3473 Note: We assume the white/black pieces have the same
3474 outline, so we make only 6 masks. This is okay
3475 since the XPM clipmask routines do the same. */
3477 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3479 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3482 /* now create the 1-bit version */
3483 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3486 values.foreground = 1;
3487 values.background = 0;
3489 /* Don't use XtGetGC, not read only */
3490 maskGC = XCreateGC(xDisplay, *mask,
3491 GCForeground | GCBackground, &values);
3492 XCopyPlane(xDisplay, temp, *mask, maskGC,
3493 0, 0, squareSize, squareSize, 0, 0, 1);
3494 XFreePixmap(xDisplay, temp);
3499 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3501 void CreateXIMPieces()
3506 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3511 /* The XSynchronize calls were copied from CreatePieces.
3512 Not sure if needed, but can't hurt */
3513 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3516 /* temp needed by loadXIM() */
3517 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3518 0, 0, ss, ss, AllPlanes, XYPixmap);
3520 if (strlen(appData.pixmapDirectory) == 0) {
3524 if (appData.monoMode) {
3525 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3529 fprintf(stderr, _("\nLoading XIMs...\n"));
3531 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3532 fprintf(stderr, "%d", piece+1);
3533 for (kind=0; kind<4; kind++) {
3534 fprintf(stderr, ".");
3535 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3536 ExpandPathName(appData.pixmapDirectory),
3537 piece <= (int) WhiteKing ? "" : "w",
3538 pieceBitmapNames[piece],
3540 ximPieceBitmap[kind][piece] =
3541 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3542 0, 0, ss, ss, AllPlanes, XYPixmap);
3543 if (appData.debugMode)
3544 fprintf(stderr, _("(File:%s:) "), buf);
3545 loadXIM(ximPieceBitmap[kind][piece],
3547 &(xpmPieceBitmap2[kind][piece]),
3548 &(ximMaskPm2[piece]));
3549 if(piece <= (int)WhiteKing)
3550 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3552 fprintf(stderr," ");
3554 /* Load light and dark squares */
3555 /* If the LSQ and DSQ pieces don't exist, we will
3556 draw them with solid squares. */
3557 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3558 if (access(buf, 0) != 0) {
3562 fprintf(stderr, _("light square "));
3564 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3565 0, 0, ss, ss, AllPlanes, XYPixmap);
3566 if (appData.debugMode)
3567 fprintf(stderr, _("(File:%s:) "), buf);
3569 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3570 fprintf(stderr, _("dark square "));
3571 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3572 ExpandPathName(appData.pixmapDirectory), ss);
3573 if (appData.debugMode)
3574 fprintf(stderr, _("(File:%s:) "), buf);
3576 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3577 0, 0, ss, ss, AllPlanes, XYPixmap);
3578 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3579 xpmJailSquare = xpmLightSquare;
3581 fprintf(stderr, _("Done.\n"));
3583 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3586 static VariantClass oldVariant = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
3589 void CreateXPMBoard(char *s, int kind)
3593 if(s == NULL || *s == 0 || *s == '*') { useTexture &= ~(kind+1); return; }
3594 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3595 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3599 void FreeXPMPieces()
3600 { // [HGM] to prevent resoucre leak on calling CreaeXPMPieces() a second time,
3601 // thisroutine has to be called t free the old piece pixmaps
3603 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++)
3604 for (kind=0; kind<4; kind++) XFreePixmap(xDisplay, xpmPieceBitmap2[kind][piece]);
3606 XFreePixmap(xDisplay, xpmLightSquare);
3607 XFreePixmap(xDisplay, xpmDarkSquare);
3611 void CreateXPMPieces()
3615 u_int ss = squareSize;
3617 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3618 XpmColorSymbol symbols[4];
3619 static int redo = False;
3621 if(redo) FreeXPMPieces(); else redo = 1;
3623 /* The XSynchronize calls were copied from CreatePieces.
3624 Not sure if needed, but can't hurt */
3625 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3627 /* Setup translations so piece colors match square colors */
3628 symbols[0].name = "light_piece";
3629 symbols[0].value = appData.whitePieceColor;
3630 symbols[1].name = "dark_piece";
3631 symbols[1].value = appData.blackPieceColor;
3632 symbols[2].name = "light_square";
3633 symbols[2].value = appData.lightSquareColor;
3634 symbols[3].name = "dark_square";
3635 symbols[3].value = appData.darkSquareColor;
3637 attr.valuemask = XpmColorSymbols;
3638 attr.colorsymbols = symbols;
3639 attr.numsymbols = 4;
3641 if (appData.monoMode) {
3642 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3646 if (strlen(appData.pixmapDirectory) == 0) {
3647 XpmPieces* pieces = builtInXpms;
3650 while (pieces->size != squareSize && pieces->size) pieces++;
3651 if (!pieces->size) {
3652 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3655 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3656 for (kind=0; kind<4; kind++) {
3658 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3659 pieces->xpm[piece][kind],
3660 &(xpmPieceBitmap2[kind][piece]),
3661 NULL, &attr)) != 0) {
3662 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3666 if(piece <= (int) WhiteKing)
3667 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3671 xpmJailSquare = xpmLightSquare;
3675 fprintf(stderr, _("\nLoading XPMs...\n"));
3678 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3679 fprintf(stderr, "%d ", piece+1);
3680 for (kind=0; kind<4; kind++) {
3681 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3682 ExpandPathName(appData.pixmapDirectory),
3683 piece > (int) WhiteKing ? "w" : "",
3684 pieceBitmapNames[piece],
3686 if (appData.debugMode) {
3687 fprintf(stderr, _("(File:%s:) "), buf);
3689 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3690 &(xpmPieceBitmap2[kind][piece]),
3691 NULL, &attr)) != 0) {
3692 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3693 // [HGM] missing: read of unorthodox piece failed; substitute King.
3694 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3695 ExpandPathName(appData.pixmapDirectory),
3697 if (appData.debugMode) {
3698 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3700 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3701 &(xpmPieceBitmap2[kind][piece]),
3705 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3710 if(piece <= (int) WhiteKing)
3711 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3714 /* Load light and dark squares */
3715 /* If the LSQ and DSQ pieces don't exist, we will
3716 draw them with solid squares. */
3717 fprintf(stderr, _("light square "));
3718 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3719 if (access(buf, 0) != 0) {
3723 if (appData.debugMode)
3724 fprintf(stderr, _("(File:%s:) "), buf);
3726 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3727 &xpmLightSquare, NULL, &attr)) != 0) {
3728 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3731 fprintf(stderr, _("dark square "));
3732 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3733 ExpandPathName(appData.pixmapDirectory), ss);
3734 if (appData.debugMode) {
3735 fprintf(stderr, _("(File:%s:) "), buf);
3737 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3738 &xpmDarkSquare, NULL, &attr)) != 0) {
3739 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3743 xpmJailSquare = xpmLightSquare;
3744 fprintf(stderr, _("Done.\n"));
3746 oldVariant = -1; // kludge to force re-makig of animation masks
3747 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3750 #endif /* HAVE_LIBXPM */
3753 /* No built-in bitmaps */
3758 u_int ss = squareSize;
3760 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3763 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3764 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3765 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3766 pieceBitmapNames[piece],
3767 ss, kind == SOLID ? 's' : 'o');
3768 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3769 if(piece <= (int)WhiteKing)
3770 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3774 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3778 /* With built-in bitmaps */
3781 BuiltInBits* bib = builtInBits;
3784 u_int ss = squareSize;
3786 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3789 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3791 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3792 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3793 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3794 pieceBitmapNames[piece],
3795 ss, kind == SOLID ? 's' : 'o');
3796 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3797 bib->bits[kind][piece], ss, ss);
3798 if(piece <= (int)WhiteKing)
3799 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3803 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3808 void ReadBitmap(pm, name, bits, wreq, hreq)
3811 unsigned char bits[];
3817 char msg[MSG_SIZ], fullname[MSG_SIZ];
3819 if (*appData.bitmapDirectory != NULLCHAR) {
3820 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3821 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3822 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3823 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3824 &w, &h, pm, &x_hot, &y_hot);
3825 fprintf(stderr, "load %s\n", name);
3826 if (errcode != BitmapSuccess) {
3828 case BitmapOpenFailed:
3829 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3831 case BitmapFileInvalid:
3832 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3834 case BitmapNoMemory:
3835 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3839 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3843 fprintf(stderr, _("%s: %s...using built-in\n"),
3845 } else if (w != wreq || h != hreq) {
3847 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3848 programName, fullname, w, h, wreq, hreq);
3854 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3863 if (lineGap == 0) return;
3865 /* [HR] Split this into 2 loops for non-square boards. */
3867 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3868 gridSegments[i].x1 = 0;
3869 gridSegments[i].x2 =
3870 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3871 gridSegments[i].y1 = gridSegments[i].y2
3872 = lineGap / 2 + (i * (squareSize + lineGap));
3875 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3876 gridSegments[j + i].y1 = 0;
3877 gridSegments[j + i].y2 =
3878 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3879 gridSegments[j + i].x1 = gridSegments[j + i].x2
3880 = lineGap / 2 + (j * (squareSize + lineGap));
3884 static void MenuBarSelect(w, addr, index)
3889 XtActionProc proc = (XtActionProc) addr;
3891 (proc)(NULL, NULL, NULL, NULL);
3894 void CreateMenuBarPopup(parent, name, mb)
3904 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3907 XtSetArg(args[j], XtNleftMargin, 20); j++;
3908 XtSetArg(args[j], XtNrightMargin, 20); j++;
3910 while (mi->string != NULL) {
3911 if (strcmp(mi->string, "----") == 0) {
3912 entry = XtCreateManagedWidget(_(mi->string), smeLineObjectClass,
3915 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3916 entry = XtCreateManagedWidget(mi->ref, smeBSBObjectClass,
3918 XtAddCallback(entry, XtNcallback,
3919 (XtCallbackProc) MenuBarSelect,
3920 (caddr_t) mi->proc);
3926 Widget CreateMenuBar(mb)
3930 Widget anchor, menuBar;
3932 char menuName[MSG_SIZ];
3935 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3936 XtSetArg(args[j], XtNvSpace, 0); j++;
3937 XtSetArg(args[j], XtNborderWidth, 0); j++;
3938 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3939 formWidget, args, j);
3941 while (mb->name != NULL) {
3942 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3943 strncat(menuName, mb->ref, MSG_SIZ - strlen(menuName) - 1);
3945 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3948 shortName[0] = mb->name[0];
3949 shortName[1] = NULLCHAR;
3950 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3953 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3956 XtSetArg(args[j], XtNborderWidth, 0); j++;
3957 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3959 CreateMenuBarPopup(menuBar, menuName, mb);
3965 Widget CreateButtonBar(mi)
3969 Widget button, buttonBar;
3973 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3975 XtSetArg(args[j], XtNhSpace, 0); j++;
3977 XtSetArg(args[j], XtNborderWidth, 0); j++;
3978 XtSetArg(args[j], XtNvSpace, 0); j++;
3979 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3980 formWidget, args, j);
3982 while (mi->string != NULL) {
3985 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3986 XtSetArg(args[j], XtNborderWidth, 0); j++;
3988 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3989 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3990 buttonBar, args, j);
3991 XtAddCallback(button, XtNcallback,
3992 (XtCallbackProc) MenuBarSelect,
3993 (caddr_t) mi->proc);
4000 CreatePieceMenu(name, color)
4007 ChessSquare selection;
4009 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
4010 boardWidget, args, 0);
4012 for (i = 0; i < PIECE_MENU_SIZE; i++) {
4013 String item = pieceMenuStrings[color][i];
4015 if (strcmp(item, "----") == 0) {
4016 entry = XtCreateManagedWidget(item, smeLineObjectClass,
4019 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
4020 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
4022 selection = pieceMenuTranslation[color][i];
4023 XtAddCallback(entry, XtNcallback,
4024 (XtCallbackProc) PieceMenuSelect,
4025 (caddr_t) selection);
4026 if (selection == WhitePawn || selection == BlackPawn) {
4027 XtSetArg(args[0], XtNpopupOnEntry, entry);
4028 XtSetValues(menu, args, 1);
4041 ChessSquare selection;
4043 whitePieceMenu = CreatePieceMenu("menuW", 0);
4044 blackPieceMenu = CreatePieceMenu("menuB", 1);
4046 XtRegisterGrabAction(PieceMenuPopup, True,
4047 (unsigned)(ButtonPressMask|ButtonReleaseMask),
4048 GrabModeAsync, GrabModeAsync);
4050 XtSetArg(args[0], XtNlabel, _("Drop"));
4051 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
4052 boardWidget, args, 1);
4053 for (i = 0; i < DROP_MENU_SIZE; i++) {
4054 String item = dropMenuStrings[i];
4056 if (strcmp(item, "----") == 0) {
4057 entry = XtCreateManagedWidget(item, smeLineObjectClass,
4060 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
4061 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
4063 selection = dropMenuTranslation[i];
4064 XtAddCallback(entry, XtNcallback,
4065 (XtCallbackProc) DropMenuSelect,
4066 (caddr_t) selection);
4071 void SetupDropMenu()
4079 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
4080 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
4081 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
4082 dmEnables[i].piece);
4083 XtSetSensitive(entry, p != NULL || !appData.testLegality
4084 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
4085 && !appData.icsActive));
4087 while (p && *p++ == dmEnables[i].piece) count++;
4088 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
4090 XtSetArg(args[j], XtNlabel, label); j++;
4091 XtSetValues(entry, args, j);
4095 void PieceMenuPopup(w, event, params, num_params)
4099 Cardinal *num_params;
4101 String whichMenu; int menuNr = -2;
4102 shiftKey = strcmp(params[0], "menuW"); // used to indicate black
4103 if (event->type == ButtonRelease)
4104 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
4105 else if (event->type == ButtonPress)
4106 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
4108 case 0: whichMenu = params[0]; break;
4109 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
4111 case -1: if (errorUp) ErrorPopDown();
4114 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
4117 static void PieceMenuSelect(w, piece, junk)
4122 if (pmFromX < 0 || pmFromY < 0) return;
4123 EditPositionMenuEvent(piece, pmFromX, pmFromY);
4126 static void DropMenuSelect(w, piece, junk)
4131 if (pmFromX < 0 || pmFromY < 0) return;
4132 DropMenuEvent(piece, pmFromX, pmFromY);
4135 void WhiteClock(w, event, prms, nprms)
4144 void BlackClock(w, event, prms, nprms)
4155 * If the user selects on a border boundary, return -1; if off the board,
4156 * return -2. Otherwise map the event coordinate to the square.
4158 int EventToSquare(x, limit)
4166 if ((x % (squareSize + lineGap)) >= squareSize)
4168 x /= (squareSize + lineGap);
4174 static void do_flash_delay(msec)
4180 static void drawHighlight(file, rank, gc)
4186 if (lineGap == 0) return;
4189 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
4190 (squareSize + lineGap);
4191 y = lineGap/2 + rank * (squareSize + lineGap);
4193 x = lineGap/2 + file * (squareSize + lineGap);
4194 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
4195 (squareSize + lineGap);
4198 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
4199 squareSize+lineGap, squareSize+lineGap);
4202 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
4203 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4206 SetHighlights(fromX, fromY, toX, toY)
4207 int fromX, fromY, toX, toY;
4209 if (hi1X != fromX || hi1Y != fromY) {
4210 if (hi1X >= 0 && hi1Y >= 0) {
4211 drawHighlight(hi1X, hi1Y, lineGC);
4213 } // [HGM] first erase both, then draw new!
4214 if (hi2X != toX || hi2Y != toY) {
4215 if (hi2X >= 0 && hi2Y >= 0) {
4216 drawHighlight(hi2X, hi2Y, lineGC);
4219 if (hi1X != fromX || hi1Y != fromY) {
4220 if (fromX >= 0 && fromY >= 0) {
4221 drawHighlight(fromX, fromY, highlineGC);
4224 if (hi2X != toX || hi2Y != toY) {
4225 if (toX >= 0 && toY >= 0) {
4226 drawHighlight(toX, toY, highlineGC);
4238 SetHighlights(-1, -1, -1, -1);
4243 SetPremoveHighlights(fromX, fromY, toX, toY)
4244 int fromX, fromY, toX, toY;
4246 if (pm1X != fromX || pm1Y != fromY) {
4247 if (pm1X >= 0 && pm1Y >= 0) {
4248 drawHighlight(pm1X, pm1Y, lineGC);
4250 if (fromX >= 0 && fromY >= 0) {
4251 drawHighlight(fromX, fromY, prelineGC);
4254 if (pm2X != toX || pm2Y != toY) {
4255 if (pm2X >= 0 && pm2Y >= 0) {
4256 drawHighlight(pm2X, pm2Y, lineGC);
4258 if (toX >= 0 && toY >= 0) {
4259 drawHighlight(toX, toY, prelineGC);
4269 ClearPremoveHighlights()
4271 SetPremoveHighlights(-1, -1, -1, -1);
4274 static int CutOutSquare(x, y, x0, y0, kind)
4275 int x, y, *x0, *y0, kind;
4277 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
4278 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
4280 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
4281 if(textureW[kind] < W*squareSize)
4282 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
4284 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
4285 if(textureH[kind] < H*squareSize)
4286 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
4288 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
4292 static void BlankSquare(x, y, color, piece, dest, fac)
4293 int x, y, color, fac;
4296 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
4298 if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
4299 XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
4300 squareSize, squareSize, x*fac, y*fac);
4302 if (useImages && useImageSqs) {
4306 pm = xpmLightSquare;
4311 case 2: /* neutral */
4316 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4317 squareSize, squareSize, x*fac, y*fac);
4327 case 2: /* neutral */
4332 XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
4337 I split out the routines to draw a piece so that I could
4338 make a generic flash routine.
4340 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4342 int square_color, x, y;
4345 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4346 switch (square_color) {
4348 case 2: /* neutral */
4350 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4351 ? *pieceToOutline(piece)
4352 : *pieceToSolid(piece),
4353 dest, bwPieceGC, 0, 0,
4354 squareSize, squareSize, x, y);
4357 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4358 ? *pieceToSolid(piece)
4359 : *pieceToOutline(piece),
4360 dest, wbPieceGC, 0, 0,
4361 squareSize, squareSize, x, y);
4366 static void monoDrawPiece(piece, square_color, x, y, dest)
4368 int square_color, x, y;
4371 switch (square_color) {
4373 case 2: /* neutral */
4375 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4376 ? *pieceToOutline(piece)
4377 : *pieceToSolid(piece),
4378 dest, bwPieceGC, 0, 0,
4379 squareSize, squareSize, x, y, 1);
4382 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4383 ? *pieceToSolid(piece)
4384 : *pieceToOutline(piece),
4385 dest, wbPieceGC, 0, 0,
4386 squareSize, squareSize, x, y, 1);
4391 static void colorDrawPiece(piece, square_color, x, y, dest)
4393 int square_color, x, y;
4396 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4397 switch (square_color) {
4399 XCopyPlane(xDisplay, *pieceToSolid(piece),
4400 dest, (int) piece < (int) BlackPawn
4401 ? wlPieceGC : blPieceGC, 0, 0,
4402 squareSize, squareSize, x, y, 1);
4405 XCopyPlane(xDisplay, *pieceToSolid(piece),
4406 dest, (int) piece < (int) BlackPawn
4407 ? wdPieceGC : bdPieceGC, 0, 0,
4408 squareSize, squareSize, x, y, 1);
4410 case 2: /* neutral */
4412 XCopyPlane(xDisplay, *pieceToSolid(piece),
4413 dest, (int) piece < (int) BlackPawn
4414 ? wjPieceGC : bjPieceGC, 0, 0,
4415 squareSize, squareSize, x, y, 1);
4420 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4422 int square_color, x, y;
4425 int kind, p = piece;
4427 switch (square_color) {
4429 case 2: /* neutral */
4431 if ((int)piece < (int) BlackPawn) {
4439 if ((int)piece < (int) BlackPawn) {
4447 if(appData.upsideDown && flipView) { kind ^= 2; p += p < BlackPawn ? BlackPawn : -BlackPawn; }// swap white and black pieces
4448 if(useTexture & square_color+1) {
4449 BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background
4450 XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]);
4451 XSetClipOrigin(xDisplay, wlPieceGC, x, y);
4452 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y);
4453 XSetClipMask(xDisplay, wlPieceGC, None);
4454 XSetClipOrigin(xDisplay, wlPieceGC, 0, 0);
4456 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4457 dest, wlPieceGC, 0, 0,
4458 squareSize, squareSize, x, y);
4461 typedef void (*DrawFunc)();
4463 DrawFunc ChooseDrawFunc()
4465 if (appData.monoMode) {
4466 if (DefaultDepth(xDisplay, xScreen) == 1) {
4467 return monoDrawPiece_1bit;
4469 return monoDrawPiece;
4473 return colorDrawPieceImage;
4475 return colorDrawPiece;
4479 /* [HR] determine square color depending on chess variant. */
4480 static int SquareColor(row, column)
4485 if (gameInfo.variant == VariantXiangqi) {
4486 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4488 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4490 } else if (row <= 4) {
4496 square_color = ((column + row) % 2) == 1;
4499 /* [hgm] holdings: next line makes all holdings squares light */
4500 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4502 return square_color;
4505 void DrawSquare(row, column, piece, do_flash)
4506 int row, column, do_flash;
4509 int square_color, x, y, direction, font_ascent, font_descent;
4512 XCharStruct overall;
4516 /* Calculate delay in milliseconds (2-delays per complete flash) */
4517 flash_delay = 500 / appData.flashRate;
4520 x = lineGap + ((BOARD_WIDTH-1)-column) *
4521 (squareSize + lineGap);
4522 y = lineGap + row * (squareSize + lineGap);
4524 x = lineGap + column * (squareSize + lineGap);
4525 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4526 (squareSize + lineGap);
4529 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4531 square_color = SquareColor(row, column);
4533 if ( // [HGM] holdings: blank out area between board and holdings
4534 column == BOARD_LEFT-1 || column == BOARD_RGHT
4535 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4536 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4537 BlankSquare(x, y, 2, EmptySquare, xBoardWindow, 1);
4539 // [HGM] print piece counts next to holdings
4540 string[1] = NULLCHAR;
4541 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4542 string[0] = '0' + piece;
4543 XTextExtents(countFontStruct, string, 1, &direction,
4544 &font_ascent, &font_descent, &overall);
4545 if (appData.monoMode) {
4546 XDrawImageString(xDisplay, xBoardWindow, countGC,
4547 x + squareSize - overall.width - 2,
4548 y + font_ascent + 1, string, 1);
4550 XDrawString(xDisplay, xBoardWindow, countGC,
4551 x + squareSize - overall.width - 2,
4552 y + font_ascent + 1, string, 1);
4555 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4556 string[0] = '0' + piece;
4557 XTextExtents(countFontStruct, string, 1, &direction,
4558 &font_ascent, &font_descent, &overall);
4559 if (appData.monoMode) {
4560 XDrawImageString(xDisplay, xBoardWindow, countGC,
4561 x + 2, y + font_ascent + 1, string, 1);
4563 XDrawString(xDisplay, xBoardWindow, countGC,
4564 x + 2, y + font_ascent + 1, string, 1);
4568 if (piece == EmptySquare || appData.blindfold) {
4569 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4571 drawfunc = ChooseDrawFunc();
4573 if (do_flash && appData.flashCount > 0) {
4574 for (i=0; i<appData.flashCount; ++i) {
4575 drawfunc(piece, square_color, x, y, xBoardWindow);
4576 XSync(xDisplay, False);
4577 do_flash_delay(flash_delay);
4579 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4580 XSync(xDisplay, False);
4581 do_flash_delay(flash_delay);
4584 drawfunc(piece, square_color, x, y, xBoardWindow);
4588 string[1] = NULLCHAR;
4589 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4590 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4591 string[0] = 'a' + column - BOARD_LEFT;
4592 XTextExtents(coordFontStruct, string, 1, &direction,
4593 &font_ascent, &font_descent, &overall);
4594 if (appData.monoMode) {
4595 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4596 x + squareSize - overall.width - 2,
4597 y + squareSize - font_descent - 1, string, 1);
4599 XDrawString(xDisplay, xBoardWindow, coordGC,
4600 x + squareSize - overall.width - 2,
4601 y + squareSize - font_descent - 1, string, 1);
4604 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4605 string[0] = ONE + row;
4606 XTextExtents(coordFontStruct, string, 1, &direction,
4607 &font_ascent, &font_descent, &overall);
4608 if (appData.monoMode) {
4609 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4610 x + 2, y + font_ascent + 1, string, 1);
4612 XDrawString(xDisplay, xBoardWindow, coordGC,
4613 x + 2, y + font_ascent + 1, string, 1);
4616 if(!partnerUp && marker[row][column]) {
4617 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4618 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4623 /* Why is this needed on some versions of X? */
4624 void EventProc(widget, unused, event)
4629 if (!XtIsRealized(widget))
4632 switch (event->type) {
4634 if (event->xexpose.count > 0) return; /* no clipping is done */
4635 XDrawPosition(widget, True, NULL);
4636 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4637 flipView = !flipView; partnerUp = !partnerUp;
4638 XDrawPosition(widget, True, NULL);
4639 flipView = !flipView; partnerUp = !partnerUp;
4643 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
4650 void DrawPosition(fullRedraw, board)
4651 /*Boolean*/int fullRedraw;
4654 XDrawPosition(boardWidget, fullRedraw, board);
4657 /* Returns 1 if there are "too many" differences between b1 and b2
4658 (i.e. more than 1 move was made) */
4659 static int too_many_diffs(b1, b2)
4665 for (i=0; i<BOARD_HEIGHT; ++i) {
4666 for (j=0; j<BOARD_WIDTH; ++j) {
4667 if (b1[i][j] != b2[i][j]) {
4668 if (++c > 4) /* Castling causes 4 diffs */
4676 /* Matrix describing castling maneuvers */
4677 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4678 static int castling_matrix[4][5] = {
4679 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4680 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4681 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4682 { 7, 7, 4, 5, 6 } /* 0-0, black */
4685 /* Checks whether castling occurred. If it did, *rrow and *rcol
4686 are set to the destination (row,col) of the rook that moved.
4688 Returns 1 if castling occurred, 0 if not.
4690 Note: Only handles a max of 1 castling move, so be sure
4691 to call too_many_diffs() first.
4693 static int check_castle_draw(newb, oldb, rrow, rcol)
4700 /* For each type of castling... */
4701 for (i=0; i<4; ++i) {
4702 r = castling_matrix[i];
4704 /* Check the 4 squares involved in the castling move */
4706 for (j=1; j<=4; ++j) {
4707 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4714 /* All 4 changed, so it must be a castling move */
4723 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4724 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4726 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4729 void DrawSeekBackground( int left, int top, int right, int bottom )
4731 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4734 void DrawSeekText(char *buf, int x, int y)
4736 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4739 void DrawSeekDot(int x, int y, int colorNr)
4741 int square = colorNr & 0x80;
4744 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4746 XFillRectangle(xDisplay, xBoardWindow, color,
4747 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4749 XFillArc(xDisplay, xBoardWindow, color,
4750 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4753 static int damage[2][BOARD_RANKS][BOARD_FILES];
4756 * event handler for redrawing the board
4758 void XDrawPosition(w, repaint, board)
4760 /*Boolean*/int repaint;
4764 static int lastFlipView = 0;
4765 static int lastBoardValid[2] = {0, 0};
4766 static Board lastBoard[2];
4769 int nr = twoBoards*partnerUp;
4771 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4773 if (board == NULL) {
4774 if (!lastBoardValid[nr]) return;
4775 board = lastBoard[nr];
4777 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4778 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4779 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Flip View"),
4784 * It would be simpler to clear the window with XClearWindow()
4785 * but this causes a very distracting flicker.
4788 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4790 if ( lineGap && IsDrawArrowEnabled())
4791 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4792 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4794 /* If too much changes (begin observing new game, etc.), don't
4796 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4798 /* Special check for castling so we don't flash both the king
4799 and the rook (just flash the king). */
4801 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4802 /* Draw rook with NO flashing. King will be drawn flashing later */
4803 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4804 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4808 /* First pass -- Draw (newly) empty squares and repair damage.
4809 This prevents you from having a piece show up twice while it
4810 is flashing on its new square */
4811 for (i = 0; i < BOARD_HEIGHT; i++)
4812 for (j = 0; j < BOARD_WIDTH; j++)
4813 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4814 || damage[nr][i][j]) {
4815 DrawSquare(i, j, board[i][j], 0);
4816 damage[nr][i][j] = False;
4819 /* Second pass -- Draw piece(s) in new position and flash them */
4820 for (i = 0; i < BOARD_HEIGHT; i++)
4821 for (j = 0; j < BOARD_WIDTH; j++)
4822 if (board[i][j] != lastBoard[nr][i][j]) {
4823 DrawSquare(i, j, board[i][j], do_flash);
4827 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4828 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4829 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4831 for (i = 0; i < BOARD_HEIGHT; i++)
4832 for (j = 0; j < BOARD_WIDTH; j++) {
4833 DrawSquare(i, j, board[i][j], 0);
4834 damage[nr][i][j] = False;
4838 CopyBoard(lastBoard[nr], board);
4839 lastBoardValid[nr] = 1;
4840 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4841 lastFlipView = flipView;
4843 /* Draw highlights */
4844 if (pm1X >= 0 && pm1Y >= 0) {
4845 drawHighlight(pm1X, pm1Y, prelineGC);
4847 if (pm2X >= 0 && pm2Y >= 0) {
4848 drawHighlight(pm2X, pm2Y, prelineGC);
4850 if (hi1X >= 0 && hi1Y >= 0) {
4851 drawHighlight(hi1X, hi1Y, highlineGC);
4853 if (hi2X >= 0 && hi2Y >= 0) {
4854 drawHighlight(hi2X, hi2Y, highlineGC);
4856 DrawArrowHighlight(hi1X, hi1Y, hi2X, hi2Y);
4858 /* If piece being dragged around board, must redraw that too */
4861 XSync(xDisplay, False);
4866 * event handler for redrawing the board
4868 void DrawPositionProc(w, event, prms, nprms)
4874 XDrawPosition(w, True, NULL);
4879 * event handler for parsing user moves
4881 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4882 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4883 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4884 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4885 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4886 // and at the end FinishMove() to perform the move after optional promotion popups.
4887 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4888 void HandleUserMove(w, event, prms, nprms)
4894 if (w != boardWidget || errorExitStatus != -1) return;
4895 if(nprms) shiftKey = !strcmp(prms[0], "1");
4898 if (event->type == ButtonPress) {
4899 XtPopdown(promotionShell);
4900 XtDestroyWidget(promotionShell);
4901 promotionUp = False;
4909 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4910 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4911 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4914 void AnimateUserMove (Widget w, XEvent * event,
4915 String * params, Cardinal * nParams)
4917 if(!PromoScroll(event->xmotion.x, event->xmotion.y))
4918 DragPieceMove(event->xmotion.x, event->xmotion.y);
4921 void HandlePV (Widget w, XEvent * event,
4922 String * params, Cardinal * nParams)
4923 { // [HGM] pv: walk PV
4924 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4927 static int savedIndex; /* gross that this is global */
4929 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
4932 XawTextPosition index, dummy;
4935 XawTextGetSelectionPos(w, &index, &dummy);
4936 XtSetArg(arg, XtNstring, &val);
4937 XtGetValues(w, &arg, 1);
4938 ReplaceComment(savedIndex, val);
4939 if(savedIndex != currentMove) ToNrEvent(savedIndex);
4940 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
4943 void EditCommentPopUp(index, title, text)
4948 if (text == NULL) text = "";
4949 NewCommentPopup(title, text, index);
4952 void ICSInputBoxPopUp()
4957 extern Option boxOptions[];
4959 void ICSInputSendText()
4966 edit = boxOptions[0].handle;
4968 XtSetArg(args[j], XtNstring, &val); j++;
4969 XtGetValues(edit, args, j);
4971 SendMultiLineToICS(val);
4972 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4973 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4976 void ICSInputBoxPopDown()
4981 void CommentPopUp(title, text)
4984 savedIndex = currentMove; // [HGM] vari
4985 NewCommentPopup(title, text, currentMove);
4988 void CommentPopDown()
4993 void FileNamePopUp(label, def, filter, proc, openMode)
5000 fileProc = proc; /* I can't see a way not */
5001 fileOpenMode = openMode; /* to use globals here */
5002 { // [HGM] use file-selector dialog stolen from Ghostview
5004 int index; // this is not supported yet
5006 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5007 (def[0] ? def : NULL), filter, openMode, NULL, &name))
5008 (void) (*fileProc)(f, index=0, name);
5012 void FileNamePopDown()
5014 if (!filenameUp) return;
5015 XtPopdown(fileNameShell);
5016 XtDestroyWidget(fileNameShell);
5021 void FileNameCallback(w, client_data, call_data)
5023 XtPointer client_data, call_data;
5028 XtSetArg(args[0], XtNlabel, &name);
5029 XtGetValues(w, args, 1);
5031 if (strcmp(name, _("cancel")) == 0) {
5036 FileNameAction(w, NULL, NULL, NULL);
5039 void FileNameAction(w, event, prms, nprms)
5051 name = XawDialogGetValueString(w = XtParent(w));
5053 if ((name != NULL) && (*name != NULLCHAR)) {
5054 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
5055 XtPopdown(w = XtParent(XtParent(w)));
5059 p = strrchr(buf, ' ');
5066 fullname = ExpandPathName(buf);
5068 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5071 f = fopen(fullname, fileOpenMode);
5073 DisplayError(_("Failed to open file"), errno);
5075 (void) (*fileProc)(f, index, buf);
5082 XtPopdown(w = XtParent(XtParent(w)));
5088 void PromotionPopUp()
5091 Widget dialog, layout;
5093 Dimension bw_width, pw_width;
5097 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5098 XtGetValues(boardWidget, args, j);
5101 XtSetArg(args[j], XtNresizable, True); j++;
5102 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5104 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5105 shellWidget, args, j);
5107 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5108 layoutArgs, XtNumber(layoutArgs));
5111 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5112 XtSetArg(args[j], XtNborderWidth, 0); j++;
5113 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5116 if(gameInfo.variant != VariantShogi) {
5117 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) {
5118 XawDialogAddButton(dialog, _("Warlord"), PromotionCallback,
5119 (XtPointer) dialog);
5120 XawDialogAddButton(dialog, _("General"), PromotionCallback,
5121 (XtPointer) dialog);
5122 XawDialogAddButton(dialog, _("Lieutenant"), PromotionCallback,
5123 (XtPointer) dialog);
5124 XawDialogAddButton(dialog, _("Captain"), PromotionCallback,
5125 (XtPointer) dialog);
5127 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5128 (XtPointer) dialog);
5129 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5130 (XtPointer) dialog);
5131 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5132 (XtPointer) dialog);
5133 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5134 (XtPointer) dialog);
5136 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5137 gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
5138 gameInfo.variant == VariantGiveaway) {
5139 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5140 (XtPointer) dialog);
5142 if(gameInfo.variant == VariantCapablanca ||
5143 gameInfo.variant == VariantGothic ||
5144 gameInfo.variant == VariantCapaRandom) {
5145 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5146 (XtPointer) dialog);
5147 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5148 (XtPointer) dialog);
5150 } else // [HGM] shogi
5152 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5153 (XtPointer) dialog);
5154 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5155 (XtPointer) dialog);
5157 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5158 (XtPointer) dialog);
5160 XtRealizeWidget(promotionShell);
5161 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5164 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5165 XtGetValues(promotionShell, args, j);
5167 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5168 lineGap + squareSize/3 +
5169 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5170 0 : 6*(squareSize + lineGap)), &x, &y);
5173 XtSetArg(args[j], XtNx, x); j++;
5174 XtSetArg(args[j], XtNy, y); j++;
5175 XtSetValues(promotionShell, args, j);
5177 XtPopup(promotionShell, XtGrabNone);
5182 void PromotionPopDown()
5184 if (!promotionUp) return;
5185 XtPopdown(promotionShell);
5186 XtDestroyWidget(promotionShell);
5187 promotionUp = False;
5190 void PromotionCallback(w, client_data, call_data)
5192 XtPointer client_data, call_data;
5198 XtSetArg(args[0], XtNlabel, &name);
5199 XtGetValues(w, args, 1);
5203 if (fromX == -1) return;
5205 if (strcmp(name, _("cancel")) == 0) {
5209 } else if (strcmp(name, _("Knight")) == 0) {
5211 } else if (strcmp(name, _("Promote")) == 0) {
5213 } else if (strcmp(name, _("Defer")) == 0) {
5216 promoChar = ToLower(name[0]);
5219 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5221 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5222 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5227 void ErrorCallback(w, client_data, call_data)
5229 XtPointer client_data, call_data;
5232 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5234 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5240 if (!errorUp) return;
5242 XtPopdown(errorShell);
5243 XtDestroyWidget(errorShell);
5244 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5247 void ErrorPopUp(title, label, modal)
5248 char *title, *label;
5252 Widget dialog, layout;
5256 Dimension bw_width, pw_width;
5257 Dimension pw_height;
5261 XtSetArg(args[i], XtNresizable, True); i++;
5262 XtSetArg(args[i], XtNtitle, title); i++;
5264 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5265 shellWidget, args, i);
5267 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5268 layoutArgs, XtNumber(layoutArgs));
5271 XtSetArg(args[i], XtNlabel, label); i++;
5272 XtSetArg(args[i], XtNborderWidth, 0); i++;
5273 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5276 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5278 XtRealizeWidget(errorShell);
5279 CatchDeleteWindow(errorShell, "ErrorPopDown");
5282 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5283 XtGetValues(boardWidget, args, i);
5285 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5286 XtSetArg(args[i], XtNheight, &pw_height); i++;
5287 XtGetValues(errorShell, args, i);
5290 /* This code seems to tickle an X bug if it is executed too soon
5291 after xboard starts up. The coordinates get transformed as if
5292 the main window was positioned at (0, 0).
5294 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5295 0 - pw_height + squareSize / 3, &x, &y);
5297 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5298 RootWindowOfScreen(XtScreen(boardWidget)),
5299 (bw_width - pw_width) / 2,
5300 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5304 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5307 XtSetArg(args[i], XtNx, x); i++;
5308 XtSetArg(args[i], XtNy, y); i++;
5309 XtSetValues(errorShell, args, i);
5312 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5315 /* Disable all user input other than deleting the window */
5316 static int frozen = 0;
5320 /* Grab by a widget that doesn't accept input */
5321 XtAddGrab(messageWidget, TRUE, FALSE);
5325 /* Undo a FreezeUI */
5328 if (!frozen) return;
5329 XtRemoveGrab(messageWidget);
5333 char *ModeToWidgetName(mode)
5337 case BeginningOfGame:
5338 if (appData.icsActive)
5339 return "menuMode.ICS Client";
5340 else if (appData.noChessProgram ||
5341 *appData.cmailGameName != NULLCHAR)
5342 return "menuMode.Edit Game";
5344 return "menuMode.Machine Black";
5345 case MachinePlaysBlack:
5346 return "menuMode.Machine Black";
5347 case MachinePlaysWhite:
5348 return "menuMode.Machine White";
5350 return "menuMode.Analysis Mode";
5352 return "menuMode.Analyze File";
5353 case TwoMachinesPlay:
5354 return "menuMode.Two Machines";
5356 return "menuMode.Edit Game";
5357 case PlayFromGameFile:
5358 return "menuFile.Load Game";
5360 return "menuMode.Edit Position";
5362 return "menuMode.Training";
5363 case IcsPlayingWhite:
5364 case IcsPlayingBlack:
5368 return "menuMode.ICS Client";
5375 void ModeHighlight()
5378 static int oldPausing = FALSE;
5379 static GameMode oldmode = (GameMode) -1;
5382 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5384 if (pausing != oldPausing) {
5385 oldPausing = pausing;
5387 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5389 XtSetArg(args[0], XtNleftBitmap, None);
5391 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5394 if (appData.showButtonBar) {
5395 /* Always toggle, don't set. Previous code messes up when
5396 invoked while the button is pressed, as releasing it
5397 toggles the state again. */
5400 XtSetArg(args[0], XtNbackground, &oldbg);
5401 XtSetArg(args[1], XtNforeground, &oldfg);
5402 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5404 XtSetArg(args[0], XtNbackground, oldfg);
5405 XtSetArg(args[1], XtNforeground, oldbg);
5407 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5411 wname = ModeToWidgetName(oldmode);
5412 if (wname != NULL) {
5413 XtSetArg(args[0], XtNleftBitmap, None);
5414 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5416 wname = ModeToWidgetName(gameMode);
5417 if (wname != NULL) {
5418 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5419 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5422 XtSetArg(args[0], XtNleftBitmap, matchMode && matchGame < appData.matchGames ? xMarkPixmap : None);
5423 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Machine Match"), args, 1);
5425 /* Maybe all the enables should be handled here, not just this one */
5426 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5427 gameMode == Training || gameMode == PlayFromGameFile);
5432 * Button/menu procedures
5434 void ResetProc(w, event, prms, nprms)
5443 int LoadGamePopUp(f, gameNumber, title)
5448 cmailMsgLoaded = FALSE;
5449 if (gameNumber == 0) {
5450 int error = GameListBuild(f);
5452 DisplayError(_("Cannot build game list"), error);
5453 } else if (!ListEmpty(&gameList) &&
5454 ((ListGame *) gameList.tailPred)->number > 1) {
5455 GameListPopUp(f, title);
5461 return LoadGame(f, gameNumber, title, FALSE);
5464 void LoadGameProc(w, event, prms, nprms)
5470 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5473 FileNamePopUp(_("Load game file name?"), "", ".pgn .game", LoadGamePopUp, "rb");
5476 void LoadNextGameProc(w, event, prms, nprms)
5485 void LoadPrevGameProc(w, event, prms, nprms)
5494 void ReloadGameProc(w, event, prms, nprms)
5503 void LoadNextPositionProc(w, event, prms, nprms)
5512 void LoadPrevPositionProc(w, event, prms, nprms)
5521 void ReloadPositionProc(w, event, prms, nprms)
5530 void LoadPositionProc(w, event, prms, nprms)
5536 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5539 FileNamePopUp(_("Load position file name?"), "", ".fen .epd .pos", LoadPosition, "rb");
5542 void SaveGameProc(w, event, prms, nprms)
5548 FileNamePopUp(_("Save game file name?"),
5549 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5550 appData.oldSaveStyle ? ".game" : ".pgn",
5554 void SavePositionProc(w, event, prms, nprms)
5560 FileNamePopUp(_("Save position file name?"),
5561 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5562 appData.oldSaveStyle ? ".pos" : ".fen",
5566 void ReloadCmailMsgProc(w, event, prms, nprms)
5572 ReloadCmailMsgEvent(FALSE);
5575 void MailMoveProc(w, event, prms, nprms)
5584 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5585 char *selected_fen_position=NULL;
5588 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5589 Atom *type_return, XtPointer *value_return,
5590 unsigned long *length_return, int *format_return)
5592 char *selection_tmp;
5594 if (!selected_fen_position) return False; /* should never happen */
5595 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5596 /* note: since no XtSelectionDoneProc was registered, Xt will
5597 * automatically call XtFree on the value returned. So have to
5598 * make a copy of it allocated with XtMalloc */
5599 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5600 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
5602 *value_return=selection_tmp;
5603 *length_return=strlen(selection_tmp);
5604 *type_return=*target;
5605 *format_return = 8; /* bits per byte */
5607 } else if (*target == XA_TARGETS(xDisplay)) {
5608 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5609 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5610 targets_tmp[1] = XA_STRING;
5611 *value_return = targets_tmp;
5612 *type_return = XA_ATOM;
5614 *format_return = 8 * sizeof(Atom);
5615 if (*format_return > 32) {
5616 *length_return *= *format_return / 32;
5617 *format_return = 32;
5625 /* note: when called from menu all parameters are NULL, so no clue what the
5626 * Widget which was clicked on was, or what the click event was
5628 void CopyPositionProc(w, event, prms, nprms)
5635 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5636 * have a notion of a position that is selected but not copied.
5637 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5639 if(gameMode == EditPosition) EditPositionDone(TRUE);
5640 if (selected_fen_position) free(selected_fen_position);
5641 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5642 if (!selected_fen_position) return;
5643 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5645 SendPositionSelection,
5646 NULL/* lose_ownership_proc */ ,
5647 NULL/* transfer_done_proc */);
5648 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5650 SendPositionSelection,
5651 NULL/* lose_ownership_proc */ ,
5652 NULL/* transfer_done_proc */);
5655 /* function called when the data to Paste is ready */
5657 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5658 Atom *type, XtPointer value, unsigned long *len, int *format)
5661 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5662 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5663 EditPositionPasteFEN(fenstr);
5667 /* called when Paste Position button is pressed,
5668 * all parameters will be NULL */
5669 void PastePositionProc(w, event, prms, nprms)
5675 XtGetSelectionValue(menuBarWidget,
5676 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5677 /* (XtSelectionCallbackProc) */ PastePositionCB,
5678 NULL, /* client_data passed to PastePositionCB */
5680 /* better to use the time field from the event that triggered the
5681 * call to this function, but that isn't trivial to get
5689 SendGameSelection(Widget w, Atom *selection, Atom *target,
5690 Atom *type_return, XtPointer *value_return,
5691 unsigned long *length_return, int *format_return)
5693 char *selection_tmp;
5695 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5696 FILE* f = fopen(gameCopyFilename, "r");
5699 if (f == NULL) return False;
5703 selection_tmp = XtMalloc(len + 1);
5704 count = fread(selection_tmp, 1, len, f);
5707 XtFree(selection_tmp);
5710 selection_tmp[len] = NULLCHAR;
5711 *value_return = selection_tmp;
5712 *length_return = len;
5713 *type_return = *target;
5714 *format_return = 8; /* bits per byte */
5716 } else if (*target == XA_TARGETS(xDisplay)) {
5717 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5718 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5719 targets_tmp[1] = XA_STRING;
5720 *value_return = targets_tmp;
5721 *type_return = XA_ATOM;
5723 *format_return = 8 * sizeof(Atom);
5724 if (*format_return > 32) {
5725 *length_return *= *format_return / 32;
5726 *format_return = 32;
5734 void CopySomething()
5739 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5740 * have a notion of a game that is selected but not copied.
5741 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5743 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5746 NULL/* lose_ownership_proc */ ,
5747 NULL/* transfer_done_proc */);
5748 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5751 NULL/* lose_ownership_proc */ ,
5752 NULL/* transfer_done_proc */);
5755 /* note: when called from menu all parameters are NULL, so no clue what the
5756 * Widget which was clicked on was, or what the click event was
5758 void CopyGameProc(w, event, prms, nprms)
5766 ret = SaveGameToFile(gameCopyFilename, FALSE);
5772 void CopyGameListProc(w, event, prms, nprms)
5778 if(!SaveGameListAsText(fopen(gameCopyFilename, "w"))) return;
5782 /* function called when the data to Paste is ready */
5784 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5785 Atom *type, XtPointer value, unsigned long *len, int *format)
5788 if (value == NULL || *len == 0) {
5789 return; /* nothing had been selected to copy */
5791 f = fopen(gamePasteFilename, "w");
5793 DisplayError(_("Can't open temp file"), errno);
5796 fwrite(value, 1, *len, f);
5799 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5802 /* called when Paste Game button is pressed,
5803 * all parameters will be NULL */
5804 void PasteGameProc(w, event, prms, nprms)
5810 XtGetSelectionValue(menuBarWidget,
5811 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5812 /* (XtSelectionCallbackProc) */ PasteGameCB,
5813 NULL, /* client_data passed to PasteGameCB */
5815 /* better to use the time field from the event that triggered the
5816 * call to this function, but that isn't trivial to get
5826 SaveGameProc(NULL, NULL, NULL, NULL);
5830 void QuitProc(w, event, prms, nprms)
5839 void PauseProc(w, event, prms, nprms)
5849 void MachineBlackProc(w, event, prms, nprms)
5855 MachineBlackEvent();
5858 void MachineWhiteProc(w, event, prms, nprms)
5864 MachineWhiteEvent();
5867 void AnalyzeModeProc(w, event, prms, nprms)
5875 if (!first.analysisSupport) {
5876 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5877 DisplayError(buf, 0);
5880 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5881 if (appData.icsActive) {
5882 if (gameMode != IcsObserving) {
5883 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
5884 DisplayError(buf, 0);
5886 if (appData.icsEngineAnalyze) {
5887 if (appData.debugMode)
5888 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5894 /* if enable, use want disable icsEngineAnalyze */
5895 if (appData.icsEngineAnalyze) {
5900 appData.icsEngineAnalyze = TRUE;
5901 if (appData.debugMode)
5902 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5904 #ifndef OPTIONSDIALOG
5905 if (!appData.showThinking)
5906 ShowThinkingProc(w,event,prms,nprms);
5912 void AnalyzeFileProc(w, event, prms, nprms)
5918 if (!first.analysisSupport) {
5920 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5921 DisplayError(buf, 0);
5925 #ifndef OPTIONSDIALOG
5926 if (!appData.showThinking)
5927 ShowThinkingProc(w,event,prms,nprms);
5930 FileNamePopUp(_("File to analyze"), "", ".pgn .game", LoadGamePopUp, "rb");
5931 AnalysisPeriodicEvent(1);
5934 void TwoMachinesProc(w, event, prms, nprms)
5943 void MatchProc(w, event, prms, nprms)
5952 void IcsClientProc(w, event, prms, nprms)
5961 void EditGameProc(w, event, prms, nprms)
5970 void EditPositionProc(w, event, prms, nprms)
5976 EditPositionEvent();
5979 void TrainingProc(w, event, prms, nprms)
5988 void EditCommentProc(w, event, prms, nprms)
5996 if (PopDown(1)) { // popdown succesful
5998 XtSetArg(args[j], XtNleftBitmap, None); j++;
5999 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"), args, j);
6000 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"), args, j);
6001 } else // was not up
6005 void IcsInputBoxProc(w, event, prms, nprms)
6011 if (!PopDown(4)) ICSInputBoxPopUp();
6014 void AcceptProc(w, event, prms, nprms)
6023 void DeclineProc(w, event, prms, nprms)
6032 void RematchProc(w, event, prms, nprms)
6041 void CallFlagProc(w, event, prms, nprms)
6050 void DrawProc(w, event, prms, nprms)
6059 void AbortProc(w, event, prms, nprms)
6068 void AdjournProc(w, event, prms, nprms)
6077 void ResignProc(w, event, prms, nprms)
6086 void AdjuWhiteProc(w, event, prms, nprms)
6092 UserAdjudicationEvent(+1);
6095 void AdjuBlackProc(w, event, prms, nprms)
6101 UserAdjudicationEvent(-1);
6104 void AdjuDrawProc(w, event, prms, nprms)
6110 UserAdjudicationEvent(0);
6113 void EnterKeyProc(w, event, prms, nprms)
6119 if (shellUp[4] == True)
6123 void UpKeyProc(w, event, prms, nprms)
6128 { // [HGM] input: let up-arrow recall previous line from history
6135 if (!shellUp[4]) return;
6136 edit = boxOptions[0].handle;
6138 XtSetArg(args[j], XtNstring, &val); j++;
6139 XtGetValues(edit, args, j);
6140 val = PrevInHistory(val);
6141 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6142 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6144 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6145 XawTextReplace(edit, 0, 0, &t);
6146 XawTextSetInsertionPoint(edit, 9999);
6150 void DownKeyProc(w, event, prms, nprms)
6155 { // [HGM] input: let down-arrow recall next line from history
6160 if (!shellUp[4]) return;
6161 edit = boxOptions[0].handle;
6162 val = NextInHistory();
6163 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6164 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6166 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6167 XawTextReplace(edit, 0, 0, &t);
6168 XawTextSetInsertionPoint(edit, 9999);
6172 void StopObservingProc(w, event, prms, nprms)
6178 StopObservingEvent();
6181 void StopExaminingProc(w, event, prms, nprms)
6187 StopExaminingEvent();
6190 void UploadProc(w, event, prms, nprms)
6200 void ForwardProc(w, event, prms, nprms)
6210 void BackwardProc(w, event, prms, nprms)
6219 void ToStartProc(w, event, prms, nprms)
6228 void ToEndProc(w, event, prms, nprms)
6237 void RevertProc(w, event, prms, nprms)
6246 void AnnotateProc(w, event, prms, nprms)
6255 void TruncateGameProc(w, event, prms, nprms)
6261 TruncateGameEvent();
6263 void RetractMoveProc(w, event, prms, nprms)
6272 void MoveNowProc(w, event, prms, nprms)
6281 void FlipViewProc(w, event, prms, nprms)
6287 flipView = !flipView;
6288 DrawPosition(True, NULL);
6291 void PonderNextMoveProc(w, event, prms, nprms)
6299 PonderNextMoveEvent(!appData.ponderNextMove);
6300 #ifndef OPTIONSDIALOG
6301 if (appData.ponderNextMove) {
6302 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6304 XtSetArg(args[0], XtNleftBitmap, None);
6306 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6311 #ifndef OPTIONSDIALOG
6312 void AlwaysQueenProc(w, event, prms, nprms)
6320 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6322 if (appData.alwaysPromoteToQueen) {
6323 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6325 XtSetArg(args[0], XtNleftBitmap, None);
6327 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6331 void AnimateDraggingProc(w, event, prms, nprms)
6339 appData.animateDragging = !appData.animateDragging;
6341 if (appData.animateDragging) {
6342 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6345 XtSetArg(args[0], XtNleftBitmap, None);
6347 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6351 void AnimateMovingProc(w, event, prms, nprms)
6359 appData.animate = !appData.animate;
6361 if (appData.animate) {
6362 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6365 XtSetArg(args[0], XtNleftBitmap, None);
6367 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6371 void AutoflagProc(w, event, prms, nprms)
6379 appData.autoCallFlag = !appData.autoCallFlag;
6381 if (appData.autoCallFlag) {
6382 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6384 XtSetArg(args[0], XtNleftBitmap, None);
6386 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6390 void AutoflipProc(w, event, prms, nprms)
6398 appData.autoFlipView = !appData.autoFlipView;
6400 if (appData.autoFlipView) {
6401 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6403 XtSetArg(args[0], XtNleftBitmap, None);
6405 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6409 void BlindfoldProc(w, event, prms, nprms)
6417 appData.blindfold = !appData.blindfold;
6419 if (appData.blindfold) {
6420 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6422 XtSetArg(args[0], XtNleftBitmap, None);
6424 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6427 DrawPosition(True, NULL);
6430 void TestLegalityProc(w, event, prms, nprms)
6438 appData.testLegality = !appData.testLegality;
6440 if (appData.testLegality) {
6441 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6443 XtSetArg(args[0], XtNleftBitmap, None);
6445 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6450 void FlashMovesProc(w, event, prms, nprms)
6458 if (appData.flashCount == 0) {
6459 appData.flashCount = 3;
6461 appData.flashCount = -appData.flashCount;
6464 if (appData.flashCount > 0) {
6465 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6467 XtSetArg(args[0], XtNleftBitmap, None);
6469 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6474 void HighlightDraggingProc(w, event, prms, nprms)
6482 appData.highlightDragging = !appData.highlightDragging;
6484 if (appData.highlightDragging) {
6485 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6487 XtSetArg(args[0], XtNleftBitmap, None);
6489 XtSetValues(XtNameToWidget(menuBarWidget,
6490 "menuOptions.Highlight Dragging"), args, 1);
6494 void HighlightLastMoveProc(w, event, prms, nprms)
6502 appData.highlightLastMove = !appData.highlightLastMove;
6504 if (appData.highlightLastMove) {
6505 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6507 XtSetArg(args[0], XtNleftBitmap, None);
6509 XtSetValues(XtNameToWidget(menuBarWidget,
6510 "menuOptions.Highlight Last Move"), args, 1);
6513 void HighlightArrowProc(w, event, prms, nprms)
6521 appData.highlightMoveWithArrow = !appData.highlightMoveWithArrow;
6523 if (appData.highlightMoveWithArrow) {
6524 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6526 XtSetArg(args[0], XtNleftBitmap, None);
6528 XtSetValues(XtNameToWidget(menuBarWidget,
6529 "menuOptions.Arrow"), args, 1);
6533 void IcsAlarmProc(w, event, prms, nprms)
6541 appData.icsAlarm = !appData.icsAlarm;
6543 if (appData.icsAlarm) {
6544 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6546 XtSetArg(args[0], XtNleftBitmap, None);
6548 XtSetValues(XtNameToWidget(menuBarWidget,
6549 "menuOptions.ICS Alarm"), args, 1);
6553 void MoveSoundProc(w, event, prms, nprms)
6561 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6563 if (appData.ringBellAfterMoves) {
6564 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6566 XtSetArg(args[0], XtNleftBitmap, None);
6568 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6572 void OneClickProc(w, event, prms, nprms)
6580 appData.oneClick = !appData.oneClick;
6582 if (appData.oneClick) {
6583 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6585 XtSetArg(args[0], XtNleftBitmap, None);
6587 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.OneClick"),
6591 void PeriodicUpdatesProc(w, event, prms, nprms)
6599 PeriodicUpdatesEvent(!appData.periodicUpdates);
6601 if (appData.periodicUpdates) {
6602 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6604 XtSetArg(args[0], XtNleftBitmap, None);
6606 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6610 void PopupExitMessageProc(w, event, prms, nprms)
6618 appData.popupExitMessage = !appData.popupExitMessage;
6620 if (appData.popupExitMessage) {
6621 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6623 XtSetArg(args[0], XtNleftBitmap, None);
6625 XtSetValues(XtNameToWidget(menuBarWidget,
6626 "menuOptions.Popup Exit Message"), args, 1);
6629 void PopupMoveErrorsProc(w, event, prms, nprms)
6637 appData.popupMoveErrors = !appData.popupMoveErrors;
6639 if (appData.popupMoveErrors) {
6640 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6642 XtSetArg(args[0], XtNleftBitmap, None);
6644 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6649 void PremoveProc(w, event, prms, nprms)
6657 appData.premove = !appData.premove;
6659 if (appData.premove) {
6660 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6662 XtSetArg(args[0], XtNleftBitmap, None);
6664 XtSetValues(XtNameToWidget(menuBarWidget,
6665 "menuOptions.Premove"), args, 1);
6669 void ShowCoordsProc(w, event, prms, nprms)
6677 appData.showCoords = !appData.showCoords;
6679 if (appData.showCoords) {
6680 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6682 XtSetArg(args[0], XtNleftBitmap, None);
6684 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6687 DrawPosition(True, NULL);
6690 void ShowThinkingProc(w, event, prms, nprms)
6696 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6697 ShowThinkingEvent();
6700 void HideThinkingProc(w, event, prms, nprms)
6708 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6709 ShowThinkingEvent();
6711 if (appData.hideThinkingFromHuman) {
6712 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6714 XtSetArg(args[0], XtNleftBitmap, None);
6716 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6721 void SaveOnExitProc(w, event, prms, nprms)
6729 saveSettingsOnExit = !saveSettingsOnExit;
6731 if (saveSettingsOnExit) {
6732 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6734 XtSetArg(args[0], XtNleftBitmap, None);
6736 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6740 void SaveSettingsProc(w, event, prms, nprms)
6746 SaveSettings(settingsFileName);
6749 void InfoProc(w, event, prms, nprms)
6756 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6761 void ManProc(w, event, prms, nprms)
6769 if (nprms && *nprms > 0)
6773 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6777 void HintProc(w, event, prms, nprms)
6786 void BookProc(w, event, prms, nprms)
6795 void AboutProc(w, event, prms, nprms)
6803 char *zippy = " (with Zippy code)";
6807 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6808 programVersion, zippy,
6809 "Copyright 1991 Digital Equipment Corporation",
6810 "Enhancements Copyright 1992-2009 Free Software Foundation",
6811 "Enhancements Copyright 2005 Alessandro Scotti",
6812 PACKAGE, " is free software and carries NO WARRANTY;",
6813 "see the file COPYING for more information.");
6814 ErrorPopUp(_("About XBoard"), buf, FALSE);
6817 void DebugProc(w, event, prms, nprms)
6823 appData.debugMode = !appData.debugMode;
6826 void AboutGameProc(w, event, prms, nprms)
6835 void NothingProc(w, event, prms, nprms)
6844 void Iconify(w, event, prms, nprms)
6853 XtSetArg(args[0], XtNiconic, True);
6854 XtSetValues(shellWidget, args, 1);
6857 void DisplayMessage(message, extMessage)
6858 char *message, *extMessage;
6860 /* display a message in the message widget */
6869 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
6874 message = extMessage;
6878 safeStrCpy(lastMsg, message, MSG_SIZ); // [HGM] make available
6880 /* need to test if messageWidget already exists, since this function
6881 can also be called during the startup, if for example a Xresource
6882 is not set up correctly */
6885 XtSetArg(arg, XtNlabel, message);
6886 XtSetValues(messageWidget, &arg, 1);
6892 void DisplayTitle(text)
6897 char title[MSG_SIZ];
6900 if (text == NULL) text = "";
6902 if (appData.titleInWindow) {
6904 XtSetArg(args[i], XtNlabel, text); i++;
6905 XtSetValues(titleWidget, args, i);
6908 if (*text != NULLCHAR) {
6909 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
6910 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
6911 } else if (appData.icsActive) {
6912 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
6913 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
6914 } else if (appData.cmailGameName[0] != NULLCHAR) {
6915 snprintf(icon, sizeof(icon), "%s", "CMail");
6916 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
6918 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
6919 } else if (gameInfo.variant == VariantGothic) {
6920 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6921 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
6924 } else if (gameInfo.variant == VariantFalcon) {
6925 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6926 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
6928 } else if (appData.noChessProgram) {
6929 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6930 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
6932 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
6933 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
6936 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
6937 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
6938 XtSetValues(shellWidget, args, i);
6943 DisplayError(message, error)
6950 if (appData.debugMode || appData.matchMode) {
6951 fprintf(stderr, "%s: %s\n", programName, message);
6954 if (appData.debugMode || appData.matchMode) {
6955 fprintf(stderr, "%s: %s: %s\n",
6956 programName, message, strerror(error));
6958 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6961 ErrorPopUp(_("Error"), message, FALSE);
6965 void DisplayMoveError(message)
6970 DrawPosition(FALSE, NULL);
6971 if (appData.debugMode || appData.matchMode) {
6972 fprintf(stderr, "%s: %s\n", programName, message);
6974 if (appData.popupMoveErrors) {
6975 ErrorPopUp(_("Error"), message, FALSE);
6977 DisplayMessage(message, "");
6982 void DisplayFatalError(message, error, status)
6988 errorExitStatus = status;
6990 fprintf(stderr, "%s: %s\n", programName, message);
6992 fprintf(stderr, "%s: %s: %s\n",
6993 programName, message, strerror(error));
6994 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6997 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
6998 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7004 void DisplayInformation(message)
7008 ErrorPopUp(_("Information"), message, TRUE);
7011 void DisplayNote(message)
7015 ErrorPopUp(_("Note"), message, FALSE);
7019 NullXErrorCheck(dpy, error_event)
7021 XErrorEvent *error_event;
7026 void DisplayIcsInteractionTitle(message)
7029 if (oldICSInteractionTitle == NULL) {
7030 /* Magic to find the old window title, adapted from vim */
7031 char *wina = getenv("WINDOWID");
7033 Window win = (Window) atoi(wina);
7034 Window root, parent, *children;
7035 unsigned int nchildren;
7036 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7038 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7039 if (!XQueryTree(xDisplay, win, &root, &parent,
7040 &children, &nchildren)) break;
7041 if (children) XFree((void *)children);
7042 if (parent == root || parent == 0) break;
7045 XSetErrorHandler(oldHandler);
7047 if (oldICSInteractionTitle == NULL) {
7048 oldICSInteractionTitle = "xterm";
7051 printf("\033]0;%s\007", message);
7055 char pendingReplyPrefix[MSG_SIZ];
7056 ProcRef pendingReplyPR;
7058 void AskQuestionProc(w, event, prms, nprms)
7065 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7069 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7072 void AskQuestionPopDown()
7074 if (!askQuestionUp) return;
7075 XtPopdown(askQuestionShell);
7076 XtDestroyWidget(askQuestionShell);
7077 askQuestionUp = False;
7080 void AskQuestionReplyAction(w, event, prms, nprms)
7090 reply = XawDialogGetValueString(w = XtParent(w));
7091 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
7092 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
7093 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
7094 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
7095 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7096 AskQuestionPopDown();
7098 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7101 void AskQuestionCallback(w, client_data, call_data)
7103 XtPointer client_data, call_data;
7108 XtSetArg(args[0], XtNlabel, &name);
7109 XtGetValues(w, args, 1);
7111 if (strcmp(name, _("cancel")) == 0) {
7112 AskQuestionPopDown();
7114 AskQuestionReplyAction(w, NULL, NULL, NULL);
7118 void AskQuestion(title, question, replyPrefix, pr)
7119 char *title, *question, *replyPrefix;
7123 Widget popup, layout, dialog, edit;
7129 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
7130 pendingReplyPR = pr;
7133 XtSetArg(args[i], XtNresizable, True); i++;
7134 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7135 askQuestionShell = popup =
7136 XtCreatePopupShell(title, transientShellWidgetClass,
7137 shellWidget, args, i);
7140 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7141 layoutArgs, XtNumber(layoutArgs));
7144 XtSetArg(args[i], XtNlabel, question); i++;
7145 XtSetArg(args[i], XtNvalue, ""); i++;
7146 XtSetArg(args[i], XtNborderWidth, 0); i++;
7147 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7150 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7151 (XtPointer) dialog);
7152 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7153 (XtPointer) dialog);
7155 XtRealizeWidget(popup);
7156 CatchDeleteWindow(popup, "AskQuestionPopDown");
7158 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7159 &x, &y, &win_x, &win_y, &mask);
7161 XtSetArg(args[0], XtNx, x - 10);
7162 XtSetArg(args[1], XtNy, y - 30);
7163 XtSetValues(popup, args, 2);
7165 XtPopup(popup, XtGrabExclusive);
7166 askQuestionUp = True;
7168 edit = XtNameToWidget(dialog, "*value");
7169 XtSetKeyboardFocus(popup, edit);
7177 if (*name == NULLCHAR) {
7179 } else if (strcmp(name, "$") == 0) {
7180 putc(BELLCHAR, stderr);
7183 char *prefix = "", *sep = "";
7184 if(!strchr(name, '/')) { prefix = appData.soundDirectory; sep = "/"; }
7185 snprintf(buf, sizeof(buf), "%s '%s%s%s' &", appData.soundProgram, prefix, sep, name);
7193 PlaySound(appData.soundMove);
7199 PlaySound(appData.soundIcsWin);
7205 PlaySound(appData.soundIcsLoss);
7211 PlaySound(appData.soundIcsDraw);
7215 PlayIcsUnfinishedSound()
7217 PlaySound(appData.soundIcsUnfinished);
7223 PlaySound(appData.soundIcsAlarm);
7229 system("stty echo");
7235 system("stty -echo");
7239 Colorize(cc, continuation)
7244 int count, outCount, error;
7246 if (textColors[(int)cc].bg > 0) {
7247 if (textColors[(int)cc].fg > 0) {
7248 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7249 textColors[(int)cc].fg, textColors[(int)cc].bg);
7251 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7252 textColors[(int)cc].bg);
7255 if (textColors[(int)cc].fg > 0) {
7256 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7257 textColors[(int)cc].fg);
7259 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7262 count = strlen(buf);
7263 outCount = OutputToProcess(NoProc, buf, count, &error);
7264 if (outCount < count) {
7265 DisplayFatalError(_("Error writing to display"), error, 1);
7268 if (continuation) return;
7271 PlaySound(appData.soundShout);
7274 PlaySound(appData.soundSShout);
7277 PlaySound(appData.soundChannel1);
7280 PlaySound(appData.soundChannel);
7283 PlaySound(appData.soundKibitz);
7286 PlaySound(appData.soundTell);
7288 case ColorChallenge:
7289 PlaySound(appData.soundChallenge);
7292 PlaySound(appData.soundRequest);
7295 PlaySound(appData.soundSeek);
7306 return getpwuid(getuid())->pw_name;
7310 ExpandPathName(path)
7313 static char static_buf[4*MSG_SIZ];
7314 char *d, *s, buf[4*MSG_SIZ];
7320 while (*s && isspace(*s))
7329 if (*(s+1) == '/') {
7330 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7334 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7335 { char *p; if(p = strchr(buf, '/')) *p = 0; }
7336 pwd = getpwnam(buf);
7339 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7343 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7344 strcat(d, strchr(s+1, '/'));
7348 safeStrCpy(d, s, 4*MSG_SIZ );
7355 static char host_name[MSG_SIZ];
7357 #if HAVE_GETHOSTNAME
7358 gethostname(host_name, MSG_SIZ);
7360 #else /* not HAVE_GETHOSTNAME */
7361 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7362 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7364 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7366 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7367 #endif /* not HAVE_GETHOSTNAME */
7370 XtIntervalId delayedEventTimerXID = 0;
7371 DelayedEventCallback delayedEventCallback = 0;
7376 delayedEventTimerXID = 0;
7377 delayedEventCallback();
7381 ScheduleDelayedEvent(cb, millisec)
7382 DelayedEventCallback cb; long millisec;
7384 if(delayedEventTimerXID && delayedEventCallback == cb)
7385 // [HGM] alive: replace, rather than add or flush identical event
7386 XtRemoveTimeOut(delayedEventTimerXID);
7387 delayedEventCallback = cb;
7388 delayedEventTimerXID =
7389 XtAppAddTimeOut(appContext, millisec,
7390 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7393 DelayedEventCallback
7396 if (delayedEventTimerXID) {
7397 return delayedEventCallback;
7404 CancelDelayedEvent()
7406 if (delayedEventTimerXID) {
7407 XtRemoveTimeOut(delayedEventTimerXID);
7408 delayedEventTimerXID = 0;
7412 XtIntervalId loadGameTimerXID = 0;
7414 int LoadGameTimerRunning()
7416 return loadGameTimerXID != 0;
7419 int StopLoadGameTimer()
7421 if (loadGameTimerXID != 0) {
7422 XtRemoveTimeOut(loadGameTimerXID);
7423 loadGameTimerXID = 0;
7431 LoadGameTimerCallback(arg, id)
7435 loadGameTimerXID = 0;
7440 StartLoadGameTimer(millisec)
7444 XtAppAddTimeOut(appContext, millisec,
7445 (XtTimerCallbackProc) LoadGameTimerCallback,
7449 XtIntervalId analysisClockXID = 0;
7452 AnalysisClockCallback(arg, id)
7456 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7457 || appData.icsEngineAnalyze) { // [DM]
7458 AnalysisPeriodicEvent(0);
7459 StartAnalysisClock();
7464 StartAnalysisClock()
7467 XtAppAddTimeOut(appContext, 2000,
7468 (XtTimerCallbackProc) AnalysisClockCallback,
7472 XtIntervalId clockTimerXID = 0;
7474 int ClockTimerRunning()
7476 return clockTimerXID != 0;
7479 int StopClockTimer()
7481 if (clockTimerXID != 0) {
7482 XtRemoveTimeOut(clockTimerXID);
7491 ClockTimerCallback(arg, id)
7500 StartClockTimer(millisec)
7504 XtAppAddTimeOut(appContext, millisec,
7505 (XtTimerCallbackProc) ClockTimerCallback,
7510 DisplayTimerLabel(w, color, timer, highlight)
7519 /* check for low time warning */
7520 Pixel foregroundOrWarningColor = timerForegroundPixel;
7523 appData.lowTimeWarning &&
7524 (timer / 1000) < appData.icsAlarmTime)
7525 foregroundOrWarningColor = lowTimeWarningColor;
7527 if (appData.clockMode) {
7528 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7529 XtSetArg(args[0], XtNlabel, buf);
7531 snprintf(buf, MSG_SIZ, "%s ", color);
7532 XtSetArg(args[0], XtNlabel, buf);
7537 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7538 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7540 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7541 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7544 XtSetValues(w, args, 3);
7548 DisplayWhiteClock(timeRemaining, highlight)
7554 if(appData.noGUI) return;
7555 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7556 if (highlight && iconPixmap == bIconPixmap) {
7557 iconPixmap = wIconPixmap;
7558 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7559 XtSetValues(shellWidget, args, 1);
7564 DisplayBlackClock(timeRemaining, highlight)
7570 if(appData.noGUI) return;
7571 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7572 if (highlight && iconPixmap == wIconPixmap) {
7573 iconPixmap = bIconPixmap;
7574 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7575 XtSetValues(shellWidget, args, 1);
7593 int StartChildProcess(cmdLine, dir, pr)
7600 int to_prog[2], from_prog[2];
7604 if (appData.debugMode) {
7605 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7608 /* We do NOT feed the cmdLine to the shell; we just
7609 parse it into blank-separated arguments in the
7610 most simple-minded way possible.
7613 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7616 while(*p == ' ') p++;
7618 if(*p == '"' || *p == '\'')
7619 p = strchr(++argv[i-1], *p);
7620 else p = strchr(p, ' ');
7621 if (p == NULL) break;
7626 SetUpChildIO(to_prog, from_prog);
7628 if ((pid = fork()) == 0) {
7630 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7631 close(to_prog[1]); // first close the unused pipe ends
7632 close(from_prog[0]);
7633 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7634 dup2(from_prog[1], 1);
7635 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7636 close(from_prog[1]); // and closing again loses one of the pipes!
7637 if(fileno(stderr) >= 2) // better safe than sorry...
7638 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7640 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7645 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7647 execvp(argv[0], argv);
7649 /* If we get here, exec failed */
7654 /* Parent process */
7656 close(from_prog[1]);
7658 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7661 cp->fdFrom = from_prog[0];
7662 cp->fdTo = to_prog[1];
7667 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7668 static RETSIGTYPE AlarmCallBack(int n)
7674 DestroyChildProcess(pr, signalType)
7678 ChildProc *cp = (ChildProc *) pr;
7680 if (cp->kind != CPReal) return;
7682 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7683 signal(SIGALRM, AlarmCallBack);
7685 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7686 kill(cp->pid, SIGKILL); // kill it forcefully
7687 wait((int *) 0); // and wait again
7691 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7693 /* Process is exiting either because of the kill or because of
7694 a quit command sent by the backend; either way, wait for it to die.
7703 InterruptChildProcess(pr)
7706 ChildProc *cp = (ChildProc *) pr;
7708 if (cp->kind != CPReal) return;
7709 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7712 int OpenTelnet(host, port, pr)
7717 char cmdLine[MSG_SIZ];
7719 if (port[0] == NULLCHAR) {
7720 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7722 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7724 return StartChildProcess(cmdLine, "", pr);
7727 int OpenTCP(host, port, pr)
7733 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7734 #else /* !OMIT_SOCKETS */
7735 struct addrinfo hints;
7736 struct addrinfo *ais, *ai;
7741 memset(&hints, 0, sizeof(hints));
7742 hints.ai_family = AF_UNSPEC;
7743 hints.ai_socktype = SOCK_STREAM;
7745 error = getaddrinfo(host, port, &hints, &ais);
7747 /* a getaddrinfo error is not an errno, so can't return it */
7748 fprintf(debugFP, "getaddrinfo(%s, %s): %s\n",
7749 host, port, gai_strerror(error));
7753 for (ai = ais; ai != NULL; ai = ai->ai_next) {
7754 if ((s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) < 0) {
7758 if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0) {
7771 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7777 #endif /* !OMIT_SOCKETS */
7782 int OpenCommPort(name, pr)
7789 fd = open(name, 2, 0);
7790 if (fd < 0) return errno;
7792 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7802 int OpenLoopback(pr)
7808 SetUpChildIO(to, from);
7810 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7813 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7820 int OpenRcmd(host, user, cmd, pr)
7821 char *host, *user, *cmd;
7824 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7828 #define INPUT_SOURCE_BUF_SIZE 8192
7837 char buf[INPUT_SOURCE_BUF_SIZE];
7842 DoInputCallback(closure, source, xid)
7847 InputSource *is = (InputSource *) closure;
7852 if (is->lineByLine) {
7853 count = read(is->fd, is->unused,
7854 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7856 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7859 is->unused += count;
7861 while (p < is->unused) {
7862 q = memchr(p, '\n', is->unused - p);
7863 if (q == NULL) break;
7865 (is->func)(is, is->closure, p, q - p, 0);
7869 while (p < is->unused) {
7874 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
7879 (is->func)(is, is->closure, is->buf, count, error);
7883 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
7890 ChildProc *cp = (ChildProc *) pr;
7892 is = (InputSource *) calloc(1, sizeof(InputSource));
7893 is->lineByLine = lineByLine;
7897 is->fd = fileno(stdin);
7899 is->kind = cp->kind;
7900 is->fd = cp->fdFrom;
7903 is->unused = is->buf;
7906 is->xid = XtAppAddInput(appContext, is->fd,
7907 (XtPointer) (XtInputReadMask),
7908 (XtInputCallbackProc) DoInputCallback,
7910 is->closure = closure;
7911 return (InputSourceRef) is;
7915 RemoveInputSource(isr)
7918 InputSource *is = (InputSource *) isr;
7920 if (is->xid == 0) return;
7921 XtRemoveInput(is->xid);
7925 int OutputToProcess(pr, message, count, outError)
7931 static int line = 0;
7932 ChildProc *cp = (ChildProc *) pr;
7937 if (appData.noJoin || !appData.useInternalWrap)
7938 outCount = fwrite(message, 1, count, stdout);
7941 int width = get_term_width();
7942 int len = wrap(NULL, message, count, width, &line);
7943 char *msg = malloc(len);
7947 outCount = fwrite(message, 1, count, stdout);
7950 dbgchk = wrap(msg, message, count, width, &line);
7951 if (dbgchk != len && appData.debugMode)
7952 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
7953 outCount = fwrite(msg, 1, dbgchk, stdout);
7959 outCount = write(cp->fdTo, message, count);
7969 /* Output message to process, with "ms" milliseconds of delay
7970 between each character. This is needed when sending the logon
7971 script to ICC, which for some reason doesn't like the
7972 instantaneous send. */
7973 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
7980 ChildProc *cp = (ChildProc *) pr;
7985 r = write(cp->fdTo, message++, 1);
7998 /**** Animation code by Hugh Fisher, DCS, ANU.
8000 Known problem: if a window overlapping the board is
8001 moved away while a piece is being animated underneath,
8002 the newly exposed area won't be updated properly.
8003 I can live with this.
8005 Known problem: if you look carefully at the animation
8006 of pieces in mono mode, they are being drawn as solid
8007 shapes without interior detail while moving. Fixing
8008 this would be a major complication for minimal return.
8011 /* Masks for XPM pieces. Black and white pieces can have
8012 different shapes, but in the interest of retaining my
8013 sanity pieces must have the same outline on both light
8014 and dark squares, and all pieces must use the same
8015 background square colors/images. */
8017 static int xpmDone = 0;
8020 CreateAnimMasks (pieceDepth)
8027 unsigned long plane;
8030 /* Need a bitmap just to get a GC with right depth */
8031 buf = XCreatePixmap(xDisplay, xBoardWindow,
8033 values.foreground = 1;
8034 values.background = 0;
8035 /* Don't use XtGetGC, not read only */
8036 maskGC = XCreateGC(xDisplay, buf,
8037 GCForeground | GCBackground, &values);
8038 XFreePixmap(xDisplay, buf);
8040 buf = XCreatePixmap(xDisplay, xBoardWindow,
8041 squareSize, squareSize, pieceDepth);
8042 values.foreground = XBlackPixel(xDisplay, xScreen);
8043 values.background = XWhitePixel(xDisplay, xScreen);
8044 bufGC = XCreateGC(xDisplay, buf,
8045 GCForeground | GCBackground, &values);
8047 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8048 /* Begin with empty mask */
8049 if(!xpmDone) // [HGM] pieces: keep using existing
8050 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8051 squareSize, squareSize, 1);
8052 XSetFunction(xDisplay, maskGC, GXclear);
8053 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8054 0, 0, squareSize, squareSize);
8056 /* Take a copy of the piece */
8061 XSetFunction(xDisplay, bufGC, GXcopy);
8062 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8064 0, 0, squareSize, squareSize, 0, 0);
8066 /* XOR the background (light) over the piece */
8067 XSetFunction(xDisplay, bufGC, GXxor);
8069 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8070 0, 0, squareSize, squareSize, 0, 0);
8072 XSetForeground(xDisplay, bufGC, lightSquareColor);
8073 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8076 /* We now have an inverted piece image with the background
8077 erased. Construct mask by just selecting all the non-zero
8078 pixels - no need to reconstruct the original image. */
8079 XSetFunction(xDisplay, maskGC, GXor);
8081 /* Might be quicker to download an XImage and create bitmap
8082 data from it rather than this N copies per piece, but it
8083 only takes a fraction of a second and there is a much
8084 longer delay for loading the pieces. */
8085 for (n = 0; n < pieceDepth; n ++) {
8086 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8087 0, 0, squareSize, squareSize,
8093 XFreePixmap(xDisplay, buf);
8094 XFreeGC(xDisplay, bufGC);
8095 XFreeGC(xDisplay, maskGC);
8099 InitAnimState (anim, info)
8101 XWindowAttributes * info;
8106 /* Each buffer is square size, same depth as window */
8107 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8108 squareSize, squareSize, info->depth);
8109 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8110 squareSize, squareSize, info->depth);
8112 /* Create a plain GC for blitting */
8113 mask = GCForeground | GCBackground | GCFunction |
8114 GCPlaneMask | GCGraphicsExposures;
8115 values.foreground = XBlackPixel(xDisplay, xScreen);
8116 values.background = XWhitePixel(xDisplay, xScreen);
8117 values.function = GXcopy;
8118 values.plane_mask = AllPlanes;
8119 values.graphics_exposures = False;
8120 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8122 /* Piece will be copied from an existing context at
8123 the start of each new animation/drag. */
8124 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8126 /* Outline will be a read-only copy of an existing */
8127 anim->outlineGC = None;
8133 XWindowAttributes info;
8135 if (xpmDone && gameInfo.variant == oldVariant) return;
8136 if(xpmDone) oldVariant = gameInfo.variant; // first time pieces might not be created yet
8137 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8139 InitAnimState(&game, &info);
8140 InitAnimState(&player, &info);
8142 /* For XPM pieces, we need bitmaps to use as masks. */
8144 CreateAnimMasks(info.depth), xpmDone = 1;
8149 static Boolean frameWaiting;
8151 static RETSIGTYPE FrameAlarm (sig)
8154 frameWaiting = False;
8155 /* In case System-V style signals. Needed?? */
8156 signal(SIGALRM, FrameAlarm);
8163 struct itimerval delay;
8165 XSync(xDisplay, False);
8168 frameWaiting = True;
8169 signal(SIGALRM, FrameAlarm);
8170 delay.it_interval.tv_sec =
8171 delay.it_value.tv_sec = time / 1000;
8172 delay.it_interval.tv_usec =
8173 delay.it_value.tv_usec = (time % 1000) * 1000;
8174 setitimer(ITIMER_REAL, &delay, NULL);
8175 while (frameWaiting) pause();
8176 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8177 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8178 setitimer(ITIMER_REAL, &delay, NULL);
8188 XSync(xDisplay, False);
8190 usleep(time * 1000);
8195 /* Convert board position to corner of screen rect and color */
8198 ScreenSquare(column, row, pt, color)
8199 int column; int row; XPoint * pt; int * color;
8202 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8203 pt->y = lineGap + row * (squareSize + lineGap);
8205 pt->x = lineGap + column * (squareSize + lineGap);
8206 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8208 *color = SquareColor(row, column);
8211 /* Convert window coords to square */
8214 BoardSquare(x, y, column, row)
8215 int x; int y; int * column; int * row;
8217 *column = EventToSquare(x, BOARD_WIDTH);
8218 if (flipView && *column >= 0)
8219 *column = BOARD_WIDTH - 1 - *column;
8220 *row = EventToSquare(y, BOARD_HEIGHT);
8221 if (!flipView && *row >= 0)
8222 *row = BOARD_HEIGHT - 1 - *row;
8227 #undef Max /* just in case */
8229 #define Max(a, b) ((a) > (b) ? (a) : (b))
8230 #define Min(a, b) ((a) < (b) ? (a) : (b))
8233 SetRect(rect, x, y, width, height)
8234 XRectangle * rect; int x; int y; int width; int height;
8238 rect->width = width;
8239 rect->height = height;
8242 /* Test if two frames overlap. If they do, return
8243 intersection rect within old and location of
8244 that rect within new. */
8247 Intersect(old, new, size, area, pt)
8248 XPoint * old; XPoint * new;
8249 int size; XRectangle * area; XPoint * pt;
8251 if (old->x > new->x + size || new->x > old->x + size ||
8252 old->y > new->y + size || new->y > old->y + size) {
8255 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8256 size - abs(old->x - new->x), size - abs(old->y - new->y));
8257 pt->x = Max(old->x - new->x, 0);
8258 pt->y = Max(old->y - new->y, 0);
8263 /* For two overlapping frames, return the rect(s)
8264 in the old that do not intersect with the new. */
8267 CalcUpdateRects(old, new, size, update, nUpdates)
8268 XPoint * old; XPoint * new; int size;
8269 XRectangle update[]; int * nUpdates;
8273 /* If old = new (shouldn't happen) then nothing to draw */
8274 if (old->x == new->x && old->y == new->y) {
8278 /* Work out what bits overlap. Since we know the rects
8279 are the same size we don't need a full intersect calc. */
8281 /* Top or bottom edge? */
8282 if (new->y > old->y) {
8283 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8285 } else if (old->y > new->y) {
8286 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8287 size, old->y - new->y);
8290 /* Left or right edge - don't overlap any update calculated above. */
8291 if (new->x > old->x) {
8292 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8293 new->x - old->x, size - abs(new->y - old->y));
8295 } else if (old->x > new->x) {
8296 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8297 old->x - new->x, size - abs(new->y - old->y));
8304 /* Generate a series of frame coords from start->mid->finish.
8305 The movement rate doubles until the half way point is
8306 reached, then halves back down to the final destination,
8307 which gives a nice slow in/out effect. The algorithmn
8308 may seem to generate too many intermediates for short
8309 moves, but remember that the purpose is to attract the
8310 viewers attention to the piece about to be moved and
8311 then to where it ends up. Too few frames would be less
8315 Tween(start, mid, finish, factor, frames, nFrames)
8316 XPoint * start; XPoint * mid;
8317 XPoint * finish; int factor;
8318 XPoint frames[]; int * nFrames;
8320 int fraction, n, count;
8324 /* Slow in, stepping 1/16th, then 1/8th, ... */
8326 for (n = 0; n < factor; n++)
8328 for (n = 0; n < factor; n++) {
8329 frames[count].x = start->x + (mid->x - start->x) / fraction;
8330 frames[count].y = start->y + (mid->y - start->y) / fraction;
8332 fraction = fraction / 2;
8336 frames[count] = *mid;
8339 /* Slow out, stepping 1/2, then 1/4, ... */
8341 for (n = 0; n < factor; n++) {
8342 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8343 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8345 fraction = fraction * 2;
8350 /* Draw a piece on the screen without disturbing what's there */
8353 SelectGCMask(piece, clip, outline, mask)
8354 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8358 /* Bitmap for piece being moved. */
8359 if (appData.monoMode) {
8360 *mask = *pieceToSolid(piece);
8361 } else if (useImages) {
8363 *mask = xpmMask[piece];
8365 *mask = ximMaskPm[piece];
8368 *mask = *pieceToSolid(piece);
8371 /* GC for piece being moved. Square color doesn't matter, but
8372 since it gets modified we make a copy of the original. */
8374 if (appData.monoMode)
8379 if (appData.monoMode)
8384 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8386 /* Outline only used in mono mode and is not modified */
8388 *outline = bwPieceGC;
8390 *outline = wbPieceGC;
8394 OverlayPiece(piece, clip, outline, dest)
8395 ChessSquare piece; GC clip; GC outline; Drawable dest;
8400 /* Draw solid rectangle which will be clipped to shape of piece */
8401 XFillRectangle(xDisplay, dest, clip,
8402 0, 0, squareSize, squareSize);
8403 if (appData.monoMode)
8404 /* Also draw outline in contrasting color for black
8405 on black / white on white cases */
8406 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8407 0, 0, squareSize, squareSize, 0, 0, 1);
8409 /* Copy the piece */
8414 if(appData.upsideDown && flipView) kind ^= 2;
8415 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8417 0, 0, squareSize, squareSize,
8422 /* Animate the movement of a single piece */
8425 BeginAnimation(anim, piece, startColor, start)
8433 if(appData.upsideDown && flipView) piece += piece < BlackPawn ? BlackPawn : -BlackPawn;
8434 /* The old buffer is initialised with the start square (empty) */
8435 BlankSquare(start->x, start->y, startColor, EmptySquare, anim->saveBuf, 0);
8436 anim->prevFrame = *start;
8438 /* The piece will be drawn using its own bitmap as a matte */
8439 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8440 XSetClipMask(xDisplay, anim->pieceGC, mask);
8444 AnimationFrame(anim, frame, piece)
8449 XRectangle updates[4];
8454 /* Save what we are about to draw into the new buffer */
8455 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8456 frame->x, frame->y, squareSize, squareSize,
8459 /* Erase bits of the previous frame */
8460 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8461 /* Where the new frame overlapped the previous,
8462 the contents in newBuf are wrong. */
8463 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8464 overlap.x, overlap.y,
8465 overlap.width, overlap.height,
8467 /* Repaint the areas in the old that don't overlap new */
8468 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8469 for (i = 0; i < count; i++)
8470 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8471 updates[i].x - anim->prevFrame.x,
8472 updates[i].y - anim->prevFrame.y,
8473 updates[i].width, updates[i].height,
8474 updates[i].x, updates[i].y);
8476 /* Easy when no overlap */
8477 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8478 0, 0, squareSize, squareSize,
8479 anim->prevFrame.x, anim->prevFrame.y);
8482 /* Save this frame for next time round */
8483 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8484 0, 0, squareSize, squareSize,
8486 anim->prevFrame = *frame;
8488 /* Draw piece over original screen contents, not current,
8489 and copy entire rect. Wipes out overlapping piece images. */
8490 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8491 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8492 0, 0, squareSize, squareSize,
8493 frame->x, frame->y);
8497 EndAnimation (anim, finish)
8501 XRectangle updates[4];
8506 /* The main code will redraw the final square, so we
8507 only need to erase the bits that don't overlap. */
8508 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8509 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8510 for (i = 0; i < count; i++)
8511 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8512 updates[i].x - anim->prevFrame.x,
8513 updates[i].y - anim->prevFrame.y,
8514 updates[i].width, updates[i].height,
8515 updates[i].x, updates[i].y);
8517 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8518 0, 0, squareSize, squareSize,
8519 anim->prevFrame.x, anim->prevFrame.y);
8524 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8526 ChessSquare piece; int startColor;
8527 XPoint * start; XPoint * finish;
8528 XPoint frames[]; int nFrames;
8532 BeginAnimation(anim, piece, startColor, start);
8533 for (n = 0; n < nFrames; n++) {
8534 AnimationFrame(anim, &(frames[n]), piece);
8535 FrameDelay(appData.animSpeed);
8537 EndAnimation(anim, finish);
8541 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
8544 ChessSquare piece = board[fromY][toY];
8545 board[fromY][toY] = EmptySquare;
8546 DrawPosition(FALSE, board);
8548 x = lineGap + ((BOARD_WIDTH-1)-toX) * (squareSize + lineGap);
8549 y = lineGap + toY * (squareSize + lineGap);
8551 x = lineGap + toX * (squareSize + lineGap);
8552 y = lineGap + ((BOARD_HEIGHT-1)-toY) * (squareSize + lineGap);
8554 for(i=1; i<4*kFactor; i++) {
8555 int r = squareSize * 9 * i/(20*kFactor - 5);
8556 XFillArc(xDisplay, xBoardWindow, highlineGC,
8557 x + squareSize/2 - r, y+squareSize/2 - r, 2*r, 2*r, 0, 64*360);
8558 FrameDelay(appData.animSpeed);
8560 board[fromY][toY] = piece;
8563 /* Main control logic for deciding what to animate and how */
8566 AnimateMove(board, fromX, fromY, toX, toY)
8575 XPoint start, finish, mid;
8576 XPoint frames[kFactor * 2 + 1];
8577 int nFrames, startColor, endColor;
8579 /* Are we animating? */
8580 if (!appData.animate || appData.blindfold)
8583 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8584 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8585 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8587 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8588 piece = board[fromY][fromX];
8589 if (piece >= EmptySquare) return;
8594 hop = abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1;
8597 if (appData.debugMode) {
8598 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8599 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8600 piece, fromX, fromY, toX, toY); }
8602 ScreenSquare(fromX, fromY, &start, &startColor);
8603 ScreenSquare(toX, toY, &finish, &endColor);
8606 /* Knight: make straight movement then diagonal */
8607 if (abs(toY - fromY) < abs(toX - fromX)) {
8608 mid.x = start.x + (finish.x - start.x) / 2;
8612 mid.y = start.y + (finish.y - start.y) / 2;
8615 mid.x = start.x + (finish.x - start.x) / 2;
8616 mid.y = start.y + (finish.y - start.y) / 2;
8619 /* Don't use as many frames for very short moves */
8620 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8621 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8623 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8624 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8625 if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged
8627 for(i=0; i<BOARD_WIDTH; i++) for(j=0; j<BOARD_HEIGHT; j++)
8628 if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] = True;
8631 /* Be sure end square is redrawn */
8632 damage[0][toY][toX] = True;
8636 DragPieceBegin(x, y)
8639 int boardX, boardY, color;
8642 /* Are we animating? */
8643 if (!appData.animateDragging || appData.blindfold)
8646 /* Figure out which square we start in and the
8647 mouse position relative to top left corner. */
8648 BoardSquare(x, y, &boardX, &boardY);
8649 player.startBoardX = boardX;
8650 player.startBoardY = boardY;
8651 ScreenSquare(boardX, boardY, &corner, &color);
8652 player.startSquare = corner;
8653 player.startColor = color;
8654 /* As soon as we start dragging, the piece will jump slightly to
8655 be centered over the mouse pointer. */
8656 player.mouseDelta.x = squareSize/2;
8657 player.mouseDelta.y = squareSize/2;
8658 /* Initialise animation */
8659 player.dragPiece = PieceForSquare(boardX, boardY);
8661 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8662 player.dragActive = True;
8663 BeginAnimation(&player, player.dragPiece, color, &corner);
8664 /* Mark this square as needing to be redrawn. Note that
8665 we don't remove the piece though, since logically (ie
8666 as seen by opponent) the move hasn't been made yet. */
8667 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8668 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8669 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8670 corner.x, corner.y, squareSize, squareSize,
8671 0, 0); // [HGM] zh: unstack in stead of grab
8672 if(gatingPiece != EmptySquare) {
8673 /* Kludge alert: When gating we want the introduced
8674 piece to appear on the from square. To generate an
8675 image of it, we draw it on the board, copy the image,
8676 and draw the original piece again. */
8677 ChessSquare piece = boards[currentMove][boardY][boardX];
8678 DrawSquare(boardY, boardX, gatingPiece, 0);
8679 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8680 corner.x, corner.y, squareSize, squareSize, 0, 0);
8681 DrawSquare(boardY, boardX, piece, 0);
8683 damage[0][boardY][boardX] = True;
8685 player.dragActive = False;
8690 ChangeDragPiece(ChessSquare piece)
8693 player.dragPiece = piece;
8694 /* The piece will be drawn using its own bitmap as a matte */
8695 SelectGCMask(piece, &player.pieceGC, &player.outlineGC, &mask);
8696 XSetClipMask(xDisplay, player.pieceGC, mask);
8705 /* Are we animating? */
8706 if (!appData.animateDragging || appData.blindfold)
8710 if (! player.dragActive)
8712 /* Move piece, maintaining same relative position
8713 of mouse within square */
8714 corner.x = x - player.mouseDelta.x;
8715 corner.y = y - player.mouseDelta.y;
8716 AnimationFrame(&player, &corner, player.dragPiece);
8718 if (appData.highlightDragging) {
8720 BoardSquare(x, y, &boardX, &boardY);
8721 SetHighlights(fromX, fromY, boardX, boardY);
8730 int boardX, boardY, color;
8733 /* Are we animating? */
8734 if (!appData.animateDragging || appData.blindfold)
8738 if (! player.dragActive)
8740 /* Last frame in sequence is square piece is
8741 placed on, which may not match mouse exactly. */
8742 BoardSquare(x, y, &boardX, &boardY);
8743 ScreenSquare(boardX, boardY, &corner, &color);
8744 EndAnimation(&player, &corner);
8746 /* Be sure end square is redrawn */
8747 damage[0][boardY][boardX] = True;
8749 /* This prevents weird things happening with fast successive
8750 clicks which on my Sun at least can cause motion events
8751 without corresponding press/release. */
8752 player.dragActive = False;
8755 /* Handle expose event while piece being dragged */
8760 if (!player.dragActive || appData.blindfold)
8763 /* What we're doing: logically, the move hasn't been made yet,
8764 so the piece is still in it's original square. But visually
8765 it's being dragged around the board. So we erase the square
8766 that the piece is on and draw it at the last known drag point. */
8767 BlankSquare(player.startSquare.x, player.startSquare.y,
8768 player.startColor, EmptySquare, xBoardWindow, 1);
8769 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8770 damage[0][player.startBoardY][player.startBoardX] = TRUE;
8773 #include <sys/ioctl.h>
8774 int get_term_width()
8776 int fd, default_width;
8779 default_width = 79; // this is FICS default anyway...
8781 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8783 if (!ioctl(fd, TIOCGSIZE, &win))
8784 default_width = win.ts_cols;
8785 #elif defined(TIOCGWINSZ)
8787 if (!ioctl(fd, TIOCGWINSZ, &win))
8788 default_width = win.ws_col;
8790 return default_width;
8796 static int old_width = 0;
8797 int new_width = get_term_width();
8799 if (old_width != new_width)
8800 ics_printf("set width %d\n", new_width);
8801 old_width = new_width;
8804 void NotifyFrontendLogin()
8809 /* [AS] Arrow highlighting support */
8811 static double A_WIDTH = 5; /* Width of arrow body */
8813 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
8814 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
8816 static double Sqr( double x )
8821 static int Round( double x )
8823 return (int) (x + 0.5);
8826 void SquareToPos(int rank, int file, int *x, int *y)
8829 *x = lineGap + ((BOARD_WIDTH-1)-file) * (squareSize + lineGap);
8830 *y = lineGap + rank * (squareSize + lineGap);
8832 *x = lineGap + file * (squareSize + lineGap);
8833 *y = lineGap + ((BOARD_HEIGHT-1)-rank) * (squareSize + lineGap);
8837 /* Draw an arrow between two points using current settings */
8838 void DrawArrowBetweenPoints( int s_x, int s_y, int d_x, int d_y )
8841 double dx, dy, j, k, x, y;
8844 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
8846 arrow[0].x = s_x + A_WIDTH + 0.5;
8849 arrow[1].x = s_x + A_WIDTH + 0.5;
8850 arrow[1].y = d_y - h;
8852 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8853 arrow[2].y = d_y - h;
8858 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
8859 arrow[5].y = d_y - h;
8861 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8862 arrow[4].y = d_y - h;
8864 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
8867 else if( d_y == s_y ) {
8868 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
8871 arrow[0].y = s_y + A_WIDTH + 0.5;
8873 arrow[1].x = d_x - w;
8874 arrow[1].y = s_y + A_WIDTH + 0.5;
8876 arrow[2].x = d_x - w;
8877 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8882 arrow[5].x = d_x - w;
8883 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
8885 arrow[4].x = d_x - w;
8886 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8889 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
8892 /* [AS] Needed a lot of paper for this! :-) */
8893 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
8894 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
8896 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
8898 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
8903 arrow[0].x = Round(x - j);
8904 arrow[0].y = Round(y + j*dx);
8906 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
8907 arrow[1].y = Round(arrow[0].y - 2*j*dx);
8910 x = (double) d_x - k;
8911 y = (double) d_y - k*dy;
8914 x = (double) d_x + k;
8915 y = (double) d_y + k*dy;
8918 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
8920 arrow[6].x = Round(x - j);
8921 arrow[6].y = Round(y + j*dx);
8923 arrow[2].x = Round(arrow[6].x + 2*j);
8924 arrow[2].y = Round(arrow[6].y - 2*j*dx);
8926 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
8927 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
8932 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
8933 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
8936 XFillPolygon(xDisplay, xBoardWindow, highlineGC, arrow, 7, Nonconvex, CoordModeOrigin);
8937 // Polygon( hdc, arrow, 7 );
8940 /* [AS] Draw an arrow between two squares */
8941 void DrawArrowBetweenSquares( int s_col, int s_row, int d_col, int d_row )
8943 int s_x, s_y, d_x, d_y, hor, vert, i;
8945 if( s_col == d_col && s_row == d_row ) {
8949 /* Get source and destination points */
8950 SquareToPos( s_row, s_col, &s_x, &s_y);
8951 SquareToPos( d_row, d_col, &d_x, &d_y);
8954 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
8956 else if( d_y < s_y ) {
8957 d_y += squareSize / 2 + squareSize / 4;
8960 d_y += squareSize / 2;
8964 d_x += squareSize / 2 - squareSize / 4;
8966 else if( d_x < s_x ) {
8967 d_x += squareSize / 2 + squareSize / 4;
8970 d_x += squareSize / 2;
8973 s_x += squareSize / 2;
8974 s_y += squareSize / 2;
8977 A_WIDTH = squareSize / 14.; //[HGM] make float
8979 DrawArrowBetweenPoints( s_x, s_y, d_x, d_y );
8981 hor = 64*s_col + 32; vert = 64*s_row + 32;
8982 for(i=0; i<= 64; i++) {
8983 damage[0][vert+6>>6][hor+6>>6] = True;
8984 damage[0][vert-6>>6][hor+6>>6] = True;
8985 damage[0][vert+6>>6][hor-6>>6] = True;
8986 damage[0][vert-6>>6][hor-6>>6] = True;
8987 hor += d_col - s_col; vert += d_row - s_row;
8991 Boolean IsDrawArrowEnabled()
8993 return appData.highlightMoveWithArrow && squareSize >= 32;
8996 void DrawArrowHighlight(int fromX, int fromY, int toX,int toY)
8998 if( IsDrawArrowEnabled() && fromX >= 0 && fromY >= 0 && toX >= 0 && toY >= 0)
8999 DrawArrowBetweenSquares(fromX, fromY, toX, toY);
9002 void UpdateLogos(int displ)
9004 return; // no logos in XBoard yet