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 Free Software Foundation, Inc.
10 * The following terms apply to Digital Equipment Corporation's copyright
12 * ------------------------------------------------------------------------
15 * Permission to use, copy, modify, and distribute this software and its
16 * documentation for any purpose and without fee is hereby granted,
17 * provided that the above copyright notice appear in all copies and that
18 * both that copyright notice and this permission notice appear in
19 * supporting documentation, and that the name of Digital not be
20 * used in advertising or publicity pertaining to distribution of the
21 * software without specific, written prior permission.
23 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
30 * ------------------------------------------------------------------------
32 * The following terms apply to the enhanced version of XBoard
33 * distributed by the Free Software Foundation:
34 * ------------------------------------------------------------------------
36 * GNU XBoard is free software: you can redistribute it and/or modify
37 * it under the terms of the GNU General Public License as published by
38 * the Free Software Foundation, either version 3 of the License, or (at
39 * your option) any later version.
41 * GNU XBoard is distributed in the hope that it will be useful, but
42 * WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44 * General Public License for more details.
46 * You should have received a copy of the GNU General Public License
47 * along with this program. If not, see http://www.gnu.org/licenses/. *
49 *------------------------------------------------------------------------
50 ** See the file ChangeLog for a revision history. */
60 #include <sys/types.h>
66 # if HAVE_SYS_SOCKET_H
67 # include <sys/socket.h>
68 # include <netinet/in.h>
70 # else /* not HAVE_SYS_SOCKET_H */
71 # if HAVE_LAN_SOCKET_H
72 # include <lan/socket.h>
74 # include <lan/netdb.h>
75 # else /* not HAVE_LAN_SOCKET_H */
76 # define OMIT_SOCKETS 1
77 # endif /* not HAVE_LAN_SOCKET_H */
78 # endif /* not HAVE_SYS_SOCKET_H */
79 #endif /* !OMIT_SOCKETS */
84 #else /* not STDC_HEADERS */
85 extern char *getenv();
88 # else /* not HAVE_STRING_H */
90 # endif /* not HAVE_STRING_H */
91 #endif /* not STDC_HEADERS */
94 # include <sys/fcntl.h>
95 #else /* not HAVE_SYS_FCNTL_H */
98 # endif /* HAVE_FCNTL_H */
99 #endif /* not HAVE_SYS_FCNTL_H */
101 #if HAVE_SYS_SYSTEMINFO_H
102 # include <sys/systeminfo.h>
103 #endif /* HAVE_SYS_SYSTEMINFO_H */
105 #if TIME_WITH_SYS_TIME
106 # include <sys/time.h>
110 # include <sys/time.h>
121 # include <sys/wait.h>
126 # define NAMLEN(dirent) strlen((dirent)->d_name)
127 # define HAVE_DIR_STRUCT
129 # define dirent direct
130 # define NAMLEN(dirent) (dirent)->d_namlen
132 # include <sys/ndir.h>
133 # define HAVE_DIR_STRUCT
136 # include <sys/dir.h>
137 # define HAVE_DIR_STRUCT
141 # define HAVE_DIR_STRUCT
145 #include <X11/Intrinsic.h>
146 #include <X11/StringDefs.h>
147 #include <X11/Shell.h>
148 #include <X11/cursorfont.h>
149 #include <X11/Xatom.h>
150 #include <X11/Xmu/Atoms.h>
152 #include <X11/Xaw3d/Dialog.h>
153 #include <X11/Xaw3d/Form.h>
154 #include <X11/Xaw3d/List.h>
155 #include <X11/Xaw3d/Label.h>
156 #include <X11/Xaw3d/SimpleMenu.h>
157 #include <X11/Xaw3d/SmeBSB.h>
158 #include <X11/Xaw3d/SmeLine.h>
159 #include <X11/Xaw3d/Box.h>
160 #include <X11/Xaw3d/MenuButton.h>
161 #include <X11/Xaw3d/Text.h>
162 #include <X11/Xaw3d/AsciiText.h>
164 #include <X11/Xaw/Dialog.h>
165 #include <X11/Xaw/Form.h>
166 #include <X11/Xaw/List.h>
167 #include <X11/Xaw/Label.h>
168 #include <X11/Xaw/SimpleMenu.h>
169 #include <X11/Xaw/SmeBSB.h>
170 #include <X11/Xaw/SmeLine.h>
171 #include <X11/Xaw/Box.h>
172 #include <X11/Xaw/MenuButton.h>
173 #include <X11/Xaw/Text.h>
174 #include <X11/Xaw/AsciiText.h>
177 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
182 #include "pixmaps/pixmaps.h"
183 #define IMAGE_EXT "xpm"
185 #define IMAGE_EXT "xim"
186 #include "bitmaps/bitmaps.h"
189 #include "bitmaps/icon_white.bm"
190 #include "bitmaps/icon_black.bm"
191 #include "bitmaps/checkmark.bm"
193 #include "frontend.h"
195 #include "backendz.h"
199 #include "xgamelist.h"
200 #include "xhistory.h"
201 #include "xedittags.h"
204 // must be moved to xengineoutput.h
206 void EngineOutputProc P((Widget w, XEvent *event,
207 String *prms, Cardinal *nprms));
208 void EvalGraphProc P((Widget w, XEvent *event,
209 String *prms, Cardinal *nprms));
216 #define usleep(t) _sleep2(((t)+500)/1000)
220 # define _(s) gettext (s)
221 # define N_(s) gettext_noop (s)
239 int main P((int argc, char **argv));
240 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
241 char *init_path, char *mode, int (*show_entry)(), char **name_return));
242 RETSIGTYPE CmailSigHandler P((int sig));
243 RETSIGTYPE IntSigHandler P((int sig));
244 RETSIGTYPE TermSizeSigHandler P((int sig));
245 void CreateGCs P((void));
246 void CreateXIMPieces P((void));
247 void CreateXPMPieces P((void));
248 void CreateXPMBoard P((char *s, int n));
249 void CreatePieces P((void));
250 void CreatePieceMenus P((void));
251 Widget CreateMenuBar P((Menu *mb));
252 Widget CreateButtonBar P ((MenuItem *mi));
253 char *FindFont P((char *pattern, int targetPxlSize));
254 void PieceMenuPopup P((Widget w, XEvent *event,
255 String *params, Cardinal *num_params));
256 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
257 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
258 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
259 u_int wreq, u_int hreq));
260 void CreateGrid P((void));
261 int EventToSquare P((int x, int limit));
262 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
263 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
264 void HandleUserMove P((Widget w, XEvent *event,
265 String *prms, Cardinal *nprms));
266 void AnimateUserMove P((Widget w, XEvent * event,
267 String * params, Cardinal * nParams));
268 void HandlePV P((Widget w, XEvent * event,
269 String * params, Cardinal * nParams));
270 void SelectPV P((Widget w, XEvent * event,
271 String * params, Cardinal * nParams));
272 void StopPV P((Widget w, XEvent * event,
273 String * params, Cardinal * nParams));
274 void WhiteClock P((Widget w, XEvent *event,
275 String *prms, Cardinal *nprms));
276 void BlackClock P((Widget w, XEvent *event,
277 String *prms, Cardinal *nprms));
278 void DrawPositionProc P((Widget w, XEvent *event,
279 String *prms, Cardinal *nprms));
280 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
282 void CommentClick P((Widget w, XEvent * event,
283 String * params, Cardinal * nParams));
284 void CommentPopUp P((char *title, char *label));
285 void CommentPopDown P((void));
286 void CommentCallback P((Widget w, XtPointer client_data,
287 XtPointer call_data));
288 void ICSInputBoxPopUp P((void));
289 void ICSInputBoxPopDown P((void));
290 void FileNamePopUp P((char *label, char *def,
291 FileProc proc, char *openMode));
292 void FileNamePopDown P((void));
293 void FileNameCallback P((Widget w, XtPointer client_data,
294 XtPointer call_data));
295 void FileNameAction P((Widget w, XEvent *event,
296 String *prms, Cardinal *nprms));
297 void AskQuestionReplyAction P((Widget w, XEvent *event,
298 String *prms, Cardinal *nprms));
299 void AskQuestionProc P((Widget w, XEvent *event,
300 String *prms, Cardinal *nprms));
301 void AskQuestionPopDown P((void));
302 void PromotionPopDown P((void));
303 void PromotionCallback P((Widget w, XtPointer client_data,
304 XtPointer call_data));
305 void EditCommentPopDown P((void));
306 void EditCommentCallback P((Widget w, XtPointer client_data,
307 XtPointer call_data));
308 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
309 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
310 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
311 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
313 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
315 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
317 void LoadPositionProc P((Widget w, XEvent *event,
318 String *prms, Cardinal *nprms));
319 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
321 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
323 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
325 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
327 void PastePositionProc P((Widget w, XEvent *event, String *prms,
329 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
330 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
331 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
332 void SavePositionProc P((Widget w, XEvent *event,
333 String *prms, Cardinal *nprms));
334 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
335 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
337 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
338 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
339 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
341 void MachineWhiteProc P((Widget w, XEvent *event,
342 String *prms, Cardinal *nprms));
343 void AnalyzeModeProc P((Widget w, XEvent *event,
344 String *prms, Cardinal *nprms));
345 void AnalyzeFileProc P((Widget w, XEvent *event,
346 String *prms, Cardinal *nprms));
347 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
349 void IcsClientProc P((Widget w, XEvent *event, String *prms,
351 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
352 void EditPositionProc P((Widget w, XEvent *event,
353 String *prms, Cardinal *nprms));
354 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
355 void EditCommentProc P((Widget w, XEvent *event,
356 String *prms, Cardinal *nprms));
357 void IcsInputBoxProc P((Widget w, XEvent *event,
358 String *prms, Cardinal *nprms));
359 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
365 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
369 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
370 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
371 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
372 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
373 void StopObservingProc P((Widget w, XEvent *event, String *prms,
375 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
377 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
379 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
380 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
384 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
386 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
388 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
389 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
391 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
393 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
395 void AutocommProc P((Widget w, XEvent *event, String *prms,
397 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
398 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
399 void AutobsProc P((Widget w, XEvent *event, String *prms,
401 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
402 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
403 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
404 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
406 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
407 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
409 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
411 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
413 void HighlightArrowProc P((Widget w, XEvent *event, String *prms,
415 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
416 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
417 void OneClickProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
418 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
420 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
422 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
424 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
426 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
427 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
428 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
430 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
432 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
434 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
436 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
437 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
442 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
443 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
444 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
445 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
446 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
447 void DisplayMove P((int moveNumber));
448 void DisplayTitle P((char *title));
449 void ICSInitScript P((void));
450 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
451 void ErrorPopUp P((char *title, char *text, int modal));
452 void ErrorPopDown P((void));
453 static char *ExpandPathName P((char *path));
454 static void CreateAnimVars P((void));
455 static void DragPieceMove P((int x, int y));
456 static void DrawDragPiece P((void));
457 char *ModeToWidgetName P((GameMode mode));
458 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
459 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
460 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
461 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
462 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
463 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
464 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
465 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
466 void GameListOptionsPopDown P(());
467 void ShufflePopDown P(());
468 void EnginePopDown P(());
469 void UciPopDown P(());
470 void TimeControlPopDown P(());
471 void NewVariantPopDown P(());
472 void SettingsPopDown P(());
473 void update_ics_width P(());
474 int get_term_width P(());
475 int CopyMemoProc P(());
476 void DrawArrowHighlight P((int fromX, int fromY, int toX,int toY));
477 Boolean IsDrawArrowEnabled P(());
480 * XBoard depends on Xt R4 or higher
482 int xtVersion = XtSpecificationRelease;
487 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
488 jailSquareColor, highlightSquareColor, premoveHighlightColor;
489 Pixel lowTimeWarningColor;
490 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
491 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
492 wjPieceGC, bjPieceGC, prelineGC, countGC;
493 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
494 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
495 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
496 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
497 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
498 ICSInputShell, fileNameShell, askQuestionShell;
499 Widget historyShell, evalGraphShell, gameListShell;
500 int hOffset; // [HGM] dual
501 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
502 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
503 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
504 Font clockFontID, coordFontID, countFontID;
505 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
506 XtAppContext appContext;
508 char *oldICSInteractionTitle;
512 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
514 Position commentX = -1, commentY = -1;
515 Dimension commentW, commentH;
516 typedef unsigned int BoardSize;
518 Boolean chessProgram;
520 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
521 int squareSize, smallLayout = 0, tinyLayout = 0,
522 marginW, marginH, // [HGM] for run-time resizing
523 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
524 ICSInputBoxUp = False, askQuestionUp = False,
525 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
526 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
527 Pixel timerForegroundPixel, timerBackgroundPixel;
528 Pixel buttonForegroundPixel, buttonBackgroundPixel;
529 char *chessDir, *programName, *programVersion,
530 *gameCopyFilename, *gamePasteFilename;
531 Boolean alwaysOnTop = False;
532 Boolean saveSettingsOnExit;
533 char *settingsFileName;
534 char *icsTextMenuString;
536 char *firstChessProgramNames;
537 char *secondChessProgramNames;
539 WindowPlacement wpMain;
540 WindowPlacement wpConsole;
541 WindowPlacement wpComment;
542 WindowPlacement wpMoveHistory;
543 WindowPlacement wpEvalGraph;
544 WindowPlacement wpEngineOutput;
545 WindowPlacement wpGameList;
546 WindowPlacement wpTags;
550 Pixmap pieceBitmap[2][(int)BlackPawn];
551 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
552 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
553 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
554 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
555 Pixmap xpmBoardBitmap[2];
556 int useImages, useImageSqs, useTexture, textureW[2], textureH[2];
557 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
558 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
559 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
560 XImage *ximLightSquare, *ximDarkSquare;
563 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
564 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
566 #define White(piece) ((int)(piece) < (int)BlackPawn)
568 /* Variables for doing smooth animation. This whole thing
569 would be much easier if the board was double-buffered,
570 but that would require a fairly major rewrite. */
575 GC blitGC, pieceGC, outlineGC;
576 XPoint startSquare, prevFrame, mouseDelta;
580 int startBoardX, startBoardY;
583 /* There can be two pieces being animated at once: a player
584 can begin dragging a piece before the remote opponent has moved. */
586 static AnimState game, player;
588 /* Bitmaps for use as masks when drawing XPM pieces.
589 Need one for each black and white piece. */
590 static Pixmap xpmMask[BlackKing + 1];
592 /* This magic number is the number of intermediate frames used
593 in each half of the animation. For short moves it's reduced
594 by 1. The total number of frames will be factor * 2 + 1. */
597 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
599 MenuItem fileMenu[] = {
600 {N_("New Game Ctrl+N"), "New Game", ResetProc},
601 {N_("New Shuffle Game ..."), "New Shuffle Game", ShuffleMenuProc},
602 {N_("New Variant ... Alt+Shift+V"), "New Variant", NewVariantProc}, // [HGM] variant: not functional yet
603 {"----", NULL, NothingProc},
604 {N_("Load Game Ctrl+O"), "Load Game", LoadGameProc},
605 {N_("Load Position Ctrl+Shift+O"), "Load Position", LoadPositionProc},
606 // {N_("Load Next Game"), "Load Next Game", LoadNextGameProc},
607 // {N_("Load Previous Game"), "Load Previous Game", LoadPrevGameProc},
608 // {N_("Reload Same Game"), "Reload Same Game", ReloadGameProc},
609 {"----", NULL, NothingProc},
610 // {N_("Load Next Position"), "Load Next Position", LoadNextPositionProc},
611 // {N_("Load Previous Position"), "Load Previous Position", LoadPrevPositionProc},
612 // {N_("Reload Same Position"), "Reload Same Position", ReloadPositionProc},
613 {N_("Save Game Ctrl+S"), "Save Game", SaveGameProc},
614 {N_("Save Position Ctrl+Shift+S"), "Save Position", SavePositionProc},
615 {"----", NULL, NothingProc},
616 {N_("Mail Move"), "Mail Move", MailMoveProc},
617 {N_("Reload CMail Message"), "Reload CMail Message", ReloadCmailMsgProc},
618 {"----", NULL, NothingProc},
619 {N_("Quit Ctr+Q"), "Exit", QuitProc},
623 MenuItem editMenu[] = {
624 {N_("Copy Game Ctrl+C"), "Copy Game", CopyGameProc},
625 {N_("Copy Position Ctrl+Shift+C"), "Copy Position", CopyPositionProc},
626 {"----", NULL, NothingProc},
627 {N_("Paste Game Ctrl+V"), "Paste Game", PasteGameProc},
628 {N_("Paste Position Ctrl+Shift+V"), "Paste Position", PastePositionProc},
629 {"----", NULL, NothingProc},
630 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
631 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
632 {N_("Edit Tags"), "Edit Tags", EditTagsProc},
633 {N_("Edit Comment"), "Edit Comment", EditCommentProc},
634 {"----", NULL, NothingProc},
635 {N_("Revert Home"), "Revert", RevertProc},
636 {N_("Annotate"), "Annotate", AnnotateProc},
637 {N_("Truncate Game End"), "Truncate Game", TruncateGameProc},
638 {"----", NULL, NothingProc},
639 {N_("Backward Alt+Left"), "Backward", BackwardProc},
640 {N_("Forward Alt+Right"), "Forward", ForwardProc},
641 {N_("Back to Start Alt+Home"), "Back to Start", ToStartProc},
642 {N_("Forward to End Alt+End"), "Forward to End", ToEndProc},
646 MenuItem viewMenu[] = {
647 {N_("Flip View F2"), "Flip View", FlipViewProc},
648 {"----", NULL, NothingProc},
649 {N_("Engine Output Alt+Shift+O"), "Show Engine Output", EngineOutputProc},
650 {N_("Move History Alt+Shift+H"), "Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
651 {N_("Evaluation Graph Alt+Shift+E"), "Show Evaluation Graph", EvalGraphProc},
652 {N_("Game List Alt+Shift+G"), "Show Game List", ShowGameListProc},
653 {"----", NULL, NothingProc},
654 {N_("Tags"), "Show Tags", EditTagsProc},
655 {N_("Comments"), "Show Comments", EditCommentProc},
656 {N_("ICS Input Box"), "ICS Input Box", IcsInputBoxProc},
660 MenuItem modeMenu[] = {
661 {N_("Machine White Ctrl+W"), "Machine White", MachineWhiteProc},
662 {N_("Machine Black Ctrl+B"), "Machine Black", MachineBlackProc},
663 {N_("Two Machines Ctrl+T"), "Two Machines", TwoMachinesProc},
664 {N_("Analysis Mode Ctrl+A"), "Analysis Mode", AnalyzeModeProc},
665 {N_("Analyze File Ctrl+F"), "Analyze File", AnalyzeFileProc },
666 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
667 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
668 {N_("Training"), "Training", TrainingProc},
669 {N_("ICS Client"), "ICS Client", IcsClientProc},
670 {"----", NULL, NothingProc},
671 {N_("Pause Pause"), "Pause", PauseProc},
675 MenuItem actionMenu[] = {
676 {N_("Accept F3"), "Accept", AcceptProc},
677 {N_("Decline F4"), "Decline", DeclineProc},
678 {N_("Rematch F12"), "Rematch", RematchProc},
679 {"----", NULL, NothingProc},
680 {N_("Call Flag F5"), "Call Flag", CallFlagProc},
681 {N_("Draw F6"), "Draw", DrawProc},
682 {N_("Adjourn F7"), "Adjourn", AdjournProc},
683 {N_("Abort F8"),"Abort", AbortProc},
684 {N_("Resign F9"), "Resign", ResignProc},
685 {"----", NULL, NothingProc},
686 {N_("Stop Observing F10"), "Stop Observing", StopObservingProc},
687 {N_("Stop Examining F11"), "Stop Examining", StopExaminingProc},
688 {N_("Upload to Examine"), "Upload to Examine", UploadProc},
689 {"----", NULL, NothingProc},
690 {N_("Adjudicate to White"), "Adjudicate to White", AdjuWhiteProc},
691 {N_("Adjudicate to Black"), "Adjudicate to Black", AdjuBlackProc},
692 {N_("Adjudicate Draw"), "Adjudicate Draw", AdjuDrawProc},
696 MenuItem engineMenu[] = {
697 {N_("Engine #1 Settings ..."), "Engine #1 Settings", FirstSettingsProc},
698 {N_("Engine #2 Settings ..."), "Engine #2 Settings", SecondSettingsProc},
699 {"----", NULL, NothingProc},
700 {N_("Hint"), "Hint", HintProc},
701 {N_("Book"), "Book", BookProc},
702 {"----", NULL, NothingProc},
703 {N_("Move Now Ctrl+M"), "Move Now", MoveNowProc},
704 {N_("Retract Move Ctrl+X"), "Retract Move", RetractMoveProc},
708 MenuItem optionsMenu[] = {
709 {N_("Time Control ... Alt+Shift+T"), "Time Control", TimeControlProc},
710 {N_("Common Engine ... Alt+Shift+U"), "Common Engine", UciMenuProc},
711 {N_("Adjudications ... Alt+Shift+J"), "Adjudications", EngineMenuProc},
712 {N_("Game List ..."), "Game List", GameListOptionsPopUp},
713 {"----", NULL, NothingProc},
714 {N_("Always Queen Ctrl+Shift+Q"), "Always Queen", AlwaysQueenProc},
715 {N_("Animate Dragging"), "Animate Dragging", AnimateDraggingProc},
716 {N_("Animate Moving Ctrl+Shift+A"), "Animate Moving", AnimateMovingProc},
717 {N_("Auto Comment"), "Auto Comment", AutocommProc},
718 {N_("Auto Flag Ctrl+Shift+F"), "Auto Flag", AutoflagProc},
719 {N_("Auto Flip View"), "Auto Flip View", AutoflipProc},
720 {N_("Auto Observe"), "Auto Observe", AutobsProc},
721 {N_("Auto Raise Board"), "Auto Raise Board", AutoraiseProc},
722 {N_("Auto Save"), "Auto Save", AutosaveProc},
723 {N_("Blindfold"), "Blindfold", BlindfoldProc},
724 {N_("Flash Moves"), "Flash Moves", FlashMovesProc},
725 {N_("Get Move List"), "Get Move List", GetMoveListProc},
727 {N_("Highlight Dragging"), "Highlight Dragging", HighlightDraggingProc},
729 {N_("Highlight Last Move"), "Highlight Last Move", HighlightLastMoveProc},
730 {N_("Highlight With Arrow"), "Arrow", HighlightArrowProc},
731 {N_("Move Sound"), "Move Sound", MoveSoundProc},
732 {N_("ICS Alarm"), "ICS Alarm", IcsAlarmProc},
733 {N_("One-Click Moving"), "OneClick", OneClickProc},
734 {N_("Periodic Updates"), "Periodic Updates", PeriodicUpdatesProc},
735 {N_("Ponder Next Move Ctrl+Shift+P"), "Ponder Next Move", PonderNextMoveProc},
736 {N_("Popup Exit Message"), "Popup Exit Message", PopupExitMessageProc},
737 {N_("Popup Move Errors"), "Popup Move Errors", PopupMoveErrorsProc},
738 {N_("Premove"), "Premove", PremoveProc},
739 {N_("Quiet Play"), "Quiet Play", QuietPlayProc},
740 {N_("Show Coords"), "Show Coords", ShowCoordsProc},
741 {N_("Hide Thinking Ctrl+Shift+H"), "Hide Thinking", HideThinkingProc},
742 {N_("Test Legality Ctrl+Shift+L"), "Test Legality", TestLegalityProc},
743 {"----", NULL, NothingProc},
744 {N_("Save Settings Now"), "Save Settings Now", SaveSettingsProc},
745 {N_("Save Settings on Exit"), "Save Settings on Exit", SaveOnExitProc},
749 MenuItem helpMenu[] = {
750 {N_("Info XBoard"), "Info XBoard", InfoProc},
751 {N_("Man XBoard F1"), "Man XBoard", ManProc},
752 {"----", NULL, NothingProc},
753 {N_("About XBoard"), "About XBoard", AboutProc},
758 {N_("File"), "File", fileMenu},
759 {N_("Edit"), "Edit", editMenu},
760 {N_("View"), "View", viewMenu},
761 {N_("Mode"), "Mode", modeMenu},
762 {N_("Action"), "Action", actionMenu},
763 {N_("Engine"), "Engine", engineMenu},
764 {N_("Options"), "Options", optionsMenu},
765 {N_("Help"), "Help", helpMenu},
769 #define PAUSE_BUTTON "P"
770 MenuItem buttonBar[] = {
771 {"<<", "<<", ToStartProc},
772 {"<", "<", BackwardProc},
773 {PAUSE_BUTTON, PAUSE_BUTTON, PauseProc},
774 {">", ">", ForwardProc},
775 {">>", ">>", ToEndProc},
779 #define PIECE_MENU_SIZE 18
780 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
781 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
782 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
783 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
784 N_("Empty square"), N_("Clear board") },
785 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
786 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
787 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
788 N_("Empty square"), N_("Clear board") }
790 /* must be in same order as PieceMenuStrings! */
791 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
792 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
793 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
794 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
795 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
796 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
797 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
798 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
799 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
802 #define DROP_MENU_SIZE 6
803 String dropMenuStrings[DROP_MENU_SIZE] = {
804 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
806 /* must be in same order as PieceMenuStrings! */
807 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
808 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
809 WhiteRook, WhiteQueen
817 DropMenuEnables dmEnables[] = {
835 { XtNborderWidth, 0 },
836 { XtNdefaultDistance, 0 },
840 { XtNborderWidth, 0 },
841 { XtNresizable, (XtArgVal) True },
845 { XtNborderWidth, 0 },
851 { XtNjustify, (XtArgVal) XtJustifyRight },
852 { XtNlabel, (XtArgVal) "..." },
853 { XtNresizable, (XtArgVal) True },
854 { XtNresize, (XtArgVal) False }
857 Arg messageArgs[] = {
858 { XtNjustify, (XtArgVal) XtJustifyLeft },
859 { XtNlabel, (XtArgVal) "..." },
860 { XtNresizable, (XtArgVal) True },
861 { XtNresize, (XtArgVal) False }
865 { XtNborderWidth, 0 },
866 { XtNjustify, (XtArgVal) XtJustifyLeft }
869 XtResource clientResources[] = {
870 { "flashCount", "flashCount", XtRInt, sizeof(int),
871 XtOffset(AppDataPtr, flashCount), XtRImmediate,
872 (XtPointer) FLASH_COUNT },
875 XrmOptionDescRec shellOptions[] = {
876 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
877 { "-flash", "flashCount", XrmoptionNoArg, "3" },
878 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
881 XtActionsRec boardActions[] = {
882 { "DrawPosition", DrawPositionProc },
883 { "HandleUserMove", HandleUserMove },
884 { "AnimateUserMove", AnimateUserMove },
885 { "HandlePV", HandlePV },
886 { "SelectPV", SelectPV },
887 { "StopPV", StopPV },
888 { "FileNameAction", FileNameAction },
889 { "AskQuestionProc", AskQuestionProc },
890 { "AskQuestionReplyAction", AskQuestionReplyAction },
891 { "PieceMenuPopup", PieceMenuPopup },
892 { "WhiteClock", WhiteClock },
893 { "BlackClock", BlackClock },
894 { "Iconify", Iconify },
895 { "ResetProc", ResetProc },
896 { "NewVariantProc", NewVariantProc },
897 { "LoadGameProc", LoadGameProc },
898 { "LoadNextGameProc", LoadNextGameProc },
899 { "LoadPrevGameProc", LoadPrevGameProc },
900 { "LoadSelectedProc", LoadSelectedProc },
901 { "SetFilterProc", SetFilterProc },
902 { "ReloadGameProc", ReloadGameProc },
903 { "LoadPositionProc", LoadPositionProc },
904 { "LoadNextPositionProc", LoadNextPositionProc },
905 { "LoadPrevPositionProc", LoadPrevPositionProc },
906 { "ReloadPositionProc", ReloadPositionProc },
907 { "CopyPositionProc", CopyPositionProc },
908 { "PastePositionProc", PastePositionProc },
909 { "CopyGameProc", CopyGameProc },
910 { "PasteGameProc", PasteGameProc },
911 { "SaveGameProc", SaveGameProc },
912 { "SavePositionProc", SavePositionProc },
913 { "MailMoveProc", MailMoveProc },
914 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
915 { "QuitProc", QuitProc },
916 { "MachineWhiteProc", MachineWhiteProc },
917 { "MachineBlackProc", MachineBlackProc },
918 { "AnalysisModeProc", AnalyzeModeProc },
919 { "AnalyzeFileProc", AnalyzeFileProc },
920 { "TwoMachinesProc", TwoMachinesProc },
921 { "IcsClientProc", IcsClientProc },
922 { "EditGameProc", EditGameProc },
923 { "EditPositionProc", EditPositionProc },
924 { "TrainingProc", EditPositionProc },
925 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
926 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
927 { "ShowGameListProc", ShowGameListProc },
928 { "ShowMoveListProc", HistoryShowProc},
929 { "EditTagsProc", EditCommentProc },
930 { "EditCommentProc", EditCommentProc },
931 { "IcsAlarmProc", IcsAlarmProc },
932 { "IcsInputBoxProc", IcsInputBoxProc },
933 { "PauseProc", PauseProc },
934 { "AcceptProc", AcceptProc },
935 { "DeclineProc", DeclineProc },
936 { "RematchProc", RematchProc },
937 { "CallFlagProc", CallFlagProc },
938 { "DrawProc", DrawProc },
939 { "AdjournProc", AdjournProc },
940 { "AbortProc", AbortProc },
941 { "ResignProc", ResignProc },
942 { "AdjuWhiteProc", AdjuWhiteProc },
943 { "AdjuBlackProc", AdjuBlackProc },
944 { "AdjuDrawProc", AdjuDrawProc },
945 { "EnterKeyProc", EnterKeyProc },
946 { "UpKeyProc", UpKeyProc },
947 { "DownKeyProc", DownKeyProc },
948 { "StopObservingProc", StopObservingProc },
949 { "StopExaminingProc", StopExaminingProc },
950 { "UploadProc", UploadProc },
951 { "BackwardProc", BackwardProc },
952 { "ForwardProc", ForwardProc },
953 { "ToStartProc", ToStartProc },
954 { "ToEndProc", ToEndProc },
955 { "RevertProc", RevertProc },
956 { "AnnotateProc", AnnotateProc },
957 { "TruncateGameProc", TruncateGameProc },
958 { "MoveNowProc", MoveNowProc },
959 { "RetractMoveProc", RetractMoveProc },
960 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
961 { "UciMenuProc", (XtActionProc) UciMenuProc },
962 { "TimeControlProc", (XtActionProc) TimeControlProc },
963 { "AlwaysQueenProc", AlwaysQueenProc },
964 { "AnimateDraggingProc", AnimateDraggingProc },
965 { "AnimateMovingProc", AnimateMovingProc },
966 { "AutoflagProc", AutoflagProc },
967 { "AutoflipProc", AutoflipProc },
968 { "AutobsProc", AutobsProc },
969 { "AutoraiseProc", AutoraiseProc },
970 { "AutosaveProc", AutosaveProc },
971 { "BlindfoldProc", BlindfoldProc },
972 { "FlashMovesProc", FlashMovesProc },
973 { "FlipViewProc", FlipViewProc },
974 { "GetMoveListProc", GetMoveListProc },
976 { "HighlightDraggingProc", HighlightDraggingProc },
978 { "HighlightLastMoveProc", HighlightLastMoveProc },
979 { "IcsAlarmProc", IcsAlarmProc },
980 { "MoveSoundProc", MoveSoundProc },
981 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
982 { "PonderNextMoveProc", PonderNextMoveProc },
983 { "PopupExitMessageProc", PopupExitMessageProc },
984 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
985 { "PremoveProc", PremoveProc },
986 { "QuietPlayProc", QuietPlayProc },
987 { "ShowCoordsProc", ShowCoordsProc },
988 { "ShowThinkingProc", ShowThinkingProc },
989 { "HideThinkingProc", HideThinkingProc },
990 { "TestLegalityProc", TestLegalityProc },
991 { "SaveSettingsProc", SaveSettingsProc },
992 { "SaveOnExitProc", SaveOnExitProc },
993 { "InfoProc", InfoProc },
994 { "ManProc", ManProc },
995 { "HintProc", HintProc },
996 { "BookProc", BookProc },
997 { "AboutGameProc", AboutGameProc },
998 { "AboutProc", AboutProc },
999 { "DebugProc", DebugProc },
1000 { "NothingProc", NothingProc },
1001 { "CommentClick", (XtActionProc) CommentClick },
1002 { "CommentPopDown", (XtActionProc) CommentPopDown },
1003 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
1004 { "TagsPopDown", (XtActionProc) TagsPopDown },
1005 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
1006 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
1007 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
1008 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
1009 { "GameListPopDown", (XtActionProc) GameListPopDown },
1010 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
1011 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1012 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
1013 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1014 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1015 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
1016 { "EnginePopDown", (XtActionProc) EnginePopDown },
1017 { "UciPopDown", (XtActionProc) UciPopDown },
1018 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
1019 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
1020 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
1021 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1024 char globalTranslations[] =
1025 ":<Key>F9: ResignProc() \n \
1026 :Ctrl<Key>n: ResetProc() \n \
1027 :Meta<Key>V: NewVariantProc() \n \
1028 :Ctrl<Key>o: LoadGameProc() \n \
1029 :Meta<Key>Next: LoadNextGameProc() \n \
1030 :Meta<Key>Prior: LoadPrevGameProc() \n \
1031 :Ctrl<Key>s: SaveGameProc() \n \
1032 :Ctrl<Key>c: CopyGameProc() \n \
1033 :Ctrl<Key>v: PasteGameProc() \n \
1034 :Ctrl<Key>O: LoadPositionProc() \n \
1035 :Shift Meta<Key>Next: LoadNextPositionProc() \n \
1036 :Shift Meta<Key>Prior: LoadPrevPositionProc() \n \
1037 :Ctrl<Key>S: SavePositionProc() \n \
1038 :Ctrl<Key>C: CopyPositionProc() \n \
1039 :Ctrl<Key>V: PastePositionProc() \n \
1040 :Ctrl<Key>q: QuitProc() \n \
1041 :Ctrl<Key>w: MachineWhiteProc() \n \
1042 :Ctrl<Key>b: MachineBlackProc() \n \
1043 :Ctrl<Key>t: TwoMachinesProc() \n \
1044 :Ctrl<Key>a: AnalysisModeProc() \n \
1045 :Ctrl<Key>f: AnalyzeFileProc() \n \
1046 :Ctrl<Key>e: EditGameProc() \n \
1047 :Ctrl<Key>E: EditPositionProc() \n \
1048 :Meta<Key>O: EngineOutputProc() \n \
1049 :Meta<Key>E: EvalGraphProc() \n \
1050 :Meta<Key>G: ShowGameListProc() \n \
1051 :Meta<Key>H: ShowMoveListProc() \n \
1052 :<Key>Pause: PauseProc() \n \
1053 :<Key>F3: AcceptProc() \n \
1054 :<Key>F4: DeclineProc() \n \
1055 :<Key>F12: RematchProc() \n \
1056 :<Key>F5: CallFlagProc() \n \
1057 :<Key>F6: DrawProc() \n \
1058 :<Key>F7: AdjournProc() \n \
1059 :<Key>F8: AbortProc() \n \
1060 :<Key>F10: StopObservingProc() \n \
1061 :<Key>F11: StopExaminingProc() \n \
1062 :Meta Ctrl<Key>F12: DebugProc() \n \
1063 :Meta<Key>End: ToEndProc() \n \
1064 :Meta<Key>Right: ForwardProc() \n \
1065 :Meta<Key>Home: ToStartProc() \n \
1066 :Meta<Key>Left: BackwardProc() \n \
1067 :<Key>Home: RevertProc() \n \
1068 :<Key>End: TruncateGameProc() \n \
1069 :Ctrl<Key>m: MoveNowProc() \n \
1070 :Ctrl<Key>x: RetractMoveProc() \n \
1071 :Meta<Key>J: EngineMenuProc() \n \
1072 :Meta<Key>U: UciMenuProc() \n \
1073 :Meta<Key>T: TimeControlProc() \n \
1074 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1075 :Ctrl<Key>F: AutoflagProc() \n \
1076 :Ctrl<Key>A: AnimateMovingProc() \n \
1077 :Ctrl<Key>P: PonderNextMoveProc() \n \
1078 :Ctrl<Key>L: TestLegalityProc() \n \
1079 :Ctrl<Key>H: HideThinkingProc() \n \
1080 :<Key>-: Iconify() \n \
1081 :<Key>F1: ManProc() \n \
1082 :<Key>F2: FlipViewProc() \n \
1083 <KeyDown>.: BackwardProc() \n \
1084 <KeyUp>.: ForwardProc() \n \
1085 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1086 \"Send to chess program:\",,1) \n \
1087 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1088 \"Send to second chess program:\",,2) \n";
1090 char boardTranslations[] =
1091 "<Btn1Down>: HandleUserMove(0) \n \
1092 Shift<Btn1Up>: HandleUserMove(1) \n \
1093 <Btn1Up>: HandleUserMove(0) \n \
1094 <Btn1Motion>: AnimateUserMove() \n \
1095 <Btn3Motion>: HandlePV() \n \
1096 <Btn3Up>: PieceMenuPopup(menuB) \n \
1097 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1098 PieceMenuPopup(menuB) \n \
1099 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1100 PieceMenuPopup(menuW) \n \
1101 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1102 PieceMenuPopup(menuW) \n \
1103 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1104 PieceMenuPopup(menuB) \n";
1106 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1107 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1109 char ICSInputTranslations[] =
1110 "<Key>Up: UpKeyProc() \n "
1111 "<Key>Down: DownKeyProc() \n "
1112 "<Key>Return: EnterKeyProc() \n";
1114 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1115 // as the widget is destroyed before the up-click can call extend-end
1116 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1118 String xboardResources[] = {
1119 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1120 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1121 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1126 /* Max possible square size */
1127 #define MAXSQSIZE 256
1129 static int xpm_avail[MAXSQSIZE];
1131 #ifdef HAVE_DIR_STRUCT
1133 /* Extract piece size from filename */
1135 xpm_getsize(name, len, ext)
1146 if ((p=strchr(name, '.')) == NULL ||
1147 StrCaseCmp(p+1, ext) != 0)
1153 while (*p && isdigit(*p))
1160 /* Setup xpm_avail */
1162 xpm_getavail(dirname, ext)
1170 for (i=0; i<MAXSQSIZE; ++i)
1173 if (appData.debugMode)
1174 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1176 dir = opendir(dirname);
1179 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1180 programName, dirname);
1184 while ((ent=readdir(dir)) != NULL) {
1185 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1186 if (i > 0 && i < MAXSQSIZE)
1196 xpm_print_avail(fp, ext)
1202 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1203 for (i=1; i<MAXSQSIZE; ++i) {
1209 /* Return XPM piecesize closest to size */
1211 xpm_closest_to(dirname, size, ext)
1217 int sm_diff = MAXSQSIZE;
1221 xpm_getavail(dirname, ext);
1223 if (appData.debugMode)
1224 xpm_print_avail(stderr, ext);
1226 for (i=1; i<MAXSQSIZE; ++i) {
1229 diff = (diff<0) ? -diff : diff;
1230 if (diff < sm_diff) {
1238 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1244 #else /* !HAVE_DIR_STRUCT */
1245 /* If we are on a system without a DIR struct, we can't
1246 read the directory, so we can't collect a list of
1247 filenames, etc., so we can't do any size-fitting. */
1249 xpm_closest_to(dirname, size, ext)
1254 fprintf(stderr, _("\
1255 Warning: No DIR structure found on this system --\n\
1256 Unable to autosize for XPM/XIM pieces.\n\
1257 Please report this error to frankm@hiwaay.net.\n\
1258 Include system type & operating system in message.\n"));
1261 #endif /* HAVE_DIR_STRUCT */
1263 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1264 "magenta", "cyan", "white" };
1268 TextColors textColors[(int)NColorClasses];
1270 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1272 parse_color(str, which)
1276 char *p, buf[100], *d;
1279 if (strlen(str) > 99) /* watch bounds on buf */
1284 for (i=0; i<which; ++i) {
1291 /* Could be looking at something like:
1293 .. in which case we want to stop on a comma also */
1294 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1298 return -1; /* Use default for empty field */
1301 if (which == 2 || isdigit(*p))
1304 while (*p && isalpha(*p))
1309 for (i=0; i<8; ++i) {
1310 if (!StrCaseCmp(buf, cnames[i]))
1311 return which? (i+40) : (i+30);
1313 if (!StrCaseCmp(buf, "default")) return -1;
1315 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1320 parse_cpair(cc, str)
1324 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1325 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1330 /* bg and attr are optional */
1331 textColors[(int)cc].bg = parse_color(str, 1);
1332 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1333 textColors[(int)cc].attr = 0;
1339 /* Arrange to catch delete-window events */
1340 Atom wm_delete_window;
1342 CatchDeleteWindow(Widget w, String procname)
1345 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1346 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1347 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1354 XtSetArg(args[0], XtNiconic, False);
1355 XtSetValues(shellWidget, args, 1);
1357 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1360 //---------------------------------------------------------------------------------------------------------
1361 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1364 #define CW_USEDEFAULT (1<<31)
1365 #define ICS_TEXT_MENU_SIZE 90
1366 #define DEBUG_FILE "xboard.debug"
1367 #define SetCurrentDirectory chdir
1368 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1372 // these two must some day move to frontend.h, when they are implemented
1373 Boolean GameListIsUp();
1375 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1378 // front-end part of option handling
1380 // [HGM] This platform-dependent table provides the location for storing the color info
1381 extern char *crWhite, * crBlack;
1385 &appData.whitePieceColor,
1386 &appData.blackPieceColor,
1387 &appData.lightSquareColor,
1388 &appData.darkSquareColor,
1389 &appData.highlightSquareColor,
1390 &appData.premoveHighlightColor,
1391 &appData.lowTimeWarningColor,
1402 // [HGM] font: keep a font for each square size, even non-stndard ones
1403 #define NUM_SIZES 18
1404 #define MAX_SIZE 130
1405 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1406 char *fontTable[NUM_FONTS][MAX_SIZE];
1409 ParseFont(char *name, int number)
1410 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1412 if(sscanf(name, "size%d:", &size)) {
1413 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1414 // defer processing it until we know if it matches our board size
1415 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1416 fontTable[number][size] = strdup(strchr(name, ':')+1);
1417 fontValid[number][size] = True;
1422 case 0: // CLOCK_FONT
1423 appData.clockFont = strdup(name);
1425 case 1: // MESSAGE_FONT
1426 appData.font = strdup(name);
1428 case 2: // COORD_FONT
1429 appData.coordFont = strdup(name);
1434 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1439 { // only 2 fonts currently
1440 appData.clockFont = CLOCK_FONT_NAME;
1441 appData.coordFont = COORD_FONT_NAME;
1442 appData.font = DEFAULT_FONT_NAME;
1447 { // no-op, until we identify the code for this already in XBoard and move it here
1451 ParseColor(int n, char *name)
1452 { // in XBoard, just copy the color-name string
1453 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1457 ParseTextAttribs(ColorClass cc, char *s)
1459 (&appData.colorShout)[cc] = strdup(s);
1463 ParseBoardSize(void *addr, char *name)
1465 appData.boardSize = strdup(name);
1470 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1474 SetCommPortDefaults()
1475 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1478 // [HGM] args: these three cases taken out to stay in front-end
1480 SaveFontArg(FILE *f, ArgDescriptor *ad)
1483 int i, n = (int)ad->argLoc;
1485 case 0: // CLOCK_FONT
1486 name = appData.clockFont;
1488 case 1: // MESSAGE_FONT
1489 name = appData.font;
1491 case 2: // COORD_FONT
1492 name = appData.coordFont;
1497 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1498 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1499 fontTable[n][squareSize] = strdup(name);
1500 fontValid[n][squareSize] = True;
1503 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1504 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1509 { // nothing to do, as the sounds are at all times represented by their text-string names already
1513 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1514 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1515 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1519 SaveColor(FILE *f, ArgDescriptor *ad)
1520 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1521 if(colorVariable[(int)ad->argLoc])
1522 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1526 SaveBoardSize(FILE *f, char *name, void *addr)
1527 { // wrapper to shield back-end from BoardSize & sizeInfo
1528 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1532 ParseCommPortSettings(char *s)
1533 { // no such option in XBoard (yet)
1536 extern Widget engineOutputShell;
1537 extern Widget tagsShell, editTagsShell;
1539 GetActualPlacement(Widget wg, WindowPlacement *wp)
1549 XtSetArg(args[i], XtNx, &x); i++;
1550 XtSetArg(args[i], XtNy, &y); i++;
1551 XtSetArg(args[i], XtNwidth, &w); i++;
1552 XtSetArg(args[i], XtNheight, &h); i++;
1553 XtGetValues(wg, args, i);
1562 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1563 // In XBoard this will have to wait until awareness of window parameters is implemented
1564 GetActualPlacement(shellWidget, &wpMain);
1565 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1566 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1567 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1568 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1569 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1570 else GetActualPlacement(editShell, &wpComment);
1571 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1572 else GetActualPlacement(editTagsShell, &wpTags);
1576 PrintCommPortSettings(FILE *f, char *name)
1577 { // This option does not exist in XBoard
1581 MySearchPath(char *installDir, char *name, char *fullname)
1582 { // just append installDir and name. Perhaps ExpandPath should be used here?
1583 name = ExpandPathName(name);
1584 if(name && name[0] == '/')
1585 safeStrCpy(fullname, name, MSG_SIZ );
1587 sprintf(fullname, "%s%c%s", installDir, '/', name);
1593 MyGetFullPathName(char *name, char *fullname)
1594 { // should use ExpandPath?
1595 name = ExpandPathName(name);
1596 safeStrCpy(fullname, name, MSG_SIZ );
1601 EnsureOnScreen(int *x, int *y, int minX, int minY)
1608 { // [HGM] args: allows testing if main window is realized from back-end
1609 return xBoardWindow != 0;
1613 PopUpStartupDialog()
1614 { // start menu not implemented in XBoard
1618 ConvertToLine(int argc, char **argv)
1620 static char line[128*1024], buf[1024];
1624 for(i=1; i<argc; i++)
1626 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1627 && argv[i][0] != '{' )
1628 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1630 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1631 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1634 line[strlen(line)-1] = NULLCHAR;
1638 //--------------------------------------------------------------------------------------------
1640 extern Boolean twoBoards, partnerUp;
1643 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1645 #define BoardSize int
1646 void InitDrawingSizes(BoardSize boardSize, int flags)
1647 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1648 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1650 XtGeometryResult gres;
1653 if(!formWidget) return;
1656 * Enable shell resizing.
1658 shellArgs[0].value = (XtArgVal) &w;
1659 shellArgs[1].value = (XtArgVal) &h;
1660 XtGetValues(shellWidget, shellArgs, 2);
1662 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1663 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1664 XtSetValues(shellWidget, &shellArgs[2], 4);
1666 XtSetArg(args[0], XtNdefaultDistance, &sep);
1667 XtGetValues(formWidget, args, 1);
1669 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1670 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1672 hOffset = boardWidth + 10;
1673 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1674 secondSegments[i] = gridSegments[i];
1675 secondSegments[i].x1 += hOffset;
1676 secondSegments[i].x2 += hOffset;
1679 XtSetArg(args[0], XtNwidth, boardWidth);
1680 XtSetArg(args[1], XtNheight, boardHeight);
1681 XtSetValues(boardWidget, args, 2);
1683 timerWidth = (boardWidth - sep) / 2;
1684 XtSetArg(args[0], XtNwidth, timerWidth);
1685 XtSetValues(whiteTimerWidget, args, 1);
1686 XtSetValues(blackTimerWidget, args, 1);
1688 XawFormDoLayout(formWidget, False);
1690 if (appData.titleInWindow) {
1692 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1693 XtSetArg(args[i], XtNheight, &h); i++;
1694 XtGetValues(titleWidget, args, i);
1696 w = boardWidth - 2*bor;
1698 XtSetArg(args[0], XtNwidth, &w);
1699 XtGetValues(menuBarWidget, args, 1);
1700 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1703 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1704 if (gres != XtGeometryYes && appData.debugMode) {
1706 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1707 programName, gres, w, h, wr, hr);
1711 XawFormDoLayout(formWidget, True);
1714 * Inhibit shell resizing.
1716 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1717 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1718 shellArgs[4].value = shellArgs[2].value = w;
1719 shellArgs[5].value = shellArgs[3].value = h;
1720 XtSetValues(shellWidget, &shellArgs[0], 6);
1722 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1725 for(i=0; i<4; i++) {
1727 for(p=0; p<=(int)WhiteKing; p++)
1728 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1729 if(gameInfo.variant == VariantShogi) {
1730 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1731 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1732 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1733 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1734 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1737 if(gameInfo.variant == VariantGothic) {
1738 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1741 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1742 xpmPieceBitmap[i][(int)WhiteAngel] = xpmPieceBitmap2[i][(int)WhiteFalcon];
1743 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1746 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1747 for(p=0; p<=(int)WhiteKing; p++)
1748 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1749 if(gameInfo.variant == VariantShogi) {
1750 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1751 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1752 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1753 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1754 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1757 if(gameInfo.variant == VariantGothic) {
1758 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1761 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1762 ximMaskPm[(int)WhiteAngel] = ximMaskPm2[(int)WhiteFalcon];
1763 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1768 for(i=0; i<2; i++) {
1770 for(p=0; p<=(int)WhiteKing; p++)
1771 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1772 if(gameInfo.variant == VariantShogi) {
1773 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1774 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1775 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1776 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1777 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1780 if(gameInfo.variant == VariantGothic) {
1781 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1784 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1785 pieceBitmap[i][(int)WhiteAngel] = pieceBitmap2[i][(int)WhiteFalcon];
1786 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1801 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1802 XSetWindowAttributes window_attributes;
1804 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1805 XrmValue vFrom, vTo;
1806 XtGeometryResult gres;
1809 int forceMono = False;
1811 srandom(time(0)); // [HGM] book: make random truly random
1813 setbuf(stdout, NULL);
1814 setbuf(stderr, NULL);
1817 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1818 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1822 programName = strrchr(argv[0], '/');
1823 if (programName == NULL)
1824 programName = argv[0];
1829 XtSetLanguageProc(NULL, NULL, NULL);
1830 bindtextdomain(PACKAGE, LOCALEDIR);
1831 textdomain(PACKAGE);
1835 XtAppInitialize(&appContext, "XBoard", shellOptions,
1836 XtNumber(shellOptions),
1837 &argc, argv, xboardResources, NULL, 0);
1838 appData.boardSize = "";
1839 InitAppData(ConvertToLine(argc, argv));
1841 if (p == NULL) p = "/tmp";
1842 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1843 gameCopyFilename = (char*) malloc(i);
1844 gamePasteFilename = (char*) malloc(i);
1845 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1846 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1848 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1849 clientResources, XtNumber(clientResources),
1852 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1853 static char buf[MSG_SIZ];
1854 EscapeExpand(buf, appData.initString);
1855 appData.initString = strdup(buf);
1856 EscapeExpand(buf, appData.secondInitString);
1857 appData.secondInitString = strdup(buf);
1858 EscapeExpand(buf, appData.firstComputerString);
1859 appData.firstComputerString = strdup(buf);
1860 EscapeExpand(buf, appData.secondComputerString);
1861 appData.secondComputerString = strdup(buf);
1864 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1867 if (chdir(chessDir) != 0) {
1868 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1874 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1875 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1876 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1877 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1880 setbuf(debugFP, NULL);
1883 /* [HGM,HR] make sure board size is acceptable */
1884 if(appData.NrFiles > BOARD_FILES ||
1885 appData.NrRanks > BOARD_RANKS )
1886 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1889 /* This feature does not work; animation needs a rewrite */
1890 appData.highlightDragging = FALSE;
1894 xDisplay = XtDisplay(shellWidget);
1895 xScreen = DefaultScreen(xDisplay);
1896 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1898 gameInfo.variant = StringToVariant(appData.variant);
1899 InitPosition(FALSE);
1902 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1904 if (isdigit(appData.boardSize[0])) {
1905 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1906 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1907 &fontPxlSize, &smallLayout, &tinyLayout);
1909 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1910 programName, appData.boardSize);
1914 /* Find some defaults; use the nearest known size */
1915 SizeDefaults *szd, *nearest;
1916 int distance = 99999;
1917 nearest = szd = sizeDefaults;
1918 while (szd->name != NULL) {
1919 if (abs(szd->squareSize - squareSize) < distance) {
1921 distance = abs(szd->squareSize - squareSize);
1922 if (distance == 0) break;
1926 if (i < 2) lineGap = nearest->lineGap;
1927 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1928 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1929 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1930 if (i < 6) smallLayout = nearest->smallLayout;
1931 if (i < 7) tinyLayout = nearest->tinyLayout;
1934 SizeDefaults *szd = sizeDefaults;
1935 if (*appData.boardSize == NULLCHAR) {
1936 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1937 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1940 if (szd->name == NULL) szd--;
1941 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1943 while (szd->name != NULL &&
1944 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1945 if (szd->name == NULL) {
1946 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1947 programName, appData.boardSize);
1951 squareSize = szd->squareSize;
1952 lineGap = szd->lineGap;
1953 clockFontPxlSize = szd->clockFontPxlSize;
1954 coordFontPxlSize = szd->coordFontPxlSize;
1955 fontPxlSize = szd->fontPxlSize;
1956 smallLayout = szd->smallLayout;
1957 tinyLayout = szd->tinyLayout;
1958 // [HGM] font: use defaults from settings file if available and not overruled
1960 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
1961 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
1962 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
1963 appData.font = fontTable[MESSAGE_FONT][squareSize];
1964 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
1965 appData.coordFont = fontTable[COORD_FONT][squareSize];
1967 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1968 if (strlen(appData.pixmapDirectory) > 0) {
1969 p = ExpandPathName(appData.pixmapDirectory);
1971 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1972 appData.pixmapDirectory);
1975 if (appData.debugMode) {
1976 fprintf(stderr, _("\
1977 XBoard square size (hint): %d\n\
1978 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1980 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1981 if (appData.debugMode) {
1982 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1985 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1987 /* [HR] height treated separately (hacked) */
1988 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1989 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1990 if (appData.showJail == 1) {
1991 /* Jail on top and bottom */
1992 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1993 XtSetArg(boardArgs[2], XtNheight,
1994 boardHeight + 2*(lineGap + squareSize));
1995 } else if (appData.showJail == 2) {
1997 XtSetArg(boardArgs[1], XtNwidth,
1998 boardWidth + 2*(lineGap + squareSize));
1999 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2002 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2003 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2007 * Determine what fonts to use.
2009 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2010 clockFontID = XLoadFont(xDisplay, appData.clockFont);
2011 clockFontStruct = XQueryFont(xDisplay, clockFontID);
2012 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2013 coordFontID = XLoadFont(xDisplay, appData.coordFont);
2014 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2015 appData.font = FindFont(appData.font, fontPxlSize);
2016 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
2017 countFontStruct = XQueryFont(xDisplay, countFontID);
2018 // appData.font = FindFont(appData.font, fontPxlSize);
2020 xdb = XtDatabase(xDisplay);
2021 XrmPutStringResource(&xdb, "*font", appData.font);
2024 * Detect if there are not enough colors available and adapt.
2026 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2027 appData.monoMode = True;
2030 if (!appData.monoMode) {
2031 vFrom.addr = (caddr_t) appData.lightSquareColor;
2032 vFrom.size = strlen(appData.lightSquareColor);
2033 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2034 if (vTo.addr == NULL) {
2035 appData.monoMode = True;
2038 lightSquareColor = *(Pixel *) vTo.addr;
2041 if (!appData.monoMode) {
2042 vFrom.addr = (caddr_t) appData.darkSquareColor;
2043 vFrom.size = strlen(appData.darkSquareColor);
2044 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2045 if (vTo.addr == NULL) {
2046 appData.monoMode = True;
2049 darkSquareColor = *(Pixel *) vTo.addr;
2052 if (!appData.monoMode) {
2053 vFrom.addr = (caddr_t) appData.whitePieceColor;
2054 vFrom.size = strlen(appData.whitePieceColor);
2055 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2056 if (vTo.addr == NULL) {
2057 appData.monoMode = True;
2060 whitePieceColor = *(Pixel *) vTo.addr;
2063 if (!appData.monoMode) {
2064 vFrom.addr = (caddr_t) appData.blackPieceColor;
2065 vFrom.size = strlen(appData.blackPieceColor);
2066 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2067 if (vTo.addr == NULL) {
2068 appData.monoMode = True;
2071 blackPieceColor = *(Pixel *) vTo.addr;
2075 if (!appData.monoMode) {
2076 vFrom.addr = (caddr_t) appData.highlightSquareColor;
2077 vFrom.size = strlen(appData.highlightSquareColor);
2078 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2079 if (vTo.addr == NULL) {
2080 appData.monoMode = True;
2083 highlightSquareColor = *(Pixel *) vTo.addr;
2087 if (!appData.monoMode) {
2088 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
2089 vFrom.size = strlen(appData.premoveHighlightColor);
2090 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2091 if (vTo.addr == NULL) {
2092 appData.monoMode = True;
2095 premoveHighlightColor = *(Pixel *) vTo.addr;
2100 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2103 if (appData.bitmapDirectory == NULL ||
2104 appData.bitmapDirectory[0] == NULLCHAR)
2105 appData.bitmapDirectory = DEF_BITMAP_DIR;
2108 if (appData.lowTimeWarning && !appData.monoMode) {
2109 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2110 vFrom.size = strlen(appData.lowTimeWarningColor);
2111 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2112 if (vTo.addr == NULL)
2113 appData.monoMode = True;
2115 lowTimeWarningColor = *(Pixel *) vTo.addr;
2118 if (appData.monoMode && appData.debugMode) {
2119 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2120 (unsigned long) XWhitePixel(xDisplay, xScreen),
2121 (unsigned long) XBlackPixel(xDisplay, xScreen));
2124 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2125 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2126 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2127 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2128 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2129 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2130 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2131 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2132 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2133 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2135 if (appData.colorize) {
2137 _("%s: can't parse color names; disabling colorization\n"),
2140 appData.colorize = FALSE;
2142 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2143 textColors[ColorNone].attr = 0;
2145 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2151 layoutName = "tinyLayout";
2152 } else if (smallLayout) {
2153 layoutName = "smallLayout";
2155 layoutName = "normalLayout";
2157 /* Outer layoutWidget is there only to provide a name for use in
2158 resources that depend on the layout style */
2160 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2161 layoutArgs, XtNumber(layoutArgs));
2163 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2164 formArgs, XtNumber(formArgs));
2165 XtSetArg(args[0], XtNdefaultDistance, &sep);
2166 XtGetValues(formWidget, args, 1);
2169 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2170 XtSetArg(args[0], XtNtop, XtChainTop);
2171 XtSetArg(args[1], XtNbottom, XtChainTop);
2172 XtSetArg(args[2], XtNright, XtChainLeft);
2173 XtSetValues(menuBarWidget, args, 3);
2175 widgetList[j++] = whiteTimerWidget =
2176 XtCreateWidget("whiteTime", labelWidgetClass,
2177 formWidget, timerArgs, XtNumber(timerArgs));
2178 XtSetArg(args[0], XtNfont, clockFontStruct);
2179 XtSetArg(args[1], XtNtop, XtChainTop);
2180 XtSetArg(args[2], XtNbottom, XtChainTop);
2181 XtSetValues(whiteTimerWidget, args, 3);
2183 widgetList[j++] = blackTimerWidget =
2184 XtCreateWidget("blackTime", labelWidgetClass,
2185 formWidget, timerArgs, XtNumber(timerArgs));
2186 XtSetArg(args[0], XtNfont, clockFontStruct);
2187 XtSetArg(args[1], XtNtop, XtChainTop);
2188 XtSetArg(args[2], XtNbottom, XtChainTop);
2189 XtSetValues(blackTimerWidget, args, 3);
2191 if (appData.titleInWindow) {
2192 widgetList[j++] = titleWidget =
2193 XtCreateWidget("title", labelWidgetClass, formWidget,
2194 titleArgs, XtNumber(titleArgs));
2195 XtSetArg(args[0], XtNtop, XtChainTop);
2196 XtSetArg(args[1], XtNbottom, XtChainTop);
2197 XtSetValues(titleWidget, args, 2);
2200 if (appData.showButtonBar) {
2201 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2202 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2203 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2204 XtSetArg(args[2], XtNtop, XtChainTop);
2205 XtSetArg(args[3], XtNbottom, XtChainTop);
2206 XtSetValues(buttonBarWidget, args, 4);
2209 widgetList[j++] = messageWidget =
2210 XtCreateWidget("message", labelWidgetClass, formWidget,
2211 messageArgs, XtNumber(messageArgs));
2212 XtSetArg(args[0], XtNtop, XtChainTop);
2213 XtSetArg(args[1], XtNbottom, XtChainTop);
2214 XtSetValues(messageWidget, args, 2);
2216 widgetList[j++] = boardWidget =
2217 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2218 XtNumber(boardArgs));
2220 XtManageChildren(widgetList, j);
2222 timerWidth = (boardWidth - sep) / 2;
2223 XtSetArg(args[0], XtNwidth, timerWidth);
2224 XtSetValues(whiteTimerWidget, args, 1);
2225 XtSetValues(blackTimerWidget, args, 1);
2227 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2228 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2229 XtGetValues(whiteTimerWidget, args, 2);
2231 if (appData.showButtonBar) {
2232 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2233 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2234 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2238 * formWidget uses these constraints but they are stored
2242 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2243 XtSetValues(menuBarWidget, args, i);
2244 if (appData.titleInWindow) {
2247 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2248 XtSetValues(whiteTimerWidget, args, i);
2250 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2251 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2252 XtSetValues(blackTimerWidget, args, i);
2254 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2255 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2256 XtSetValues(titleWidget, args, i);
2258 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2259 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2260 XtSetValues(messageWidget, args, i);
2261 if (appData.showButtonBar) {
2263 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2264 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2265 XtSetValues(buttonBarWidget, args, i);
2269 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2270 XtSetValues(whiteTimerWidget, args, i);
2272 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2273 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2274 XtSetValues(blackTimerWidget, args, i);
2276 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2277 XtSetValues(titleWidget, args, i);
2279 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2280 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2281 XtSetValues(messageWidget, args, i);
2282 if (appData.showButtonBar) {
2284 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2285 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2286 XtSetValues(buttonBarWidget, args, i);
2291 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2292 XtSetValues(whiteTimerWidget, args, i);
2294 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2295 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2296 XtSetValues(blackTimerWidget, args, i);
2298 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2299 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2300 XtSetValues(messageWidget, args, i);
2301 if (appData.showButtonBar) {
2303 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2304 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2305 XtSetValues(buttonBarWidget, args, i);
2309 XtSetArg(args[0], XtNfromVert, messageWidget);
2310 XtSetArg(args[1], XtNtop, XtChainTop);
2311 XtSetArg(args[2], XtNbottom, XtChainBottom);
2312 XtSetArg(args[3], XtNleft, XtChainLeft);
2313 XtSetArg(args[4], XtNright, XtChainRight);
2314 XtSetValues(boardWidget, args, 5);
2316 XtRealizeWidget(shellWidget);
2319 XtSetArg(args[0], XtNx, wpMain.x);
2320 XtSetArg(args[1], XtNy, wpMain.y);
2321 XtSetValues(shellWidget, args, 2);
2325 * Correct the width of the message and title widgets.
2326 * It is not known why some systems need the extra fudge term.
2327 * The value "2" is probably larger than needed.
2329 XawFormDoLayout(formWidget, False);
2331 #define WIDTH_FUDGE 2
2333 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2334 XtSetArg(args[i], XtNheight, &h); i++;
2335 XtGetValues(messageWidget, args, i);
2336 if (appData.showButtonBar) {
2338 XtSetArg(args[i], XtNwidth, &w); i++;
2339 XtGetValues(buttonBarWidget, args, i);
2340 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2342 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2345 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2346 if (gres != XtGeometryYes && appData.debugMode) {
2347 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2348 programName, gres, w, h, wr, hr);
2351 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2352 /* The size used for the child widget in layout lags one resize behind
2353 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2355 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2356 if (gres != XtGeometryYes && appData.debugMode) {
2357 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2358 programName, gres, w, h, wr, hr);
2361 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2362 XtSetArg(args[1], XtNright, XtChainRight);
2363 XtSetValues(messageWidget, args, 2);
2365 if (appData.titleInWindow) {
2367 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2368 XtSetArg(args[i], XtNheight, &h); i++;
2369 XtGetValues(titleWidget, args, i);
2371 w = boardWidth - 2*bor;
2373 XtSetArg(args[0], XtNwidth, &w);
2374 XtGetValues(menuBarWidget, args, 1);
2375 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2378 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2379 if (gres != XtGeometryYes && appData.debugMode) {
2381 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2382 programName, gres, w, h, wr, hr);
2385 XawFormDoLayout(formWidget, True);
2387 xBoardWindow = XtWindow(boardWidget);
2389 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2390 // not need to go into InitDrawingSizes().
2394 * Create X checkmark bitmap and initialize option menu checks.
2396 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2397 checkmark_bits, checkmark_width, checkmark_height);
2398 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2399 if (appData.alwaysPromoteToQueen) {
2400 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2403 if (appData.animateDragging) {
2404 XtSetValues(XtNameToWidget(menuBarWidget,
2405 "menuOptions.Animate Dragging"),
2408 if (appData.animate) {
2409 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2412 if (appData.autoComment) {
2413 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2416 if (appData.autoCallFlag) {
2417 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2420 if (appData.autoFlipView) {
2421 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2424 if (appData.autoObserve) {
2425 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2428 if (appData.autoRaiseBoard) {
2429 XtSetValues(XtNameToWidget(menuBarWidget,
2430 "menuOptions.Auto Raise Board"), args, 1);
2432 if (appData.autoSaveGames) {
2433 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2436 if (appData.saveGameFile[0] != NULLCHAR) {
2437 /* Can't turn this off from menu */
2438 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2440 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2444 if (appData.blindfold) {
2445 XtSetValues(XtNameToWidget(menuBarWidget,
2446 "menuOptions.Blindfold"), args, 1);
2448 if (appData.flashCount > 0) {
2449 XtSetValues(XtNameToWidget(menuBarWidget,
2450 "menuOptions.Flash Moves"),
2453 if (appData.getMoveList) {
2454 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2458 if (appData.highlightDragging) {
2459 XtSetValues(XtNameToWidget(menuBarWidget,
2460 "menuOptions.Highlight Dragging"),
2464 if (appData.highlightLastMove) {
2465 XtSetValues(XtNameToWidget(menuBarWidget,
2466 "menuOptions.Highlight Last Move"),
2469 if (appData.highlightMoveWithArrow) {
2470 XtSetValues(XtNameToWidget(menuBarWidget,
2471 "menuOptions.Arrow"),
2474 if (appData.icsAlarm) {
2475 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2478 if (appData.ringBellAfterMoves) {
2479 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2482 if (appData.oneClick) {
2483 XtSetValues(XtNameToWidget(menuBarWidget,
2484 "menuOptions.OneClick"), args, 1);
2486 if (appData.periodicUpdates) {
2487 XtSetValues(XtNameToWidget(menuBarWidget,
2488 "menuOptions.Periodic Updates"), args, 1);
2490 if (appData.ponderNextMove) {
2491 XtSetValues(XtNameToWidget(menuBarWidget,
2492 "menuOptions.Ponder Next Move"), args, 1);
2494 if (appData.popupExitMessage) {
2495 XtSetValues(XtNameToWidget(menuBarWidget,
2496 "menuOptions.Popup Exit Message"), args, 1);
2498 if (appData.popupMoveErrors) {
2499 XtSetValues(XtNameToWidget(menuBarWidget,
2500 "menuOptions.Popup Move Errors"), args, 1);
2502 if (appData.premove) {
2503 XtSetValues(XtNameToWidget(menuBarWidget,
2504 "menuOptions.Premove"), args, 1);
2506 if (appData.quietPlay) {
2507 XtSetValues(XtNameToWidget(menuBarWidget,
2508 "menuOptions.Quiet Play"), args, 1);
2510 if (appData.showCoords) {
2511 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2514 if (appData.hideThinkingFromHuman) {
2515 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2518 if (appData.testLegality) {
2519 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2522 if (saveSettingsOnExit) {
2523 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2530 ReadBitmap(&wIconPixmap, "icon_white.bm",
2531 icon_white_bits, icon_white_width, icon_white_height);
2532 ReadBitmap(&bIconPixmap, "icon_black.bm",
2533 icon_black_bits, icon_black_width, icon_black_height);
2534 iconPixmap = wIconPixmap;
2536 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2537 XtSetValues(shellWidget, args, i);
2540 * Create a cursor for the board widget.
2542 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2543 XChangeWindowAttributes(xDisplay, xBoardWindow,
2544 CWCursor, &window_attributes);
2547 * Inhibit shell resizing.
2549 shellArgs[0].value = (XtArgVal) &w;
2550 shellArgs[1].value = (XtArgVal) &h;
2551 XtGetValues(shellWidget, shellArgs, 2);
2552 shellArgs[4].value = shellArgs[2].value = w;
2553 shellArgs[5].value = shellArgs[3].value = h;
2554 XtSetValues(shellWidget, &shellArgs[2], 4);
2555 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2556 marginH = h - boardHeight;
2558 CatchDeleteWindow(shellWidget, "QuitProc");
2563 if (appData.bitmapDirectory[0] != NULLCHAR) {
2567 CreateXPMBoard(appData.liteBackTextureFile, 1);
2568 CreateXPMBoard(appData.darkBackTextureFile, 0);
2572 /* Create regular pieces */
2573 if (!useImages) CreatePieces();
2578 if (appData.animate || appData.animateDragging)
2581 XtAugmentTranslations(formWidget,
2582 XtParseTranslationTable(globalTranslations));
2583 XtAugmentTranslations(boardWidget,
2584 XtParseTranslationTable(boardTranslations));
2585 XtAugmentTranslations(whiteTimerWidget,
2586 XtParseTranslationTable(whiteTranslations));
2587 XtAugmentTranslations(blackTimerWidget,
2588 XtParseTranslationTable(blackTranslations));
2590 /* Why is the following needed on some versions of X instead
2591 * of a translation? */
2592 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2593 (XtEventHandler) EventProc, NULL);
2596 /* [AS] Restore layout */
2597 if( wpMoveHistory.visible ) {
2601 if( wpEvalGraph.visible )
2606 if( wpEngineOutput.visible ) {
2607 EngineOutputPopUp();
2612 if (errorExitStatus == -1) {
2613 if (appData.icsActive) {
2614 /* We now wait until we see "login:" from the ICS before
2615 sending the logon script (problems with timestamp otherwise) */
2616 /*ICSInitScript();*/
2617 if (appData.icsInputBox) ICSInputBoxPopUp();
2621 signal(SIGWINCH, TermSizeSigHandler);
2623 signal(SIGINT, IntSigHandler);
2624 signal(SIGTERM, IntSigHandler);
2625 if (*appData.cmailGameName != NULLCHAR) {
2626 signal(SIGUSR1, CmailSigHandler);
2629 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2631 XtSetKeyboardFocus(shellWidget, formWidget);
2633 XtAppMainLoop(appContext);
2634 if (appData.debugMode) fclose(debugFP); // [DM] debug
2641 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2642 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2644 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2645 unlink(gameCopyFilename);
2646 unlink(gamePasteFilename);
2649 RETSIGTYPE TermSizeSigHandler(int sig)
2662 CmailSigHandler(sig)
2668 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2670 /* Activate call-back function CmailSigHandlerCallBack() */
2671 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2673 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2677 CmailSigHandlerCallBack(isr, closure, message, count, error)
2685 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2687 /**** end signal code ****/
2693 /* try to open the icsLogon script, either in the location given
2694 * or in the users HOME directory
2701 f = fopen(appData.icsLogon, "r");
2704 homedir = getenv("HOME");
2705 if (homedir != NULL)
2707 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2708 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2709 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2710 f = fopen(buf, "r");
2715 ProcessICSInitScript(f);
2717 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2726 EditCommentPopDown();
2741 if (!menuBarWidget) return;
2742 w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2744 DisplayError("menuEdit.Revert", 0);
2746 XtSetSensitive(w, !grey);
2748 w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2750 DisplayError("menuEdit.Annotate", 0);
2752 XtSetSensitive(w, !grey);
2757 SetMenuEnables(enab)
2761 if (!menuBarWidget) return;
2762 while (enab->name != NULL) {
2763 w = XtNameToWidget(menuBarWidget, enab->name);
2765 DisplayError(enab->name, 0);
2767 XtSetSensitive(w, enab->value);
2773 Enables icsEnables[] = {
2774 { "menuFile.Mail Move", False },
2775 { "menuFile.Reload CMail Message", False },
2776 { "menuMode.Machine Black", False },
2777 { "menuMode.Machine White", False },
2778 { "menuMode.Analysis Mode", False },
2779 { "menuMode.Analyze File", False },
2780 { "menuMode.Two Machines", False },
2782 { "menuEngine.Hint", False },
2783 { "menuEngine.Book", False },
2784 { "menuEngine.Move Now", False },
2785 { "menuOptions.Periodic Updates", False },
2786 { "menuOptions.Hide Thinking", False },
2787 { "menuOptions.Ponder Next Move", False },
2788 { "menuEngine.Engine #1 Settings", False },
2790 { "menuEngine.Engine #2 Settings", False },
2791 { "menuEdit.Annotate", False },
2795 Enables ncpEnables[] = {
2796 { "menuFile.Mail Move", False },
2797 { "menuFile.Reload CMail Message", False },
2798 { "menuMode.Machine White", False },
2799 { "menuMode.Machine Black", False },
2800 { "menuMode.Analysis Mode", False },
2801 { "menuMode.Analyze File", False },
2802 { "menuMode.Two Machines", False },
2803 { "menuMode.ICS Client", False },
2804 { "menuView.ICS Input Box", False },
2805 { "Action", False },
2806 { "menuEdit.Revert", False },
2807 { "menuEdit.Annotate", False },
2808 { "menuEngine.Engine #1 Settings", False },
2809 { "menuEngine.Engine #2 Settings", False },
2810 { "menuEngine.Move Now", False },
2811 { "menuEngine.Retract Move", False },
2812 { "menuOptions.Auto Comment", False },
2813 { "menuOptions.Auto Flag", False },
2814 { "menuOptions.Auto Flip View", False },
2815 { "menuOptions.Auto Observe", False },
2816 { "menuOptions.Auto Raise Board", False },
2817 { "menuOptions.Get Move List", False },
2818 { "menuOptions.ICS Alarm", False },
2819 { "menuOptions.Move Sound", False },
2820 { "menuOptions.Quiet Play", False },
2821 { "menuOptions.Hide Thinking", False },
2822 { "menuOptions.Periodic Updates", False },
2823 { "menuOptions.Ponder Next Move", False },
2824 { "menuEngine.Hint", False },
2825 { "menuEngine.Book", False },
2829 Enables gnuEnables[] = {
2830 { "menuMode.ICS Client", False },
2831 { "menuView.ICS Input Box", False },
2832 { "menuAction.Accept", False },
2833 { "menuAction.Decline", False },
2834 { "menuAction.Rematch", False },
2835 { "menuAction.Adjourn", False },
2836 { "menuAction.Stop Examining", False },
2837 { "menuAction.Stop Observing", False },
2838 { "menuAction.Upload to Examine", False },
2839 { "menuEdit.Revert", False },
2840 { "menuEdit.Annotate", False },
2841 { "menuOptions.Auto Comment", False },
2842 { "menuOptions.Auto Observe", False },
2843 { "menuOptions.Auto Raise Board", False },
2844 { "menuOptions.Get Move List", False },
2845 { "menuOptions.Premove", False },
2846 { "menuOptions.Quiet Play", False },
2848 /* The next two options rely on SetCmailMode being called *after* */
2849 /* SetGNUMode so that when GNU is being used to give hints these */
2850 /* menu options are still available */
2852 { "menuFile.Mail Move", False },
2853 { "menuFile.Reload CMail Message", False },
2857 Enables cmailEnables[] = {
2859 { "menuAction.Call Flag", False },
2860 { "menuAction.Draw", True },
2861 { "menuAction.Adjourn", False },
2862 { "menuAction.Abort", False },
2863 { "menuAction.Stop Observing", False },
2864 { "menuAction.Stop Examining", False },
2865 { "menuFile.Mail Move", True },
2866 { "menuFile.Reload CMail Message", True },
2870 Enables trainingOnEnables[] = {
2871 { "menuMode.Edit Comment", False },
2872 { "menuMode.Pause", False },
2873 { "menuEdit.Forward", False },
2874 { "menuEdit.Backward", False },
2875 { "menuEdit.Forward to End", False },
2876 { "menuEdit.Back to Start", False },
2877 { "menuEngine.Move Now", False },
2878 { "menuEdit.Truncate Game", False },
2882 Enables trainingOffEnables[] = {
2883 { "menuMode.Edit Comment", True },
2884 { "menuMode.Pause", True },
2885 { "menuEdit.Forward", True },
2886 { "menuEdit.Backward", True },
2887 { "menuEdit.Forward to End", True },
2888 { "menuEdit.Back to Start", True },
2889 { "menuEngine.Move Now", True },
2890 { "menuEdit.Truncate Game", True },
2894 Enables machineThinkingEnables[] = {
2895 { "menuFile.Load Game", False },
2896 // { "menuFile.Load Next Game", False },
2897 // { "menuFile.Load Previous Game", False },
2898 // { "menuFile.Reload Same Game", False },
2899 { "menuEdit.Paste Game", False },
2900 { "menuFile.Load Position", False },
2901 // { "menuFile.Load Next Position", False },
2902 // { "menuFile.Load Previous Position", False },
2903 // { "menuFile.Reload Same Position", False },
2904 { "menuEdit.Paste Position", False },
2905 { "menuMode.Machine White", False },
2906 { "menuMode.Machine Black", False },
2907 { "menuMode.Two Machines", False },
2908 { "menuEngine.Retract Move", False },
2912 Enables userThinkingEnables[] = {
2913 { "menuFile.Load Game", True },
2914 // { "menuFile.Load Next Game", True },
2915 // { "menuFile.Load Previous Game", True },
2916 // { "menuFile.Reload Same Game", True },
2917 { "menuEdit.Paste Game", True },
2918 { "menuFile.Load Position", True },
2919 // { "menuFile.Load Next Position", True },
2920 // { "menuFile.Load Previous Position", True },
2921 // { "menuFile.Reload Same Position", True },
2922 { "menuEdit.Paste Position", True },
2923 { "menuMode.Machine White", True },
2924 { "menuMode.Machine Black", True },
2925 { "menuMode.Two Machines", True },
2926 { "menuEngine.Retract Move", True },
2932 SetMenuEnables(icsEnables);
2935 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2936 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2943 SetMenuEnables(ncpEnables);
2949 SetMenuEnables(gnuEnables);
2955 SetMenuEnables(cmailEnables);
2961 SetMenuEnables(trainingOnEnables);
2962 if (appData.showButtonBar) {
2963 XtSetSensitive(buttonBarWidget, False);
2969 SetTrainingModeOff()
2971 SetMenuEnables(trainingOffEnables);
2972 if (appData.showButtonBar) {
2973 XtSetSensitive(buttonBarWidget, True);
2978 SetUserThinkingEnables()
2980 if (appData.noChessProgram) return;
2981 SetMenuEnables(userThinkingEnables);
2985 SetMachineThinkingEnables()
2987 if (appData.noChessProgram) return;
2988 SetMenuEnables(machineThinkingEnables);
2990 case MachinePlaysBlack:
2991 case MachinePlaysWhite:
2992 case TwoMachinesPlay:
2993 XtSetSensitive(XtNameToWidget(menuBarWidget,
2994 ModeToWidgetName(gameMode)), True);
3001 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
3002 #define HISTORY_SIZE 64
3003 static char *history[HISTORY_SIZE];
3004 int histIn = 0, histP = 0;
3007 SaveInHistory(char *cmd)
3009 if (history[histIn] != NULL) {
3010 free(history[histIn]);
3011 history[histIn] = NULL;
3013 if (*cmd == NULLCHAR) return;
3014 history[histIn] = StrSave(cmd);
3015 histIn = (histIn + 1) % HISTORY_SIZE;
3016 if (history[histIn] != NULL) {
3017 free(history[histIn]);
3018 history[histIn] = NULL;
3024 PrevInHistory(char *cmd)
3027 if (histP == histIn) {
3028 if (history[histIn] != NULL) free(history[histIn]);
3029 history[histIn] = StrSave(cmd);
3031 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
3032 if (newhp == histIn || history[newhp] == NULL) return NULL;
3034 return history[histP];
3040 if (histP == histIn) return NULL;
3041 histP = (histP + 1) % HISTORY_SIZE;
3042 return history[histP];
3044 // end of borrowed code
3046 #define Abs(n) ((n)<0 ? -(n) : (n))
3049 * Find a font that matches "pattern" that is as close as
3050 * possible to the targetPxlSize. Prefer fonts that are k
3051 * pixels smaller to fonts that are k pixels larger. The
3052 * pattern must be in the X Consortium standard format,
3053 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3054 * The return value should be freed with XtFree when no
3058 FindFont(pattern, targetPxlSize)
3062 char **fonts, *p, *best, *scalable, *scalableTail;
3063 int i, j, nfonts, minerr, err, pxlSize;
3066 char **missing_list;
3068 char *def_string, *base_fnt_lst, strInt[3];
3070 XFontStruct **fnt_list;
3072 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3073 snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize);
3074 p = strstr(pattern, "--");
3075 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3076 strcat(base_fnt_lst, strInt);
3077 strcat(base_fnt_lst, strchr(p + 2, '-'));
3079 if ((fntSet = XCreateFontSet(xDisplay,
3083 &def_string)) == NULL) {
3085 fprintf(stderr, _("Unable to create font set.\n"));
3089 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3091 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3093 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3094 programName, pattern);
3102 for (i=0; i<nfonts; i++) {
3105 if (*p != '-') continue;
3107 if (*p == NULLCHAR) break;
3108 if (*p++ == '-') j++;
3110 if (j < 7) continue;
3113 scalable = fonts[i];
3116 err = pxlSize - targetPxlSize;
3117 if (Abs(err) < Abs(minerr) ||
3118 (minerr > 0 && err < 0 && -err == minerr)) {
3124 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3125 /* If the error is too big and there is a scalable font,
3126 use the scalable font. */
3127 int headlen = scalableTail - scalable;
3128 p = (char *) XtMalloc(strlen(scalable) + 10);
3129 while (isdigit(*scalableTail)) scalableTail++;
3130 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3132 p = (char *) XtMalloc(strlen(best) + 2);
3133 safeStrCpy(p, best, strlen(best)+1 );
3135 if (appData.debugMode) {
3136 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3137 pattern, targetPxlSize, p);
3140 if (missing_count > 0)
3141 XFreeStringList(missing_list);
3142 XFreeFontSet(xDisplay, fntSet);
3144 XFreeFontNames(fonts);
3151 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3152 | GCBackground | GCFunction | GCPlaneMask;
3153 XGCValues gc_values;
3156 gc_values.plane_mask = AllPlanes;
3157 gc_values.line_width = lineGap;
3158 gc_values.line_style = LineSolid;
3159 gc_values.function = GXcopy;
3161 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3162 gc_values.background = XBlackPixel(xDisplay, xScreen);
3163 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3165 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3166 gc_values.background = XWhitePixel(xDisplay, xScreen);
3167 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3168 XSetFont(xDisplay, coordGC, coordFontID);
3170 // [HGM] make font for holdings counts (white on black0
3171 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3172 gc_values.background = XBlackPixel(xDisplay, xScreen);
3173 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3174 XSetFont(xDisplay, countGC, countFontID);
3176 if (appData.monoMode) {
3177 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3178 gc_values.background = XWhitePixel(xDisplay, xScreen);
3179 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3181 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3182 gc_values.background = XBlackPixel(xDisplay, xScreen);
3183 lightSquareGC = wbPieceGC
3184 = XtGetGC(shellWidget, value_mask, &gc_values);
3186 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3187 gc_values.background = XWhitePixel(xDisplay, xScreen);
3188 darkSquareGC = bwPieceGC
3189 = XtGetGC(shellWidget, value_mask, &gc_values);
3191 if (DefaultDepth(xDisplay, xScreen) == 1) {
3192 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3193 gc_values.function = GXcopyInverted;
3194 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3195 gc_values.function = GXcopy;
3196 if (XBlackPixel(xDisplay, xScreen) == 1) {
3197 bwPieceGC = darkSquareGC;
3198 wbPieceGC = copyInvertedGC;
3200 bwPieceGC = copyInvertedGC;
3201 wbPieceGC = lightSquareGC;
3205 gc_values.foreground = highlightSquareColor;
3206 gc_values.background = highlightSquareColor;
3207 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3209 gc_values.foreground = premoveHighlightColor;
3210 gc_values.background = premoveHighlightColor;
3211 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3213 gc_values.foreground = lightSquareColor;
3214 gc_values.background = darkSquareColor;
3215 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3217 gc_values.foreground = darkSquareColor;
3218 gc_values.background = lightSquareColor;
3219 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3221 gc_values.foreground = jailSquareColor;
3222 gc_values.background = jailSquareColor;
3223 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3225 gc_values.foreground = whitePieceColor;
3226 gc_values.background = darkSquareColor;
3227 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3229 gc_values.foreground = whitePieceColor;
3230 gc_values.background = lightSquareColor;
3231 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3233 gc_values.foreground = whitePieceColor;
3234 gc_values.background = jailSquareColor;
3235 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3237 gc_values.foreground = blackPieceColor;
3238 gc_values.background = darkSquareColor;
3239 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3241 gc_values.foreground = blackPieceColor;
3242 gc_values.background = lightSquareColor;
3243 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3245 gc_values.foreground = blackPieceColor;
3246 gc_values.background = jailSquareColor;
3247 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3251 void loadXIM(xim, xmask, filename, dest, mask)
3264 fp = fopen(filename, "rb");
3266 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3273 for (y=0; y<h; ++y) {
3274 for (x=0; x<h; ++x) {
3279 XPutPixel(xim, x, y, blackPieceColor);
3281 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3284 XPutPixel(xim, x, y, darkSquareColor);
3286 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3289 XPutPixel(xim, x, y, whitePieceColor);
3291 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3294 XPutPixel(xim, x, y, lightSquareColor);
3296 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3302 /* create Pixmap of piece */
3303 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3305 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3308 /* create Pixmap of clipmask
3309 Note: We assume the white/black pieces have the same
3310 outline, so we make only 6 masks. This is okay
3311 since the XPM clipmask routines do the same. */
3313 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3315 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3318 /* now create the 1-bit version */
3319 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3322 values.foreground = 1;
3323 values.background = 0;
3325 /* Don't use XtGetGC, not read only */
3326 maskGC = XCreateGC(xDisplay, *mask,
3327 GCForeground | GCBackground, &values);
3328 XCopyPlane(xDisplay, temp, *mask, maskGC,
3329 0, 0, squareSize, squareSize, 0, 0, 1);
3330 XFreePixmap(xDisplay, temp);
3335 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3337 void CreateXIMPieces()
3342 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3347 /* The XSynchronize calls were copied from CreatePieces.
3348 Not sure if needed, but can't hurt */
3349 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3352 /* temp needed by loadXIM() */
3353 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3354 0, 0, ss, ss, AllPlanes, XYPixmap);
3356 if (strlen(appData.pixmapDirectory) == 0) {
3360 if (appData.monoMode) {
3361 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3365 fprintf(stderr, _("\nLoading XIMs...\n"));
3367 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3368 fprintf(stderr, "%d", piece+1);
3369 for (kind=0; kind<4; kind++) {
3370 fprintf(stderr, ".");
3371 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3372 ExpandPathName(appData.pixmapDirectory),
3373 piece <= (int) WhiteKing ? "" : "w",
3374 pieceBitmapNames[piece],
3376 ximPieceBitmap[kind][piece] =
3377 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3378 0, 0, ss, ss, AllPlanes, XYPixmap);
3379 if (appData.debugMode)
3380 fprintf(stderr, _("(File:%s:) "), buf);
3381 loadXIM(ximPieceBitmap[kind][piece],
3383 &(xpmPieceBitmap2[kind][piece]),
3384 &(ximMaskPm2[piece]));
3385 if(piece <= (int)WhiteKing)
3386 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3388 fprintf(stderr," ");
3390 /* Load light and dark squares */
3391 /* If the LSQ and DSQ pieces don't exist, we will
3392 draw them with solid squares. */
3393 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3394 if (access(buf, 0) != 0) {
3398 fprintf(stderr, _("light square "));
3400 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3401 0, 0, ss, ss, AllPlanes, XYPixmap);
3402 if (appData.debugMode)
3403 fprintf(stderr, _("(File:%s:) "), buf);
3405 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3406 fprintf(stderr, _("dark square "));
3407 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3408 ExpandPathName(appData.pixmapDirectory), ss);
3409 if (appData.debugMode)
3410 fprintf(stderr, _("(File:%s:) "), buf);
3412 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3413 0, 0, ss, ss, AllPlanes, XYPixmap);
3414 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3415 xpmJailSquare = xpmLightSquare;
3417 fprintf(stderr, _("Done.\n"));
3419 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3423 void CreateXPMBoard(char *s, int kind)
3427 if(s == NULL || *s == 0 || *s == '*') return;
3428 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3429 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3433 void CreateXPMPieces()
3437 u_int ss = squareSize;
3439 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3440 XpmColorSymbol symbols[4];
3442 /* The XSynchronize calls were copied from CreatePieces.
3443 Not sure if needed, but can't hurt */
3444 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3446 /* Setup translations so piece colors match square colors */
3447 symbols[0].name = "light_piece";
3448 symbols[0].value = appData.whitePieceColor;
3449 symbols[1].name = "dark_piece";
3450 symbols[1].value = appData.blackPieceColor;
3451 symbols[2].name = "light_square";
3452 symbols[2].value = appData.lightSquareColor;
3453 symbols[3].name = "dark_square";
3454 symbols[3].value = appData.darkSquareColor;
3456 attr.valuemask = XpmColorSymbols;
3457 attr.colorsymbols = symbols;
3458 attr.numsymbols = 4;
3460 if (appData.monoMode) {
3461 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3465 if (strlen(appData.pixmapDirectory) == 0) {
3466 XpmPieces* pieces = builtInXpms;
3469 while (pieces->size != squareSize && pieces->size) pieces++;
3470 if (!pieces->size) {
3471 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3474 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3475 for (kind=0; kind<4; kind++) {
3477 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3478 pieces->xpm[piece][kind],
3479 &(xpmPieceBitmap2[kind][piece]),
3480 NULL, &attr)) != 0) {
3481 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3485 if(piece <= (int) WhiteKing)
3486 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3490 xpmJailSquare = xpmLightSquare;
3494 fprintf(stderr, _("\nLoading XPMs...\n"));
3497 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3498 fprintf(stderr, "%d ", piece+1);
3499 for (kind=0; kind<4; kind++) {
3500 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3501 ExpandPathName(appData.pixmapDirectory),
3502 piece > (int) WhiteKing ? "w" : "",
3503 pieceBitmapNames[piece],
3505 if (appData.debugMode) {
3506 fprintf(stderr, _("(File:%s:) "), buf);
3508 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3509 &(xpmPieceBitmap2[kind][piece]),
3510 NULL, &attr)) != 0) {
3511 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3512 // [HGM] missing: read of unorthodox piece failed; substitute King.
3513 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3514 ExpandPathName(appData.pixmapDirectory),
3516 if (appData.debugMode) {
3517 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3519 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3520 &(xpmPieceBitmap2[kind][piece]),
3524 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3529 if(piece <= (int) WhiteKing)
3530 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3533 /* Load light and dark squares */
3534 /* If the LSQ and DSQ pieces don't exist, we will
3535 draw them with solid squares. */
3536 fprintf(stderr, _("light square "));
3537 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3538 if (access(buf, 0) != 0) {
3542 if (appData.debugMode)
3543 fprintf(stderr, _("(File:%s:) "), buf);
3545 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3546 &xpmLightSquare, NULL, &attr)) != 0) {
3547 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3550 fprintf(stderr, _("dark square "));
3551 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3552 ExpandPathName(appData.pixmapDirectory), ss);
3553 if (appData.debugMode) {
3554 fprintf(stderr, _("(File:%s:) "), buf);
3556 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3557 &xpmDarkSquare, NULL, &attr)) != 0) {
3558 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3562 xpmJailSquare = xpmLightSquare;
3563 fprintf(stderr, _("Done.\n"));
3565 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3568 #endif /* HAVE_LIBXPM */
3571 /* No built-in bitmaps */
3576 u_int ss = squareSize;
3578 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3581 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3582 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3583 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3584 pieceBitmapNames[piece],
3585 ss, kind == SOLID ? 's' : 'o');
3586 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3587 if(piece <= (int)WhiteKing)
3588 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3592 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3596 /* With built-in bitmaps */
3599 BuiltInBits* bib = builtInBits;
3602 u_int ss = squareSize;
3604 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3607 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3609 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3610 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3611 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3612 pieceBitmapNames[piece],
3613 ss, kind == SOLID ? 's' : 'o');
3614 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3615 bib->bits[kind][piece], ss, ss);
3616 if(piece <= (int)WhiteKing)
3617 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3621 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3626 void ReadBitmap(pm, name, bits, wreq, hreq)
3629 unsigned char bits[];
3635 char msg[MSG_SIZ], fullname[MSG_SIZ];
3637 if (*appData.bitmapDirectory != NULLCHAR) {
3638 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3639 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3640 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3641 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3642 &w, &h, pm, &x_hot, &y_hot);
3643 fprintf(stderr, "load %s\n", name);
3644 if (errcode != BitmapSuccess) {
3646 case BitmapOpenFailed:
3647 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3649 case BitmapFileInvalid:
3650 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3652 case BitmapNoMemory:
3653 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3657 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3661 fprintf(stderr, _("%s: %s...using built-in\n"),
3663 } else if (w != wreq || h != hreq) {
3665 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3666 programName, fullname, w, h, wreq, hreq);
3672 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3681 if (lineGap == 0) return;
3683 /* [HR] Split this into 2 loops for non-square boards. */
3685 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3686 gridSegments[i].x1 = 0;
3687 gridSegments[i].x2 =
3688 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3689 gridSegments[i].y1 = gridSegments[i].y2
3690 = lineGap / 2 + (i * (squareSize + lineGap));
3693 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3694 gridSegments[j + i].y1 = 0;
3695 gridSegments[j + i].y2 =
3696 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3697 gridSegments[j + i].x1 = gridSegments[j + i].x2
3698 = lineGap / 2 + (j * (squareSize + lineGap));
3702 static void MenuBarSelect(w, addr, index)
3707 XtActionProc proc = (XtActionProc) addr;
3709 (proc)(NULL, NULL, NULL, NULL);
3712 void CreateMenuBarPopup(parent, name, mb)
3722 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3725 XtSetArg(args[j], XtNleftMargin, 20); j++;
3726 XtSetArg(args[j], XtNrightMargin, 20); j++;
3728 while (mi->string != NULL) {
3729 if (strcmp(mi->string, "----") == 0) {
3730 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3733 XtSetArg(args[j], XtNlabel, XtNewString(mi->string));
3734 entry = XtCreateManagedWidget(mi->ref, smeBSBObjectClass,
3736 XtAddCallback(entry, XtNcallback,
3737 (XtCallbackProc) MenuBarSelect,
3738 (caddr_t) mi->proc);
3744 Widget CreateMenuBar(mb)
3748 Widget anchor, menuBar;
3750 char menuName[MSG_SIZ];
3753 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3754 XtSetArg(args[j], XtNvSpace, 0); j++;
3755 XtSetArg(args[j], XtNborderWidth, 0); j++;
3756 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3757 formWidget, args, j);
3759 while (mb->name != NULL) {
3760 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3761 strncat(menuName, mb->ref, MSG_SIZ - strlen(menuName) - 1);
3763 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3766 shortName[0] = mb->name[0];
3767 shortName[1] = NULLCHAR;
3768 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3771 XtSetArg(args[j], XtNlabel, XtNewString(mb->name)); j++;
3774 XtSetArg(args[j], XtNborderWidth, 0); j++;
3775 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3777 CreateMenuBarPopup(menuBar, menuName, mb);
3783 Widget CreateButtonBar(mi)
3787 Widget button, buttonBar;
3791 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3793 XtSetArg(args[j], XtNhSpace, 0); j++;
3795 XtSetArg(args[j], XtNborderWidth, 0); j++;
3796 XtSetArg(args[j], XtNvSpace, 0); j++;
3797 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3798 formWidget, args, j);
3800 while (mi->string != NULL) {
3803 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3804 XtSetArg(args[j], XtNborderWidth, 0); j++;
3806 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3807 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3808 buttonBar, args, j);
3809 XtAddCallback(button, XtNcallback,
3810 (XtCallbackProc) MenuBarSelect,
3811 (caddr_t) mi->proc);
3818 CreatePieceMenu(name, color)
3825 ChessSquare selection;
3827 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3828 boardWidget, args, 0);
3830 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3831 String item = pieceMenuStrings[color][i];
3833 if (strcmp(item, "----") == 0) {
3834 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3837 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3838 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3840 selection = pieceMenuTranslation[color][i];
3841 XtAddCallback(entry, XtNcallback,
3842 (XtCallbackProc) PieceMenuSelect,
3843 (caddr_t) selection);
3844 if (selection == WhitePawn || selection == BlackPawn) {
3845 XtSetArg(args[0], XtNpopupOnEntry, entry);
3846 XtSetValues(menu, args, 1);
3859 ChessSquare selection;
3861 whitePieceMenu = CreatePieceMenu("menuW", 0);
3862 blackPieceMenu = CreatePieceMenu("menuB", 1);
3864 XtRegisterGrabAction(PieceMenuPopup, True,
3865 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3866 GrabModeAsync, GrabModeAsync);
3868 XtSetArg(args[0], XtNlabel, _("Drop"));
3869 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3870 boardWidget, args, 1);
3871 for (i = 0; i < DROP_MENU_SIZE; i++) {
3872 String item = dropMenuStrings[i];
3874 if (strcmp(item, "----") == 0) {
3875 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3878 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3879 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3881 selection = dropMenuTranslation[i];
3882 XtAddCallback(entry, XtNcallback,
3883 (XtCallbackProc) DropMenuSelect,
3884 (caddr_t) selection);
3889 void SetupDropMenu()
3897 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3898 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3899 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3900 dmEnables[i].piece);
3901 XtSetSensitive(entry, p != NULL || !appData.testLegality
3902 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3903 && !appData.icsActive));
3905 while (p && *p++ == dmEnables[i].piece) count++;
3906 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3908 XtSetArg(args[j], XtNlabel, label); j++;
3909 XtSetValues(entry, args, j);
3913 void PieceMenuPopup(w, event, params, num_params)
3917 Cardinal *num_params;
3919 String whichMenu; int menuNr;
3920 if (event->type == ButtonRelease)
3921 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3922 else if (event->type == ButtonPress)
3923 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3925 case 0: whichMenu = params[0]; break;
3926 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3928 case -1: if (errorUp) ErrorPopDown();
3931 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3934 static void PieceMenuSelect(w, piece, junk)
3939 if (pmFromX < 0 || pmFromY < 0) return;
3940 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3943 static void DropMenuSelect(w, piece, junk)
3948 if (pmFromX < 0 || pmFromY < 0) return;
3949 DropMenuEvent(piece, pmFromX, pmFromY);
3952 void WhiteClock(w, event, prms, nprms)
3958 if (gameMode == EditPosition || gameMode == IcsExamining) {
3959 SetWhiteToPlayEvent();
3960 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3965 void BlackClock(w, event, prms, nprms)
3971 if (gameMode == EditPosition || gameMode == IcsExamining) {
3972 SetBlackToPlayEvent();
3973 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3980 * If the user selects on a border boundary, return -1; if off the board,
3981 * return -2. Otherwise map the event coordinate to the square.
3983 int EventToSquare(x, limit)
3991 if ((x % (squareSize + lineGap)) >= squareSize)
3993 x /= (squareSize + lineGap);
3999 static void do_flash_delay(msec)
4005 static void drawHighlight(file, rank, gc)
4011 if (lineGap == 0) return;
4014 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
4015 (squareSize + lineGap);
4016 y = lineGap/2 + rank * (squareSize + lineGap);
4018 x = lineGap/2 + file * (squareSize + lineGap);
4019 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
4020 (squareSize + lineGap);
4023 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
4024 squareSize+lineGap, squareSize+lineGap);
4027 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
4028 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4031 SetHighlights(fromX, fromY, toX, toY)
4032 int fromX, fromY, toX, toY;
4034 if (hi1X != fromX || hi1Y != fromY) {
4035 if (hi1X >= 0 && hi1Y >= 0) {
4036 drawHighlight(hi1X, hi1Y, lineGC);
4038 } // [HGM] first erase both, then draw new!
4039 if (hi2X != toX || hi2Y != toY) {
4040 if (hi2X >= 0 && hi2Y >= 0) {
4041 drawHighlight(hi2X, hi2Y, lineGC);
4044 if (hi1X != fromX || hi1Y != fromY) {
4045 if (fromX >= 0 && fromY >= 0) {
4046 drawHighlight(fromX, fromY, highlineGC);
4049 if (hi2X != toX || hi2Y != toY) {
4050 if (toX >= 0 && toY >= 0) {
4051 drawHighlight(toX, toY, highlineGC);
4063 SetHighlights(-1, -1, -1, -1);
4068 SetPremoveHighlights(fromX, fromY, toX, toY)
4069 int fromX, fromY, toX, toY;
4071 if (pm1X != fromX || pm1Y != fromY) {
4072 if (pm1X >= 0 && pm1Y >= 0) {
4073 drawHighlight(pm1X, pm1Y, lineGC);
4075 if (fromX >= 0 && fromY >= 0) {
4076 drawHighlight(fromX, fromY, prelineGC);
4079 if (pm2X != toX || pm2Y != toY) {
4080 if (pm2X >= 0 && pm2Y >= 0) {
4081 drawHighlight(pm2X, pm2Y, lineGC);
4083 if (toX >= 0 && toY >= 0) {
4084 drawHighlight(toX, toY, prelineGC);
4094 ClearPremoveHighlights()
4096 SetPremoveHighlights(-1, -1, -1, -1);
4099 static int CutOutSquare(x, y, x0, y0, kind)
4100 int x, y, *x0, *y0, kind;
4102 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
4103 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
4105 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
4106 if(textureW[kind] < W*squareSize)
4107 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
4109 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
4110 if(textureH[kind] < H*squareSize)
4111 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
4113 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
4117 static void BlankSquare(x, y, color, piece, dest, fac)
4118 int x, y, color, fac;
4121 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
4123 if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
4124 XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
4125 squareSize, squareSize, x*fac, y*fac);
4127 if (useImages && useImageSqs) {
4131 pm = xpmLightSquare;
4136 case 2: /* neutral */
4141 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4142 squareSize, squareSize, x*fac, y*fac);
4152 case 2: /* neutral */
4157 XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
4162 I split out the routines to draw a piece so that I could
4163 make a generic flash routine.
4165 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4167 int square_color, x, y;
4170 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4171 switch (square_color) {
4173 case 2: /* neutral */
4175 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4176 ? *pieceToOutline(piece)
4177 : *pieceToSolid(piece),
4178 dest, bwPieceGC, 0, 0,
4179 squareSize, squareSize, x, y);
4182 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4183 ? *pieceToSolid(piece)
4184 : *pieceToOutline(piece),
4185 dest, wbPieceGC, 0, 0,
4186 squareSize, squareSize, x, y);
4191 static void monoDrawPiece(piece, square_color, x, y, dest)
4193 int square_color, x, y;
4196 switch (square_color) {
4198 case 2: /* neutral */
4200 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4201 ? *pieceToOutline(piece)
4202 : *pieceToSolid(piece),
4203 dest, bwPieceGC, 0, 0,
4204 squareSize, squareSize, x, y, 1);
4207 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4208 ? *pieceToSolid(piece)
4209 : *pieceToOutline(piece),
4210 dest, wbPieceGC, 0, 0,
4211 squareSize, squareSize, x, y, 1);
4216 static void colorDrawPiece(piece, square_color, x, y, dest)
4218 int square_color, x, y;
4221 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4222 switch (square_color) {
4224 XCopyPlane(xDisplay, *pieceToSolid(piece),
4225 dest, (int) piece < (int) BlackPawn
4226 ? wlPieceGC : blPieceGC, 0, 0,
4227 squareSize, squareSize, x, y, 1);
4230 XCopyPlane(xDisplay, *pieceToSolid(piece),
4231 dest, (int) piece < (int) BlackPawn
4232 ? wdPieceGC : bdPieceGC, 0, 0,
4233 squareSize, squareSize, x, y, 1);
4235 case 2: /* neutral */
4237 XCopyPlane(xDisplay, *pieceToSolid(piece),
4238 dest, (int) piece < (int) BlackPawn
4239 ? wjPieceGC : bjPieceGC, 0, 0,
4240 squareSize, squareSize, x, y, 1);
4245 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4247 int square_color, x, y;
4250 int kind, p = piece;
4252 switch (square_color) {
4254 case 2: /* neutral */
4256 if ((int)piece < (int) BlackPawn) {
4264 if ((int)piece < (int) BlackPawn) {
4272 if(appData.upsideDown && flipView) kind ^= 2; // swap white and black pieces
4273 if(useTexture & square_color+1) {
4274 BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background
4275 XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]);
4276 XSetClipOrigin(xDisplay, wlPieceGC, x, y);
4277 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y);
4278 XSetClipMask(xDisplay, wlPieceGC, None);
4279 XSetClipOrigin(xDisplay, wlPieceGC, 0, 0);
4281 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4282 dest, wlPieceGC, 0, 0,
4283 squareSize, squareSize, x, y);
4286 typedef void (*DrawFunc)();
4288 DrawFunc ChooseDrawFunc()
4290 if (appData.monoMode) {
4291 if (DefaultDepth(xDisplay, xScreen) == 1) {
4292 return monoDrawPiece_1bit;
4294 return monoDrawPiece;
4298 return colorDrawPieceImage;
4300 return colorDrawPiece;
4304 /* [HR] determine square color depending on chess variant. */
4305 static int SquareColor(row, column)
4310 if (gameInfo.variant == VariantXiangqi) {
4311 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4313 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4315 } else if (row <= 4) {
4321 square_color = ((column + row) % 2) == 1;
4324 /* [hgm] holdings: next line makes all holdings squares light */
4325 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4327 return square_color;
4330 void DrawSquare(row, column, piece, do_flash)
4331 int row, column, do_flash;
4334 int square_color, x, y, direction, font_ascent, font_descent;
4337 XCharStruct overall;
4341 /* Calculate delay in milliseconds (2-delays per complete flash) */
4342 flash_delay = 500 / appData.flashRate;
4345 x = lineGap + ((BOARD_WIDTH-1)-column) *
4346 (squareSize + lineGap);
4347 y = lineGap + row * (squareSize + lineGap);
4349 x = lineGap + column * (squareSize + lineGap);
4350 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4351 (squareSize + lineGap);
4354 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4356 square_color = SquareColor(row, column);
4358 if ( // [HGM] holdings: blank out area between board and holdings
4359 column == BOARD_LEFT-1 || column == BOARD_RGHT
4360 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4361 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4362 BlankSquare(x, y, 2, EmptySquare, xBoardWindow, 1);
4364 // [HGM] print piece counts next to holdings
4365 string[1] = NULLCHAR;
4366 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4367 string[0] = '0' + piece;
4368 XTextExtents(countFontStruct, string, 1, &direction,
4369 &font_ascent, &font_descent, &overall);
4370 if (appData.monoMode) {
4371 XDrawImageString(xDisplay, xBoardWindow, countGC,
4372 x + squareSize - overall.width - 2,
4373 y + font_ascent + 1, string, 1);
4375 XDrawString(xDisplay, xBoardWindow, countGC,
4376 x + squareSize - overall.width - 2,
4377 y + font_ascent + 1, string, 1);
4380 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4381 string[0] = '0' + piece;
4382 XTextExtents(countFontStruct, string, 1, &direction,
4383 &font_ascent, &font_descent, &overall);
4384 if (appData.monoMode) {
4385 XDrawImageString(xDisplay, xBoardWindow, countGC,
4386 x + 2, y + font_ascent + 1, string, 1);
4388 XDrawString(xDisplay, xBoardWindow, countGC,
4389 x + 2, y + font_ascent + 1, string, 1);
4393 if (piece == EmptySquare || appData.blindfold) {
4394 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4396 drawfunc = ChooseDrawFunc();
4397 if (do_flash && appData.flashCount > 0) {
4398 for (i=0; i<appData.flashCount; ++i) {
4400 drawfunc(piece, square_color, x, y, xBoardWindow);
4401 XSync(xDisplay, False);
4402 do_flash_delay(flash_delay);
4404 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4405 XSync(xDisplay, False);
4406 do_flash_delay(flash_delay);
4409 drawfunc(piece, square_color, x, y, xBoardWindow);
4413 string[1] = NULLCHAR;
4414 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4415 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4416 string[0] = 'a' + column - BOARD_LEFT;
4417 XTextExtents(coordFontStruct, string, 1, &direction,
4418 &font_ascent, &font_descent, &overall);
4419 if (appData.monoMode) {
4420 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4421 x + squareSize - overall.width - 2,
4422 y + squareSize - font_descent - 1, string, 1);
4424 XDrawString(xDisplay, xBoardWindow, coordGC,
4425 x + squareSize - overall.width - 2,
4426 y + squareSize - font_descent - 1, string, 1);
4429 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4430 string[0] = ONE + row;
4431 XTextExtents(coordFontStruct, string, 1, &direction,
4432 &font_ascent, &font_descent, &overall);
4433 if (appData.monoMode) {
4434 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4435 x + 2, y + font_ascent + 1, string, 1);
4437 XDrawString(xDisplay, xBoardWindow, coordGC,
4438 x + 2, y + font_ascent + 1, string, 1);
4441 if(!partnerUp && marker[row][column]) {
4442 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4443 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4448 /* Why is this needed on some versions of X? */
4449 void EventProc(widget, unused, event)
4454 if (!XtIsRealized(widget))
4457 switch (event->type) {
4459 if (event->xexpose.count > 0) return; /* no clipping is done */
4460 XDrawPosition(widget, True, NULL);
4461 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4462 flipView = !flipView; partnerUp = !partnerUp;
4463 XDrawPosition(widget, True, NULL);
4464 flipView = !flipView; partnerUp = !partnerUp;
4468 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
4475 void DrawPosition(fullRedraw, board)
4476 /*Boolean*/int fullRedraw;
4479 XDrawPosition(boardWidget, fullRedraw, board);
4482 /* Returns 1 if there are "too many" differences between b1 and b2
4483 (i.e. more than 1 move was made) */
4484 static int too_many_diffs(b1, b2)
4490 for (i=0; i<BOARD_HEIGHT; ++i) {
4491 for (j=0; j<BOARD_WIDTH; ++j) {
4492 if (b1[i][j] != b2[i][j]) {
4493 if (++c > 4) /* Castling causes 4 diffs */
4502 /* Matrix describing castling maneuvers */
4503 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4504 static int castling_matrix[4][5] = {
4505 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4506 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4507 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4508 { 7, 7, 4, 5, 6 } /* 0-0, black */
4511 /* Checks whether castling occurred. If it did, *rrow and *rcol
4512 are set to the destination (row,col) of the rook that moved.
4514 Returns 1 if castling occurred, 0 if not.
4516 Note: Only handles a max of 1 castling move, so be sure
4517 to call too_many_diffs() first.
4519 static int check_castle_draw(newb, oldb, rrow, rcol)
4526 /* For each type of castling... */
4527 for (i=0; i<4; ++i) {
4528 r = castling_matrix[i];
4530 /* Check the 4 squares involved in the castling move */
4532 for (j=1; j<=4; ++j) {
4533 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4540 /* All 4 changed, so it must be a castling move */
4549 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4550 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4552 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4555 void DrawSeekBackground( int left, int top, int right, int bottom )
4557 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4560 void DrawSeekText(char *buf, int x, int y)
4562 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4565 void DrawSeekDot(int x, int y, int colorNr)
4567 int square = colorNr & 0x80;
4570 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4572 XFillRectangle(xDisplay, xBoardWindow, color,
4573 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4575 XFillArc(xDisplay, xBoardWindow, color,
4576 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4579 static int damage[2][BOARD_RANKS][BOARD_FILES];
4582 * event handler for redrawing the board
4584 void XDrawPosition(w, repaint, board)
4586 /*Boolean*/int repaint;
4590 static int lastFlipView = 0;
4591 static int lastBoardValid[2] = {0, 0};
4592 static Board lastBoard[2];
4595 int nr = twoBoards*partnerUp;
4597 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4599 if (board == NULL) {
4600 if (!lastBoardValid[nr]) return;
4601 board = lastBoard[nr];
4603 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4604 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4605 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Flip View"),
4610 * It would be simpler to clear the window with XClearWindow()
4611 * but this causes a very distracting flicker.
4614 if ( lineGap && IsDrawArrowEnabled()) repaint = True;
4615 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4617 /* If too much changes (begin observing new game, etc.), don't
4619 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4621 /* Special check for castling so we don't flash both the king
4622 and the rook (just flash the king). */
4624 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4625 /* Draw rook with NO flashing. King will be drawn flashing later */
4626 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4627 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4631 /* First pass -- Draw (newly) empty squares and repair damage.
4632 This prevents you from having a piece show up twice while it
4633 is flashing on its new square */
4634 for (i = 0; i < BOARD_HEIGHT; i++)
4635 for (j = 0; j < BOARD_WIDTH; j++)
4636 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4637 || damage[nr][i][j]) {
4638 DrawSquare(i, j, board[i][j], 0);
4639 damage[nr][i][j] = False;
4642 /* Second pass -- Draw piece(s) in new position and flash them */
4643 for (i = 0; i < BOARD_HEIGHT; i++)
4644 for (j = 0; j < BOARD_WIDTH; j++)
4645 if (board[i][j] != lastBoard[nr][i][j]) {
4646 DrawSquare(i, j, board[i][j], do_flash);
4650 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4651 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4652 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4654 for (i = 0; i < BOARD_HEIGHT; i++)
4655 for (j = 0; j < BOARD_WIDTH; j++) {
4656 DrawSquare(i, j, board[i][j], 0);
4657 damage[nr][i][j] = False;
4661 CopyBoard(lastBoard[nr], board);
4662 lastBoardValid[nr] = 1;
4663 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4664 lastFlipView = flipView;
4666 /* Draw highlights */
4667 if (pm1X >= 0 && pm1Y >= 0) {
4668 drawHighlight(pm1X, pm1Y, prelineGC);
4670 if (pm2X >= 0 && pm2Y >= 0) {
4671 drawHighlight(pm2X, pm2Y, prelineGC);
4673 if (hi1X >= 0 && hi1Y >= 0) {
4674 drawHighlight(hi1X, hi1Y, highlineGC);
4676 if (hi2X >= 0 && hi2Y >= 0) {
4677 drawHighlight(hi2X, hi2Y, highlineGC);
4679 DrawArrowHighlight(hi1X, hi1Y, hi2X, hi2Y);
4681 /* If piece being dragged around board, must redraw that too */
4684 XSync(xDisplay, False);
4689 * event handler for redrawing the board
4691 void DrawPositionProc(w, event, prms, nprms)
4697 XDrawPosition(w, True, NULL);
4702 * event handler for parsing user moves
4704 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4705 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4706 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4707 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4708 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4709 // and at the end FinishMove() to perform the move after optional promotion popups.
4710 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4711 void HandleUserMove(w, event, prms, nprms)
4717 if (w != boardWidget || errorExitStatus != -1) return;
4718 if(nprms) shiftKey = !strcmp(prms[0], "1");
4721 if (event->type == ButtonPress) {
4722 XtPopdown(promotionShell);
4723 XtDestroyWidget(promotionShell);
4724 promotionUp = False;
4732 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4733 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4734 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4737 void AnimateUserMove (Widget w, XEvent * event,
4738 String * params, Cardinal * nParams)
4740 DragPieceMove(event->xmotion.x, event->xmotion.y);
4743 void HandlePV (Widget w, XEvent * event,
4744 String * params, Cardinal * nParams)
4745 { // [HGM] pv: walk PV
4746 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4749 Widget CommentCreate(name, text, mutable, callback, lines)
4751 int /*Boolean*/ mutable;
4752 XtCallbackProc callback;
4756 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4761 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4762 XtGetValues(boardWidget, args, j);
4765 XtSetArg(args[j], XtNresizable, True); j++;
4768 XtCreatePopupShell(name, topLevelShellWidgetClass,
4769 shellWidget, args, j);
4772 XtCreatePopupShell(name, transientShellWidgetClass,
4773 shellWidget, args, j);
4776 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4777 layoutArgs, XtNumber(layoutArgs));
4779 XtCreateManagedWidget("form", formWidgetClass, layout,
4780 formArgs, XtNumber(formArgs));
4784 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4785 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4787 XtSetArg(args[j], XtNstring, text); j++;
4788 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4789 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4790 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4791 XtSetArg(args[j], XtNright, XtChainRight); j++;
4792 XtSetArg(args[j], XtNresizable, True); j++;
4793 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4794 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4795 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4796 XtSetArg(args[j], XtNautoFill, True); j++;
4797 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4799 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4800 XtOverrideTranslations(edit, XtParseTranslationTable(commentTranslations));
4804 XtSetArg(args[j], XtNfromVert, edit); j++;
4805 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4806 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4807 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4808 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4810 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4811 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4814 XtSetArg(args[j], XtNfromVert, edit); j++;
4815 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4816 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4817 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4818 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4819 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4821 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4822 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4825 XtSetArg(args[j], XtNfromVert, edit); j++;
4826 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4827 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4828 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4829 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4830 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4832 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4833 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4836 XtSetArg(args[j], XtNfromVert, edit); j++;
4837 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4838 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4839 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4840 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4842 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4843 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4846 XtSetArg(args[j], XtNfromVert, edit); j++;
4847 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4848 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4849 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4850 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4851 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4853 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4854 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4857 XtRealizeWidget(shell);
4859 if (commentX == -1) {
4862 Dimension pw_height;
4863 Dimension ew_height;
4866 XtSetArg(args[j], XtNheight, &ew_height); j++;
4867 XtGetValues(edit, args, j);
4870 XtSetArg(args[j], XtNheight, &pw_height); j++;
4871 XtGetValues(shell, args, j);
4872 commentH = pw_height + (lines - 1) * ew_height;
4873 commentW = bw_width - 16;
4875 XSync(xDisplay, False);
4877 /* This code seems to tickle an X bug if it is executed too soon
4878 after xboard starts up. The coordinates get transformed as if
4879 the main window was positioned at (0, 0).
4881 XtTranslateCoords(shellWidget,
4882 (bw_width - commentW) / 2, 0 - commentH / 2,
4883 &commentX, &commentY);
4885 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4886 RootWindowOfScreen(XtScreen(shellWidget)),
4887 (bw_width - commentW) / 2, 0 - commentH / 2,
4892 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4895 if(wpComment.width > 0) {
4896 commentX = wpComment.x;
4897 commentY = wpComment.y;
4898 commentW = wpComment.width;
4899 commentH = wpComment.height;
4903 XtSetArg(args[j], XtNheight, commentH); j++;
4904 XtSetArg(args[j], XtNwidth, commentW); j++;
4905 XtSetArg(args[j], XtNx, commentX); j++;
4906 XtSetArg(args[j], XtNy, commentY); j++;
4907 XtSetValues(shell, args, j);
4908 XtSetKeyboardFocus(shell, edit);
4913 /* Used for analysis window and ICS input window */
4914 Widget MiscCreate(name, text, mutable, callback, lines)
4916 int /*Boolean*/ mutable;
4917 XtCallbackProc callback;
4921 Widget shell, layout, form, edit;
4923 Dimension bw_width, pw_height, ew_height, w, h;
4929 XtSetArg(args[j], XtNresizable, True); j++;
4932 XtCreatePopupShell(name, topLevelShellWidgetClass,
4933 shellWidget, args, j);
4936 XtCreatePopupShell(name, transientShellWidgetClass,
4937 shellWidget, args, j);
4940 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4941 layoutArgs, XtNumber(layoutArgs));
4943 XtCreateManagedWidget("form", formWidgetClass, layout,
4944 formArgs, XtNumber(formArgs));
4948 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4949 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4951 XtSetArg(args[j], XtNstring, text); j++;
4952 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4953 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4954 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4955 XtSetArg(args[j], XtNright, XtChainRight); j++;
4956 XtSetArg(args[j], XtNresizable, True); j++;
4957 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4958 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4959 XtSetArg(args[j], XtNautoFill, True); j++;
4960 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4962 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4964 XtRealizeWidget(shell);
4967 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4968 XtGetValues(boardWidget, args, j);
4971 XtSetArg(args[j], XtNheight, &ew_height); j++;
4972 XtGetValues(edit, args, j);
4975 XtSetArg(args[j], XtNheight, &pw_height); j++;
4976 XtGetValues(shell, args, j);
4977 h = pw_height + (lines - 1) * ew_height;
4980 XSync(xDisplay, False);
4982 /* This code seems to tickle an X bug if it is executed too soon
4983 after xboard starts up. The coordinates get transformed as if
4984 the main window was positioned at (0, 0).
4986 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4988 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4989 RootWindowOfScreen(XtScreen(shellWidget)),
4990 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4994 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4997 XtSetArg(args[j], XtNheight, h); j++;
4998 XtSetArg(args[j], XtNwidth, w); j++;
4999 XtSetArg(args[j], XtNx, x); j++;
5000 XtSetArg(args[j], XtNy, y); j++;
5001 XtSetValues(shell, args, j);
5007 static int savedIndex; /* gross that this is global */
5009 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
5012 XawTextPosition index, dummy;
5015 XawTextGetSelectionPos(w, &index, &dummy);
5016 XtSetArg(arg, XtNstring, &val);
5017 XtGetValues(w, &arg, 1);
5018 ReplaceComment(savedIndex, val);
5019 if(savedIndex != currentMove) ToNrEvent(savedIndex);
5020 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
5023 void EditCommentPopUp(index, title, text)
5032 if (text == NULL) text = "";
5034 if (editShell == NULL) {
5036 CommentCreate(title, text, True, EditCommentCallback, 4);
5037 XtRealizeWidget(editShell);
5038 CatchDeleteWindow(editShell, "EditCommentPopDown");
5040 edit = XtNameToWidget(editShell, "*form.text");
5042 XtSetArg(args[j], XtNstring, text); j++;
5043 XtSetValues(edit, args, j);
5045 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5046 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5047 XtSetValues(editShell, args, j);
5050 XtPopup(editShell, XtGrabNone);
5054 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5055 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"),
5057 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"),
5061 void EditCommentCallback(w, client_data, call_data)
5063 XtPointer client_data, call_data;
5071 XtSetArg(args[j], XtNlabel, &name); j++;
5072 XtGetValues(w, args, j);
5074 if (strcmp(name, _("ok")) == 0) {
5075 edit = XtNameToWidget(editShell, "*form.text");
5077 XtSetArg(args[j], XtNstring, &val); j++;
5078 XtGetValues(edit, args, j);
5079 ReplaceComment(savedIndex, val);
5080 EditCommentPopDown();
5081 } else if (strcmp(name, _("cancel")) == 0) {
5082 EditCommentPopDown();
5083 } else if (strcmp(name, _("clear")) == 0) {
5084 edit = XtNameToWidget(editShell, "*form.text");
5085 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5086 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5090 void EditCommentPopDown()
5095 if (!editUp) return;
5097 XtSetArg(args[j], XtNx, &commentX); j++;
5098 XtSetArg(args[j], XtNy, &commentY); j++;
5099 XtSetArg(args[j], XtNheight, &commentH); j++;
5100 XtSetArg(args[j], XtNwidth, &commentW); j++;
5101 XtGetValues(editShell, args, j);
5102 XtPopdown(editShell);
5105 XtSetArg(args[j], XtNleftBitmap, None); j++;
5106 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"),
5108 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"),
5112 void ICSInputBoxPopUp()
5117 char *title = _("ICS Input");
5120 if (ICSInputShell == NULL) {
5121 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
5122 tr = XtParseTranslationTable(ICSInputTranslations);
5123 edit = XtNameToWidget(ICSInputShell, "*form.text");
5124 XtOverrideTranslations(edit, tr);
5125 XtRealizeWidget(ICSInputShell);
5126 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
5129 edit = XtNameToWidget(ICSInputShell, "*form.text");
5131 XtSetArg(args[j], XtNstring, ""); j++;
5132 XtSetValues(edit, args, j);
5134 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5135 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5136 XtSetValues(ICSInputShell, args, j);
5139 XtPopup(ICSInputShell, XtGrabNone);
5140 XtSetKeyboardFocus(ICSInputShell, edit);
5142 ICSInputBoxUp = True;
5144 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5145 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.ICS Input Box"),
5149 void ICSInputSendText()
5156 edit = XtNameToWidget(ICSInputShell, "*form.text");
5158 XtSetArg(args[j], XtNstring, &val); j++;
5159 XtGetValues(edit, args, j);
5161 SendMultiLineToICS(val);
5162 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5163 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5166 void ICSInputBoxPopDown()
5171 if (!ICSInputBoxUp) return;
5173 XtPopdown(ICSInputShell);
5174 ICSInputBoxUp = False;
5176 XtSetArg(args[j], XtNleftBitmap, None); j++;
5177 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.ICS Input Box"),
5181 void CommentPopUp(title, text)
5188 savedIndex = currentMove; // [HGM] vari
5189 if (commentShell == NULL) {
5191 CommentCreate(title, text, False, CommentCallback, 4);
5192 XtRealizeWidget(commentShell);
5193 CatchDeleteWindow(commentShell, "CommentPopDown");
5195 edit = XtNameToWidget(commentShell, "*form.text");
5197 XtSetArg(args[j], XtNstring, text); j++;
5198 XtSetValues(edit, args, j);
5200 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5201 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5202 XtSetValues(commentShell, args, j);
5205 XtPopup(commentShell, XtGrabNone);
5206 XSync(xDisplay, False);
5211 void CommentCallback(w, client_data, call_data)
5213 XtPointer client_data, call_data;
5220 XtSetArg(args[j], XtNlabel, &name); j++;
5221 XtGetValues(w, args, j);
5223 if (strcmp(name, _("close")) == 0) {
5225 } else if (strcmp(name, _("edit")) == 0) {
5232 void CommentPopDown()
5237 if (!commentUp) return;
5239 XtSetArg(args[j], XtNx, &commentX); j++;
5240 XtSetArg(args[j], XtNy, &commentY); j++;
5241 XtSetArg(args[j], XtNwidth, &commentW); j++;
5242 XtSetArg(args[j], XtNheight, &commentH); j++;
5243 XtGetValues(commentShell, args, j);
5244 XtPopdown(commentShell);
5245 XSync(xDisplay, False);
5249 void FileNamePopUp(label, def, proc, openMode)
5255 fileProc = proc; /* I can't see a way not */
5256 fileOpenMode = openMode; /* to use globals here */
5257 { // [HGM] use file-selector dialog stolen from Ghostview
5259 int index; // this is not supported yet
5261 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5262 def, openMode, NULL, &name))
5263 (void) (*fileProc)(f, index=0, name);
5267 void FileNamePopDown()
5269 if (!filenameUp) return;
5270 XtPopdown(fileNameShell);
5271 XtDestroyWidget(fileNameShell);
5276 void FileNameCallback(w, client_data, call_data)
5278 XtPointer client_data, call_data;
5283 XtSetArg(args[0], XtNlabel, &name);
5284 XtGetValues(w, args, 1);
5286 if (strcmp(name, _("cancel")) == 0) {
5291 FileNameAction(w, NULL, NULL, NULL);
5294 void FileNameAction(w, event, prms, nprms)
5306 name = XawDialogGetValueString(w = XtParent(w));
5308 if ((name != NULL) && (*name != NULLCHAR)) {
5309 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
5310 XtPopdown(w = XtParent(XtParent(w)));
5314 p = strrchr(buf, ' ');
5321 fullname = ExpandPathName(buf);
5323 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5326 f = fopen(fullname, fileOpenMode);
5328 DisplayError(_("Failed to open file"), errno);
5330 (void) (*fileProc)(f, index, buf);
5337 XtPopdown(w = XtParent(XtParent(w)));
5343 void PromotionPopUp()
5346 Widget dialog, layout;
5348 Dimension bw_width, pw_width;
5352 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5353 XtGetValues(boardWidget, args, j);
5356 XtSetArg(args[j], XtNresizable, True); j++;
5357 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5359 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5360 shellWidget, args, j);
5362 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5363 layoutArgs, XtNumber(layoutArgs));
5366 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5367 XtSetArg(args[j], XtNborderWidth, 0); j++;
5368 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5371 if(gameInfo.variant != VariantShogi) {
5372 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) {
5373 XawDialogAddButton(dialog, _("Warlord"), PromotionCallback,
5374 (XtPointer) dialog);
5375 XawDialogAddButton(dialog, _("General"), PromotionCallback,
5376 (XtPointer) dialog);
5377 XawDialogAddButton(dialog, _("Lieutenant"), PromotionCallback,
5378 (XtPointer) dialog);
5379 XawDialogAddButton(dialog, _("Captain"), PromotionCallback,
5380 (XtPointer) dialog);
5382 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5383 (XtPointer) dialog);
5384 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5385 (XtPointer) dialog);
5386 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5387 (XtPointer) dialog);
5388 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5389 (XtPointer) dialog);
5391 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5392 gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
\r
5393 gameInfo.variant == VariantGiveaway) {
5394 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5395 (XtPointer) dialog);
5397 if(gameInfo.variant == VariantCapablanca ||
5398 gameInfo.variant == VariantGothic ||
5399 gameInfo.variant == VariantCapaRandom) {
5400 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5401 (XtPointer) dialog);
5402 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5403 (XtPointer) dialog);
5405 } else // [HGM] shogi
5407 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5408 (XtPointer) dialog);
5409 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5410 (XtPointer) dialog);
5412 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5413 (XtPointer) dialog);
5415 XtRealizeWidget(promotionShell);
5416 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5419 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5420 XtGetValues(promotionShell, args, j);
5422 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5423 lineGap + squareSize/3 +
5424 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5425 0 : 6*(squareSize + lineGap)), &x, &y);
5428 XtSetArg(args[j], XtNx, x); j++;
5429 XtSetArg(args[j], XtNy, y); j++;
5430 XtSetValues(promotionShell, args, j);
5432 XtPopup(promotionShell, XtGrabNone);
5437 void PromotionPopDown()
5439 if (!promotionUp) return;
5440 XtPopdown(promotionShell);
5441 XtDestroyWidget(promotionShell);
5442 promotionUp = False;
5445 void PromotionCallback(w, client_data, call_data)
5447 XtPointer client_data, call_data;
5453 XtSetArg(args[0], XtNlabel, &name);
5454 XtGetValues(w, args, 1);
5458 if (fromX == -1) return;
5460 if (strcmp(name, _("cancel")) == 0) {
5464 } else if (strcmp(name, _("Knight")) == 0) {
5466 } else if (strcmp(name, _("Promote")) == 0) {
5468 } else if (strcmp(name, _("Defer")) == 0) {
5471 promoChar = ToLower(name[0]);
5474 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5476 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5477 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5482 void ErrorCallback(w, client_data, call_data)
5484 XtPointer client_data, call_data;
5487 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5489 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5495 if (!errorUp) return;
5497 XtPopdown(errorShell);
5498 XtDestroyWidget(errorShell);
5499 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5502 void ErrorPopUp(title, label, modal)
5503 char *title, *label;
5507 Widget dialog, layout;
5511 Dimension bw_width, pw_width;
5512 Dimension pw_height;
5516 XtSetArg(args[i], XtNresizable, True); i++;
5517 XtSetArg(args[i], XtNtitle, title); i++;
5519 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5520 shellWidget, args, i);
5522 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5523 layoutArgs, XtNumber(layoutArgs));
5526 XtSetArg(args[i], XtNlabel, label); i++;
5527 XtSetArg(args[i], XtNborderWidth, 0); i++;
5528 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5531 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5533 XtRealizeWidget(errorShell);
5534 CatchDeleteWindow(errorShell, "ErrorPopDown");
5537 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5538 XtGetValues(boardWidget, args, i);
5540 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5541 XtSetArg(args[i], XtNheight, &pw_height); i++;
5542 XtGetValues(errorShell, args, i);
5545 /* This code seems to tickle an X bug if it is executed too soon
5546 after xboard starts up. The coordinates get transformed as if
5547 the main window was positioned at (0, 0).
5549 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5550 0 - pw_height + squareSize / 3, &x, &y);
5552 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5553 RootWindowOfScreen(XtScreen(boardWidget)),
5554 (bw_width - pw_width) / 2,
5555 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5559 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5562 XtSetArg(args[i], XtNx, x); i++;
5563 XtSetArg(args[i], XtNy, y); i++;
5564 XtSetValues(errorShell, args, i);
5567 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5570 /* Disable all user input other than deleting the window */
5571 static int frozen = 0;
5575 /* Grab by a widget that doesn't accept input */
5576 XtAddGrab(messageWidget, TRUE, FALSE);
5580 /* Undo a FreezeUI */
5583 if (!frozen) return;
5584 XtRemoveGrab(messageWidget);
5588 char *ModeToWidgetName(mode)
5592 case BeginningOfGame:
5593 if (appData.icsActive)
5594 return "menuMode.ICS Client";
5595 else if (appData.noChessProgram ||
5596 *appData.cmailGameName != NULLCHAR)
5597 return "menuMode.Edit Game";
5599 return "menuMode.Machine Black";
5600 case MachinePlaysBlack:
5601 return "menuMode.Machine Black";
5602 case MachinePlaysWhite:
5603 return "menuMode.Machine White";
5605 return "menuMode.Analysis Mode";
5607 return "menuMode.Analyze File";
5608 case TwoMachinesPlay:
5609 return "menuMode.Two Machines";
5611 return "menuMode.Edit Game";
5612 case PlayFromGameFile:
5613 return "menuFile.Load Game";
5615 return "menuMode.Edit Position";
5617 return "menuMode.Training";
5618 case IcsPlayingWhite:
5619 case IcsPlayingBlack:
5623 return "menuMode.ICS Client";
5630 void ModeHighlight()
5633 static int oldPausing = FALSE;
5634 static GameMode oldmode = (GameMode) -1;
5637 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5639 if (pausing != oldPausing) {
5640 oldPausing = pausing;
5642 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5644 XtSetArg(args[0], XtNleftBitmap, None);
5646 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5649 if (appData.showButtonBar) {
5650 /* Always toggle, don't set. Previous code messes up when
5651 invoked while the button is pressed, as releasing it
5652 toggles the state again. */
5655 XtSetArg(args[0], XtNbackground, &oldbg);
5656 XtSetArg(args[1], XtNforeground, &oldfg);
5657 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5659 XtSetArg(args[0], XtNbackground, oldfg);
5660 XtSetArg(args[1], XtNforeground, oldbg);
5662 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5666 wname = ModeToWidgetName(oldmode);
5667 if (wname != NULL) {
5668 XtSetArg(args[0], XtNleftBitmap, None);
5669 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5671 wname = ModeToWidgetName(gameMode);
5672 if (wname != NULL) {
5673 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5674 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5678 /* Maybe all the enables should be handled here, not just this one */
5679 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5680 gameMode == Training || gameMode == PlayFromGameFile);
5685 * Button/menu procedures
5687 void ResetProc(w, event, prms, nprms)
5696 int LoadGamePopUp(f, gameNumber, title)
5701 cmailMsgLoaded = FALSE;
5702 if (gameNumber == 0) {
5703 int error = GameListBuild(f);
5705 DisplayError(_("Cannot build game list"), error);
5706 } else if (!ListEmpty(&gameList) &&
5707 ((ListGame *) gameList.tailPred)->number > 1) {
5708 GameListPopUp(f, title);
5714 return LoadGame(f, gameNumber, title, FALSE);
5717 void LoadGameProc(w, event, prms, nprms)
5723 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5726 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5729 void LoadNextGameProc(w, event, prms, nprms)
5738 void LoadPrevGameProc(w, event, prms, nprms)
5747 void ReloadGameProc(w, event, prms, nprms)
5756 void LoadNextPositionProc(w, event, prms, nprms)
5765 void LoadPrevPositionProc(w, event, prms, nprms)
5774 void ReloadPositionProc(w, event, prms, nprms)
5783 void LoadPositionProc(w, event, prms, nprms)
5789 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5792 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5795 void SaveGameProc(w, event, prms, nprms)
5801 FileNamePopUp(_("Save game file name?"),
5802 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5806 void SavePositionProc(w, event, prms, nprms)
5812 FileNamePopUp(_("Save position file name?"),
5813 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5817 void ReloadCmailMsgProc(w, event, prms, nprms)
5823 ReloadCmailMsgEvent(FALSE);
5826 void MailMoveProc(w, event, prms, nprms)
5835 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5836 char *selected_fen_position=NULL;
5839 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5840 Atom *type_return, XtPointer *value_return,
5841 unsigned long *length_return, int *format_return)
5843 char *selection_tmp;
5845 if (!selected_fen_position) return False; /* should never happen */
5846 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5847 /* note: since no XtSelectionDoneProc was registered, Xt will
5848 * automatically call XtFree on the value returned. So have to
5849 * make a copy of it allocated with XtMalloc */
5850 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5851 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
5853 *value_return=selection_tmp;
5854 *length_return=strlen(selection_tmp);
5855 *type_return=*target;
5856 *format_return = 8; /* bits per byte */
5858 } else if (*target == XA_TARGETS(xDisplay)) {
5859 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5860 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5861 targets_tmp[1] = XA_STRING;
5862 *value_return = targets_tmp;
5863 *type_return = XA_ATOM;
5865 *format_return = 8 * sizeof(Atom);
5866 if (*format_return > 32) {
5867 *length_return *= *format_return / 32;
5868 *format_return = 32;
5876 /* note: when called from menu all parameters are NULL, so no clue what the
5877 * Widget which was clicked on was, or what the click event was
5879 void CopyPositionProc(w, event, prms, nprms)
5886 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5887 * have a notion of a position that is selected but not copied.
5888 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5890 if(gameMode == EditPosition) EditPositionDone(TRUE);
5891 if (selected_fen_position) free(selected_fen_position);
5892 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5893 if (!selected_fen_position) return;
5894 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5896 SendPositionSelection,
5897 NULL/* lose_ownership_proc */ ,
5898 NULL/* transfer_done_proc */);
5899 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5901 SendPositionSelection,
5902 NULL/* lose_ownership_proc */ ,
5903 NULL/* transfer_done_proc */);
5906 /* function called when the data to Paste is ready */
5908 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5909 Atom *type, XtPointer value, unsigned long *len, int *format)
5912 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5913 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5914 EditPositionPasteFEN(fenstr);
5918 /* called when Paste Position button is pressed,
5919 * all parameters will be NULL */
5920 void PastePositionProc(w, event, prms, nprms)
5926 XtGetSelectionValue(menuBarWidget,
5927 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5928 /* (XtSelectionCallbackProc) */ PastePositionCB,
5929 NULL, /* client_data passed to PastePositionCB */
5931 /* better to use the time field from the event that triggered the
5932 * call to this function, but that isn't trivial to get
5940 SendGameSelection(Widget w, Atom *selection, Atom *target,
5941 Atom *type_return, XtPointer *value_return,
5942 unsigned long *length_return, int *format_return)
5944 char *selection_tmp;
5946 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5947 FILE* f = fopen(gameCopyFilename, "r");
5950 if (f == NULL) return False;
5954 selection_tmp = XtMalloc(len + 1);
5955 count = fread(selection_tmp, 1, len, f);
5957 XtFree(selection_tmp);
5960 selection_tmp[len] = NULLCHAR;
5961 *value_return = selection_tmp;
5962 *length_return = len;
5963 *type_return = *target;
5964 *format_return = 8; /* bits per byte */
5966 } else if (*target == XA_TARGETS(xDisplay)) {
5967 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5968 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5969 targets_tmp[1] = XA_STRING;
5970 *value_return = targets_tmp;
5971 *type_return = XA_ATOM;
5973 *format_return = 8 * sizeof(Atom);
5974 if (*format_return > 32) {
5975 *length_return *= *format_return / 32;
5976 *format_return = 32;
5984 /* note: when called from menu all parameters are NULL, so no clue what the
5985 * Widget which was clicked on was, or what the click event was
5987 void CopyGameProc(w, event, prms, nprms)
5995 ret = SaveGameToFile(gameCopyFilename, FALSE);
5999 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
6000 * have a notion of a game that is selected but not copied.
6001 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
6003 XtOwnSelection(menuBarWidget, XA_PRIMARY,
6006 NULL/* lose_ownership_proc */ ,
6007 NULL/* transfer_done_proc */);
6008 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
6011 NULL/* lose_ownership_proc */ ,
6012 NULL/* transfer_done_proc */);
6015 /* function called when the data to Paste is ready */
6017 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
6018 Atom *type, XtPointer value, unsigned long *len, int *format)
6021 if (value == NULL || *len == 0) {
6022 return; /* nothing had been selected to copy */
6024 f = fopen(gamePasteFilename, "w");
6026 DisplayError(_("Can't open temp file"), errno);
6029 fwrite(value, 1, *len, f);
6032 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
6035 /* called when Paste Game button is pressed,
6036 * all parameters will be NULL */
6037 void PasteGameProc(w, event, prms, nprms)
6043 XtGetSelectionValue(menuBarWidget,
6044 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
6045 /* (XtSelectionCallbackProc) */ PasteGameCB,
6046 NULL, /* client_data passed to PasteGameCB */
6048 /* better to use the time field from the event that triggered the
6049 * call to this function, but that isn't trivial to get
6059 SaveGameProc(NULL, NULL, NULL, NULL);
6063 void QuitProc(w, event, prms, nprms)
6072 void PauseProc(w, event, prms, nprms)
6082 void MachineBlackProc(w, event, prms, nprms)
6088 MachineBlackEvent();
6091 void MachineWhiteProc(w, event, prms, nprms)
6097 MachineWhiteEvent();
6100 void AnalyzeModeProc(w, event, prms, nprms)
6108 if (!first.analysisSupport) {
6109 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6110 DisplayError(buf, 0);
6113 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
6114 if (appData.icsActive) {
6115 if (gameMode != IcsObserving) {
6116 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
6117 DisplayError(buf, 0);
6119 if (appData.icsEngineAnalyze) {
6120 if (appData.debugMode)
6121 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
6127 /* if enable, use want disable icsEngineAnalyze */
6128 if (appData.icsEngineAnalyze) {
6133 appData.icsEngineAnalyze = TRUE;
6134 if (appData.debugMode)
6135 fprintf(debugFP, _("ICS engine analyze starting... \n"));
6137 if (!appData.showThinking)
6138 ShowThinkingProc(w,event,prms,nprms);
6143 void AnalyzeFileProc(w, event, prms, nprms)
6149 if (!first.analysisSupport) {
6151 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6152 DisplayError(buf, 0);
6157 if (!appData.showThinking)
6158 ShowThinkingProc(w,event,prms,nprms);
6161 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
6162 AnalysisPeriodicEvent(1);
6165 void TwoMachinesProc(w, event, prms, nprms)
6174 void IcsClientProc(w, event, prms, nprms)
6183 void EditGameProc(w, event, prms, nprms)
6192 void EditPositionProc(w, event, prms, nprms)
6198 EditPositionEvent();
6201 void TrainingProc(w, event, prms, nprms)
6210 void EditCommentProc(w, event, prms, nprms)
6217 EditCommentPopDown();
6223 void IcsInputBoxProc(w, event, prms, nprms)
6229 if (ICSInputBoxUp) {
6230 ICSInputBoxPopDown();
6236 void AcceptProc(w, event, prms, nprms)
6245 void DeclineProc(w, event, prms, nprms)
6254 void RematchProc(w, event, prms, nprms)
6263 void CallFlagProc(w, event, prms, nprms)
6272 void DrawProc(w, event, prms, nprms)
6281 void AbortProc(w, event, prms, nprms)
6290 void AdjournProc(w, event, prms, nprms)
6299 void ResignProc(w, event, prms, nprms)
6308 void AdjuWhiteProc(w, event, prms, nprms)
6314 UserAdjudicationEvent(+1);
6317 void AdjuBlackProc(w, event, prms, nprms)
6323 UserAdjudicationEvent(-1);
6326 void AdjuDrawProc(w, event, prms, nprms)
6332 UserAdjudicationEvent(0);
6335 void EnterKeyProc(w, event, prms, nprms)
6341 if (ICSInputBoxUp == True)
6345 void UpKeyProc(w, event, prms, nprms)
6350 { // [HGM] input: let up-arrow recall previous line from history
6357 if (!ICSInputBoxUp) return;
6358 edit = XtNameToWidget(ICSInputShell, "*form.text");
6360 XtSetArg(args[j], XtNstring, &val); j++;
6361 XtGetValues(edit, args, j);
6362 val = PrevInHistory(val);
6363 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6364 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6366 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6367 XawTextReplace(edit, 0, 0, &t);
6368 XawTextSetInsertionPoint(edit, 9999);
6372 void DownKeyProc(w, event, prms, nprms)
6377 { // [HGM] input: let down-arrow recall next line from history
6382 if (!ICSInputBoxUp) return;
6383 edit = XtNameToWidget(ICSInputShell, "*form.text");
6384 val = NextInHistory();
6385 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6386 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6388 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6389 XawTextReplace(edit, 0, 0, &t);
6390 XawTextSetInsertionPoint(edit, 9999);
6394 void StopObservingProc(w, event, prms, nprms)
6400 StopObservingEvent();
6403 void StopExaminingProc(w, event, prms, nprms)
6409 StopExaminingEvent();
6412 void UploadProc(w, event, prms, nprms)
6422 void ForwardProc(w, event, prms, nprms)
6432 void BackwardProc(w, event, prms, nprms)
6441 void ToStartProc(w, event, prms, nprms)
6450 void ToEndProc(w, event, prms, nprms)
6459 void RevertProc(w, event, prms, nprms)
6468 void AnnotateProc(w, event, prms, nprms)
6477 void TruncateGameProc(w, event, prms, nprms)
6483 TruncateGameEvent();
6485 void RetractMoveProc(w, event, prms, nprms)
6494 void MoveNowProc(w, event, prms, nprms)
6504 void AlwaysQueenProc(w, event, prms, nprms)
6512 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6514 if (appData.alwaysPromoteToQueen) {
6515 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6517 XtSetArg(args[0], XtNleftBitmap, None);
6519 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6523 void AnimateDraggingProc(w, event, prms, nprms)
6531 appData.animateDragging = !appData.animateDragging;
6533 if (appData.animateDragging) {
6534 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6537 XtSetArg(args[0], XtNleftBitmap, None);
6539 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6543 void AnimateMovingProc(w, event, prms, nprms)
6551 appData.animate = !appData.animate;
6553 if (appData.animate) {
6554 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6557 XtSetArg(args[0], XtNleftBitmap, None);
6559 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6563 void AutocommProc(w, event, prms, nprms)
6571 appData.autoComment = !appData.autoComment;
6573 if (appData.autoComment) {
6574 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6576 XtSetArg(args[0], XtNleftBitmap, None);
6578 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6583 void AutoflagProc(w, event, prms, nprms)
6591 appData.autoCallFlag = !appData.autoCallFlag;
6593 if (appData.autoCallFlag) {
6594 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6596 XtSetArg(args[0], XtNleftBitmap, None);
6598 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6602 void AutoflipProc(w, event, prms, nprms)
6610 appData.autoFlipView = !appData.autoFlipView;
6612 if (appData.autoFlipView) {
6613 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6615 XtSetArg(args[0], XtNleftBitmap, None);
6617 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6621 void AutobsProc(w, event, prms, nprms)
6629 appData.autoObserve = !appData.autoObserve;
6631 if (appData.autoObserve) {
6632 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6634 XtSetArg(args[0], XtNleftBitmap, None);
6636 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6640 void AutoraiseProc(w, event, prms, nprms)
6648 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6650 if (appData.autoRaiseBoard) {
6651 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6653 XtSetArg(args[0], XtNleftBitmap, None);
6655 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6659 void AutosaveProc(w, event, prms, nprms)
6667 appData.autoSaveGames = !appData.autoSaveGames;
6669 if (appData.autoSaveGames) {
6670 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6672 XtSetArg(args[0], XtNleftBitmap, None);
6674 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6678 void BlindfoldProc(w, event, prms, nprms)
6686 appData.blindfold = !appData.blindfold;
6688 if (appData.blindfold) {
6689 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6691 XtSetArg(args[0], XtNleftBitmap, None);
6693 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6696 DrawPosition(True, NULL);
6699 void TestLegalityProc(w, event, prms, nprms)
6707 appData.testLegality = !appData.testLegality;
6709 if (appData.testLegality) {
6710 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6712 XtSetArg(args[0], XtNleftBitmap, None);
6714 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6719 void FlashMovesProc(w, event, prms, nprms)
6727 if (appData.flashCount == 0) {
6728 appData.flashCount = 3;
6730 appData.flashCount = -appData.flashCount;
6733 if (appData.flashCount > 0) {
6734 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6736 XtSetArg(args[0], XtNleftBitmap, None);
6738 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6742 void FlipViewProc(w, event, prms, nprms)
6748 flipView = !flipView;
6749 DrawPosition(True, NULL);
6752 void GetMoveListProc(w, event, prms, nprms)
6760 appData.getMoveList = !appData.getMoveList;
6762 if (appData.getMoveList) {
6763 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6766 XtSetArg(args[0], XtNleftBitmap, None);
6768 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6773 void HighlightDraggingProc(w, event, prms, nprms)
6781 appData.highlightDragging = !appData.highlightDragging;
6783 if (appData.highlightDragging) {
6784 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6786 XtSetArg(args[0], XtNleftBitmap, None);
6788 XtSetValues(XtNameToWidget(menuBarWidget,
6789 "menuOptions.Highlight Dragging"), args, 1);
6793 void HighlightLastMoveProc(w, event, prms, nprms)
6801 appData.highlightLastMove = !appData.highlightLastMove;
6803 if (appData.highlightLastMove) {
6804 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6806 XtSetArg(args[0], XtNleftBitmap, None);
6808 XtSetValues(XtNameToWidget(menuBarWidget,
6809 "menuOptions.Highlight Last Move"), args, 1);
6812 void HighlightArrowProc(w, event, prms, nprms)
6820 appData.highlightMoveWithArrow = !appData.highlightMoveWithArrow;
6822 if (appData.highlightMoveWithArrow) {
6823 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6825 XtSetArg(args[0], XtNleftBitmap, None);
6827 XtSetValues(XtNameToWidget(menuBarWidget,
6828 "menuOptions.Arrow"), args, 1);
6831 void IcsAlarmProc(w, event, prms, nprms)
6839 appData.icsAlarm = !appData.icsAlarm;
6841 if (appData.icsAlarm) {
6842 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6844 XtSetArg(args[0], XtNleftBitmap, None);
6846 XtSetValues(XtNameToWidget(menuBarWidget,
6847 "menuOptions.ICS Alarm"), args, 1);
6850 void MoveSoundProc(w, event, prms, nprms)
6858 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6860 if (appData.ringBellAfterMoves) {
6861 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6863 XtSetArg(args[0], XtNleftBitmap, None);
6865 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6869 void OneClickProc(w, event, prms, nprms)
6877 appData.oneClick = !appData.oneClick;
6879 if (appData.oneClick) {
6880 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6882 XtSetArg(args[0], XtNleftBitmap, None);
6884 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.OneClick"),
6888 void PeriodicUpdatesProc(w, event, prms, nprms)
6896 PeriodicUpdatesEvent(!appData.periodicUpdates);
6898 if (appData.periodicUpdates) {
6899 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6901 XtSetArg(args[0], XtNleftBitmap, None);
6903 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6907 void PonderNextMoveProc(w, event, prms, nprms)
6915 PonderNextMoveEvent(!appData.ponderNextMove);
6917 if (appData.ponderNextMove) {
6918 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6920 XtSetArg(args[0], XtNleftBitmap, None);
6922 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6926 void PopupExitMessageProc(w, event, prms, nprms)
6934 appData.popupExitMessage = !appData.popupExitMessage;
6936 if (appData.popupExitMessage) {
6937 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6939 XtSetArg(args[0], XtNleftBitmap, None);
6941 XtSetValues(XtNameToWidget(menuBarWidget,
6942 "menuOptions.Popup Exit Message"), args, 1);
6945 void PopupMoveErrorsProc(w, event, prms, nprms)
6953 appData.popupMoveErrors = !appData.popupMoveErrors;
6955 if (appData.popupMoveErrors) {
6956 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6958 XtSetArg(args[0], XtNleftBitmap, None);
6960 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6964 void PremoveProc(w, event, prms, nprms)
6972 appData.premove = !appData.premove;
6974 if (appData.premove) {
6975 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6977 XtSetArg(args[0], XtNleftBitmap, None);
6979 XtSetValues(XtNameToWidget(menuBarWidget,
6980 "menuOptions.Premove"), args, 1);
6983 void QuietPlayProc(w, event, prms, nprms)
6991 appData.quietPlay = !appData.quietPlay;
6993 if (appData.quietPlay) {
6994 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6996 XtSetArg(args[0], XtNleftBitmap, None);
6998 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
7002 void ShowCoordsProc(w, event, prms, nprms)
7010 appData.showCoords = !appData.showCoords;
7012 if (appData.showCoords) {
7013 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
7015 XtSetArg(args[0], XtNleftBitmap, None);
7017 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
7020 DrawPosition(True, NULL);
7023 void ShowThinkingProc(w, event, prms, nprms)
7029 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
7030 ShowThinkingEvent();
7033 void HideThinkingProc(w, event, prms, nprms)
7041 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
7042 ShowThinkingEvent();
7044 if (appData.hideThinkingFromHuman) {
7045 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
7047 XtSetArg(args[0], XtNleftBitmap, None);
7049 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
7053 void SaveOnExitProc(w, event, prms, nprms)
7061 saveSettingsOnExit = !saveSettingsOnExit;
7063 if (saveSettingsOnExit) {
7064 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
7066 XtSetArg(args[0], XtNleftBitmap, None);
7068 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
7072 void SaveSettingsProc(w, event, prms, nprms)
7078 SaveSettings(settingsFileName);
7081 void InfoProc(w, event, prms, nprms)
7088 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
7093 void ManProc(w, event, prms, nprms)
7101 if (nprms && *nprms > 0)
7105 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
7109 void HintProc(w, event, prms, nprms)
7118 void BookProc(w, event, prms, nprms)
7127 void AboutProc(w, event, prms, nprms)
7135 char *zippy = " (with Zippy code)";
7139 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
7140 programVersion, zippy,
7141 "Copyright 1991 Digital Equipment Corporation",
7142 "Enhancements Copyright 1992-2009 Free Software Foundation",
7143 "Enhancements Copyright 2005 Alessandro Scotti",
7144 PACKAGE, " is free software and carries NO WARRANTY;",
7145 "see the file COPYING for more information.");
7146 ErrorPopUp(_("About XBoard"), buf, FALSE);
7149 void DebugProc(w, event, prms, nprms)
7155 appData.debugMode = !appData.debugMode;
7158 void AboutGameProc(w, event, prms, nprms)
7167 void NothingProc(w, event, prms, nprms)
7176 void Iconify(w, event, prms, nprms)
7185 XtSetArg(args[0], XtNiconic, True);
7186 XtSetValues(shellWidget, args, 1);
7189 void DisplayMessage(message, extMessage)
7190 char *message, *extMessage;
7192 /* display a message in the message widget */
7201 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
7206 message = extMessage;
7210 /* need to test if messageWidget already exists, since this function
7211 can also be called during the startup, if for example a Xresource
7212 is not set up correctly */
7215 XtSetArg(arg, XtNlabel, message);
7216 XtSetValues(messageWidget, &arg, 1);
7222 void DisplayTitle(text)
7227 char title[MSG_SIZ];
7230 if (text == NULL) text = "";
7232 if (appData.titleInWindow) {
7234 XtSetArg(args[i], XtNlabel, text); i++;
7235 XtSetValues(titleWidget, args, i);
7238 if (*text != NULLCHAR) {
7239 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
7240 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
7241 } else if (appData.icsActive) {
7242 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7243 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7244 } else if (appData.cmailGameName[0] != NULLCHAR) {
7245 snprintf(icon, sizeof(icon), "%s", "CMail");
7246 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7248 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7249 } else if (gameInfo.variant == VariantGothic) {
7250 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7251 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
7254 } else if (gameInfo.variant == VariantFalcon) {
7255 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7256 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
7258 } else if (appData.noChessProgram) {
7259 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7260 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
7262 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
7263 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7266 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7267 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7268 XtSetValues(shellWidget, args, i);
7273 DisplayError(message, error)
7280 if (appData.debugMode || appData.matchMode) {
7281 fprintf(stderr, "%s: %s\n", programName, message);
7284 if (appData.debugMode || appData.matchMode) {
7285 fprintf(stderr, "%s: %s: %s\n",
7286 programName, message, strerror(error));
7288 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7291 ErrorPopUp(_("Error"), message, FALSE);
7295 void DisplayMoveError(message)
7300 DrawPosition(FALSE, NULL);
7301 if (appData.debugMode || appData.matchMode) {
7302 fprintf(stderr, "%s: %s\n", programName, message);
7304 if (appData.popupMoveErrors) {
7305 ErrorPopUp(_("Error"), message, FALSE);
7307 DisplayMessage(message, "");
7312 void DisplayFatalError(message, error, status)
7318 errorExitStatus = status;
7320 fprintf(stderr, "%s: %s\n", programName, message);
7322 fprintf(stderr, "%s: %s: %s\n",
7323 programName, message, strerror(error));
7324 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7327 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7328 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7334 void DisplayInformation(message)
7338 ErrorPopUp(_("Information"), message, TRUE);
7341 void DisplayNote(message)
7345 ErrorPopUp(_("Note"), message, FALSE);
7349 NullXErrorCheck(dpy, error_event)
7351 XErrorEvent *error_event;
7356 void DisplayIcsInteractionTitle(message)
7359 if (oldICSInteractionTitle == NULL) {
7360 /* Magic to find the old window title, adapted from vim */
7361 char *wina = getenv("WINDOWID");
7363 Window win = (Window) atoi(wina);
7364 Window root, parent, *children;
7365 unsigned int nchildren;
7366 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7368 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7369 if (!XQueryTree(xDisplay, win, &root, &parent,
7370 &children, &nchildren)) break;
7371 if (children) XFree((void *)children);
7372 if (parent == root || parent == 0) break;
7375 XSetErrorHandler(oldHandler);
7377 if (oldICSInteractionTitle == NULL) {
7378 oldICSInteractionTitle = "xterm";
7381 printf("\033]0;%s\007", message);
7385 char pendingReplyPrefix[MSG_SIZ];
7386 ProcRef pendingReplyPR;
7388 void AskQuestionProc(w, event, prms, nprms)
7395 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7399 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7402 void AskQuestionPopDown()
7404 if (!askQuestionUp) return;
7405 XtPopdown(askQuestionShell);
7406 XtDestroyWidget(askQuestionShell);
7407 askQuestionUp = False;
7410 void AskQuestionReplyAction(w, event, prms, nprms)
7420 reply = XawDialogGetValueString(w = XtParent(w));
7421 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
7422 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
7423 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
7424 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
7425 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7426 AskQuestionPopDown();
7428 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7431 void AskQuestionCallback(w, client_data, call_data)
7433 XtPointer client_data, call_data;
7438 XtSetArg(args[0], XtNlabel, &name);
7439 XtGetValues(w, args, 1);
7441 if (strcmp(name, _("cancel")) == 0) {
7442 AskQuestionPopDown();
7444 AskQuestionReplyAction(w, NULL, NULL, NULL);
7448 void AskQuestion(title, question, replyPrefix, pr)
7449 char *title, *question, *replyPrefix;
7453 Widget popup, layout, dialog, edit;
7459 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
7460 pendingReplyPR = pr;
7463 XtSetArg(args[i], XtNresizable, True); i++;
7464 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7465 askQuestionShell = popup =
7466 XtCreatePopupShell(title, transientShellWidgetClass,
7467 shellWidget, args, i);
7470 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7471 layoutArgs, XtNumber(layoutArgs));
7474 XtSetArg(args[i], XtNlabel, question); i++;
7475 XtSetArg(args[i], XtNvalue, ""); i++;
7476 XtSetArg(args[i], XtNborderWidth, 0); i++;
7477 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7480 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7481 (XtPointer) dialog);
7482 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7483 (XtPointer) dialog);
7485 XtRealizeWidget(popup);
7486 CatchDeleteWindow(popup, "AskQuestionPopDown");
7488 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7489 &x, &y, &win_x, &win_y, &mask);
7491 XtSetArg(args[0], XtNx, x - 10);
7492 XtSetArg(args[1], XtNy, y - 30);
7493 XtSetValues(popup, args, 2);
7495 XtPopup(popup, XtGrabExclusive);
7496 askQuestionUp = True;
7498 edit = XtNameToWidget(dialog, "*value");
7499 XtSetKeyboardFocus(popup, edit);
7507 if (*name == NULLCHAR) {
7509 } else if (strcmp(name, "$") == 0) {
7510 putc(BELLCHAR, stderr);
7513 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7521 PlaySound(appData.soundMove);
7527 PlaySound(appData.soundIcsWin);
7533 PlaySound(appData.soundIcsLoss);
7539 PlaySound(appData.soundIcsDraw);
7543 PlayIcsUnfinishedSound()
7545 PlaySound(appData.soundIcsUnfinished);
7551 PlaySound(appData.soundIcsAlarm);
7557 system("stty echo");
7563 system("stty -echo");
7567 Colorize(cc, continuation)
7572 int count, outCount, error;
7574 if (textColors[(int)cc].bg > 0) {
7575 if (textColors[(int)cc].fg > 0) {
7576 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7577 textColors[(int)cc].fg, textColors[(int)cc].bg);
7579 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7580 textColors[(int)cc].bg);
7583 if (textColors[(int)cc].fg > 0) {
7584 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7585 textColors[(int)cc].fg);
7587 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7590 count = strlen(buf);
7591 outCount = OutputToProcess(NoProc, buf, count, &error);
7592 if (outCount < count) {
7593 DisplayFatalError(_("Error writing to display"), error, 1);
7596 if (continuation) return;
7599 PlaySound(appData.soundShout);
7602 PlaySound(appData.soundSShout);
7605 PlaySound(appData.soundChannel1);
7608 PlaySound(appData.soundChannel);
7611 PlaySound(appData.soundKibitz);
7614 PlaySound(appData.soundTell);
7616 case ColorChallenge:
7617 PlaySound(appData.soundChallenge);
7620 PlaySound(appData.soundRequest);
7623 PlaySound(appData.soundSeek);
7634 return getpwuid(getuid())->pw_name;
7638 ExpandPathName(path)
7641 static char static_buf[4*MSG_SIZ];
7642 char *d, *s, buf[4*MSG_SIZ];
7648 while (*s && isspace(*s))
7657 if (*(s+1) == '/') {
7658 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7662 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7663 { char *p; if(p = strchr(buf, '/')) *p = 0; }
7664 pwd = getpwnam(buf);
7667 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7671 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7672 strcat(d, strchr(s+1, '/'));
7676 safeStrCpy(d, s, 4*MSG_SIZ );
7683 static char host_name[MSG_SIZ];
7685 #if HAVE_GETHOSTNAME
7686 gethostname(host_name, MSG_SIZ);
7688 #else /* not HAVE_GETHOSTNAME */
7689 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7690 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7692 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7694 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7695 #endif /* not HAVE_GETHOSTNAME */
7698 XtIntervalId delayedEventTimerXID = 0;
7699 DelayedEventCallback delayedEventCallback = 0;
7704 delayedEventTimerXID = 0;
7705 delayedEventCallback();
7709 ScheduleDelayedEvent(cb, millisec)
7710 DelayedEventCallback cb; long millisec;
7712 if(delayedEventTimerXID && delayedEventCallback == cb)
7713 // [HGM] alive: replace, rather than add or flush identical event
7714 XtRemoveTimeOut(delayedEventTimerXID);
7715 delayedEventCallback = cb;
7716 delayedEventTimerXID =
7717 XtAppAddTimeOut(appContext, millisec,
7718 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7721 DelayedEventCallback
7724 if (delayedEventTimerXID) {
7725 return delayedEventCallback;
7732 CancelDelayedEvent()
7734 if (delayedEventTimerXID) {
7735 XtRemoveTimeOut(delayedEventTimerXID);
7736 delayedEventTimerXID = 0;
7740 XtIntervalId loadGameTimerXID = 0;
7742 int LoadGameTimerRunning()
7744 return loadGameTimerXID != 0;
7747 int StopLoadGameTimer()
7749 if (loadGameTimerXID != 0) {
7750 XtRemoveTimeOut(loadGameTimerXID);
7751 loadGameTimerXID = 0;
7759 LoadGameTimerCallback(arg, id)
7763 loadGameTimerXID = 0;
7768 StartLoadGameTimer(millisec)
7772 XtAppAddTimeOut(appContext, millisec,
7773 (XtTimerCallbackProc) LoadGameTimerCallback,
7777 XtIntervalId analysisClockXID = 0;
7780 AnalysisClockCallback(arg, id)
7784 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7785 || appData.icsEngineAnalyze) { // [DM]
7786 AnalysisPeriodicEvent(0);
7787 StartAnalysisClock();
7792 StartAnalysisClock()
7795 XtAppAddTimeOut(appContext, 2000,
7796 (XtTimerCallbackProc) AnalysisClockCallback,
7800 XtIntervalId clockTimerXID = 0;
7802 int ClockTimerRunning()
7804 return clockTimerXID != 0;
7807 int StopClockTimer()
7809 if (clockTimerXID != 0) {
7810 XtRemoveTimeOut(clockTimerXID);
7819 ClockTimerCallback(arg, id)
7828 StartClockTimer(millisec)
7832 XtAppAddTimeOut(appContext, millisec,
7833 (XtTimerCallbackProc) ClockTimerCallback,
7838 DisplayTimerLabel(w, color, timer, highlight)
7847 /* check for low time warning */
7848 Pixel foregroundOrWarningColor = timerForegroundPixel;
7851 appData.lowTimeWarning &&
7852 (timer / 1000) < appData.icsAlarmTime)
7853 foregroundOrWarningColor = lowTimeWarningColor;
7855 if (appData.clockMode) {
7856 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7857 XtSetArg(args[0], XtNlabel, buf);
7859 snprintf(buf, MSG_SIZ, "%s ", color);
7860 XtSetArg(args[0], XtNlabel, buf);
7865 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7866 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7868 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7869 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7872 XtSetValues(w, args, 3);
7876 DisplayWhiteClock(timeRemaining, highlight)
7882 if(appData.noGUI) return;
7883 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7884 if (highlight && iconPixmap == bIconPixmap) {
7885 iconPixmap = wIconPixmap;
7886 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7887 XtSetValues(shellWidget, args, 1);
7892 DisplayBlackClock(timeRemaining, highlight)
7898 if(appData.noGUI) return;
7899 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7900 if (highlight && iconPixmap == wIconPixmap) {
7901 iconPixmap = bIconPixmap;
7902 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7903 XtSetValues(shellWidget, args, 1);
7921 int StartChildProcess(cmdLine, dir, pr)
7928 int to_prog[2], from_prog[2];
7932 if (appData.debugMode) {
7933 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7936 /* We do NOT feed the cmdLine to the shell; we just
7937 parse it into blank-separated arguments in the
7938 most simple-minded way possible.
7941 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7944 while(*p == ' ') p++;
7946 if(*p == '"' || *p == '\'')
7947 p = strchr(++argv[i-1], *p);
7948 else p = strchr(p, ' ');
7949 if (p == NULL) break;
7954 SetUpChildIO(to_prog, from_prog);
7956 if ((pid = fork()) == 0) {
7958 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7959 close(to_prog[1]); // first close the unused pipe ends
7960 close(from_prog[0]);
7961 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7962 dup2(from_prog[1], 1);
7963 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7964 close(from_prog[1]); // and closing again loses one of the pipes!
7965 if(fileno(stderr) >= 2) // better safe than sorry...
7966 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7968 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7973 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7975 execvp(argv[0], argv);
7977 /* If we get here, exec failed */
7982 /* Parent process */
7984 close(from_prog[1]);
7986 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7989 cp->fdFrom = from_prog[0];
7990 cp->fdTo = to_prog[1];
7995 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7996 static RETSIGTYPE AlarmCallBack(int n)
8002 DestroyChildProcess(pr, signalType)
8006 ChildProc *cp = (ChildProc *) pr;
8008 if (cp->kind != CPReal) return;
8010 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
8011 signal(SIGALRM, AlarmCallBack);
8013 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
8014 kill(cp->pid, SIGKILL); // kill it forcefully
8015 wait((int *) 0); // and wait again
8019 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
8021 /* Process is exiting either because of the kill or because of
8022 a quit command sent by the backend; either way, wait for it to die.
8031 InterruptChildProcess(pr)
8034 ChildProc *cp = (ChildProc *) pr;
8036 if (cp->kind != CPReal) return;
8037 (void) kill(cp->pid, SIGINT); /* stop it thinking */
8040 int OpenTelnet(host, port, pr)
8045 char cmdLine[MSG_SIZ];
8047 if (port[0] == NULLCHAR) {
8048 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
8050 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
8052 return StartChildProcess(cmdLine, "", pr);
8055 int OpenTCP(host, port, pr)
8061 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
8062 #else /* !OMIT_SOCKETS */
8064 struct sockaddr_in sa;
8066 unsigned short uport;
8069 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
8073 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
8074 sa.sin_family = AF_INET;
8075 sa.sin_addr.s_addr = INADDR_ANY;
8076 uport = (unsigned short) 0;
8077 sa.sin_port = htons(uport);
8078 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
8082 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
8083 if (!(hp = gethostbyname(host))) {
8085 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
8086 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
8087 hp->h_addrtype = AF_INET;
8089 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
8090 hp->h_addr_list[0] = (char *) malloc(4);
8091 hp->h_addr_list[0][0] = b0;
8092 hp->h_addr_list[0][1] = b1;
8093 hp->h_addr_list[0][2] = b2;
8094 hp->h_addr_list[0][3] = b3;
8099 sa.sin_family = hp->h_addrtype;
8100 uport = (unsigned short) atoi(port);
8101 sa.sin_port = htons(uport);
8102 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
8104 if (connect(s, (struct sockaddr *) &sa,
8105 sizeof(struct sockaddr_in)) < 0) {
8109 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8116 #endif /* !OMIT_SOCKETS */
8121 int OpenCommPort(name, pr)
8128 fd = open(name, 2, 0);
8129 if (fd < 0) return errno;
8131 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8141 int OpenLoopback(pr)
8147 SetUpChildIO(to, from);
8149 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8152 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
8159 int OpenRcmd(host, user, cmd, pr)
8160 char *host, *user, *cmd;
8163 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
8167 #define INPUT_SOURCE_BUF_SIZE 8192
8176 char buf[INPUT_SOURCE_BUF_SIZE];
8181 DoInputCallback(closure, source, xid)
8186 InputSource *is = (InputSource *) closure;
8191 if (is->lineByLine) {
8192 count = read(is->fd, is->unused,
8193 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
8195 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
8198 is->unused += count;
8200 while (p < is->unused) {
8201 q = memchr(p, '\n', is->unused - p);
8202 if (q == NULL) break;
8204 (is->func)(is, is->closure, p, q - p, 0);
8208 while (p < is->unused) {
8213 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8218 (is->func)(is, is->closure, is->buf, count, error);
8222 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8229 ChildProc *cp = (ChildProc *) pr;
8231 is = (InputSource *) calloc(1, sizeof(InputSource));
8232 is->lineByLine = lineByLine;
8236 is->fd = fileno(stdin);
8238 is->kind = cp->kind;
8239 is->fd = cp->fdFrom;
8242 is->unused = is->buf;
8245 is->xid = XtAppAddInput(appContext, is->fd,
8246 (XtPointer) (XtInputReadMask),
8247 (XtInputCallbackProc) DoInputCallback,
8249 is->closure = closure;
8250 return (InputSourceRef) is;
8254 RemoveInputSource(isr)
8257 InputSource *is = (InputSource *) isr;
8259 if (is->xid == 0) return;
8260 XtRemoveInput(is->xid);
8264 int OutputToProcess(pr, message, count, outError)
8270 static int line = 0;
8271 ChildProc *cp = (ChildProc *) pr;
8276 if (appData.noJoin || !appData.useInternalWrap)
8277 outCount = fwrite(message, 1, count, stdout);
8280 int width = get_term_width();
8281 int len = wrap(NULL, message, count, width, &line);
8282 char *msg = malloc(len);
8286 outCount = fwrite(message, 1, count, stdout);
8289 dbgchk = wrap(msg, message, count, width, &line);
8290 if (dbgchk != len && appData.debugMode)
8291 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8292 outCount = fwrite(msg, 1, dbgchk, stdout);
8298 outCount = write(cp->fdTo, message, count);
8308 /* Output message to process, with "ms" milliseconds of delay
8309 between each character. This is needed when sending the logon
8310 script to ICC, which for some reason doesn't like the
8311 instantaneous send. */
8312 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8319 ChildProc *cp = (ChildProc *) pr;
8324 r = write(cp->fdTo, message++, 1);
8337 /**** Animation code by Hugh Fisher, DCS, ANU.
8339 Known problem: if a window overlapping the board is
8340 moved away while a piece is being animated underneath,
8341 the newly exposed area won't be updated properly.
8342 I can live with this.
8344 Known problem: if you look carefully at the animation
8345 of pieces in mono mode, they are being drawn as solid
8346 shapes without interior detail while moving. Fixing
8347 this would be a major complication for minimal return.
8350 /* Masks for XPM pieces. Black and white pieces can have
8351 different shapes, but in the interest of retaining my
8352 sanity pieces must have the same outline on both light
8353 and dark squares, and all pieces must use the same
8354 background square colors/images. */
8356 static int xpmDone = 0;
8359 CreateAnimMasks (pieceDepth)
8366 unsigned long plane;
8369 /* Need a bitmap just to get a GC with right depth */
8370 buf = XCreatePixmap(xDisplay, xBoardWindow,
8372 values.foreground = 1;
8373 values.background = 0;
8374 /* Don't use XtGetGC, not read only */
8375 maskGC = XCreateGC(xDisplay, buf,
8376 GCForeground | GCBackground, &values);
8377 XFreePixmap(xDisplay, buf);
8379 buf = XCreatePixmap(xDisplay, xBoardWindow,
8380 squareSize, squareSize, pieceDepth);
8381 values.foreground = XBlackPixel(xDisplay, xScreen);
8382 values.background = XWhitePixel(xDisplay, xScreen);
8383 bufGC = XCreateGC(xDisplay, buf,
8384 GCForeground | GCBackground, &values);
8386 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8387 /* Begin with empty mask */
8388 if(!xpmDone) // [HGM] pieces: keep using existing
8389 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8390 squareSize, squareSize, 1);
8391 XSetFunction(xDisplay, maskGC, GXclear);
8392 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8393 0, 0, squareSize, squareSize);
8395 /* Take a copy of the piece */
8400 XSetFunction(xDisplay, bufGC, GXcopy);
8401 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8403 0, 0, squareSize, squareSize, 0, 0);
8405 /* XOR the background (light) over the piece */
8406 XSetFunction(xDisplay, bufGC, GXxor);
8408 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8409 0, 0, squareSize, squareSize, 0, 0);
8411 XSetForeground(xDisplay, bufGC, lightSquareColor);
8412 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8415 /* We now have an inverted piece image with the background
8416 erased. Construct mask by just selecting all the non-zero
8417 pixels - no need to reconstruct the original image. */
8418 XSetFunction(xDisplay, maskGC, GXor);
8420 /* Might be quicker to download an XImage and create bitmap
8421 data from it rather than this N copies per piece, but it
8422 only takes a fraction of a second and there is a much
8423 longer delay for loading the pieces. */
8424 for (n = 0; n < pieceDepth; n ++) {
8425 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8426 0, 0, squareSize, squareSize,
8432 XFreePixmap(xDisplay, buf);
8433 XFreeGC(xDisplay, bufGC);
8434 XFreeGC(xDisplay, maskGC);
8438 InitAnimState (anim, info)
8440 XWindowAttributes * info;
8445 /* Each buffer is square size, same depth as window */
8446 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8447 squareSize, squareSize, info->depth);
8448 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8449 squareSize, squareSize, info->depth);
8451 /* Create a plain GC for blitting */
8452 mask = GCForeground | GCBackground | GCFunction |
8453 GCPlaneMask | GCGraphicsExposures;
8454 values.foreground = XBlackPixel(xDisplay, xScreen);
8455 values.background = XWhitePixel(xDisplay, xScreen);
8456 values.function = GXcopy;
8457 values.plane_mask = AllPlanes;
8458 values.graphics_exposures = False;
8459 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8461 /* Piece will be copied from an existing context at
8462 the start of each new animation/drag. */
8463 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8465 /* Outline will be a read-only copy of an existing */
8466 anim->outlineGC = None;
8472 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8473 XWindowAttributes info;
8475 if (xpmDone && gameInfo.variant == old) return;
8476 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8477 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8479 InitAnimState(&game, &info);
8480 InitAnimState(&player, &info);
8482 /* For XPM pieces, we need bitmaps to use as masks. */
8484 CreateAnimMasks(info.depth);
8490 static Boolean frameWaiting;
8492 static RETSIGTYPE FrameAlarm (sig)
8495 frameWaiting = False;
8496 /* In case System-V style signals. Needed?? */
8497 signal(SIGALRM, FrameAlarm);
8504 struct itimerval delay;
8506 XSync(xDisplay, False);
8509 frameWaiting = True;
8510 signal(SIGALRM, FrameAlarm);
8511 delay.it_interval.tv_sec =
8512 delay.it_value.tv_sec = time / 1000;
8513 delay.it_interval.tv_usec =
8514 delay.it_value.tv_usec = (time % 1000) * 1000;
8515 setitimer(ITIMER_REAL, &delay, NULL);
8516 while (frameWaiting) pause();
8517 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8518 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8519 setitimer(ITIMER_REAL, &delay, NULL);
8529 XSync(xDisplay, False);
8531 usleep(time * 1000);
8536 /* Convert board position to corner of screen rect and color */
8539 ScreenSquare(column, row, pt, color)
8540 int column; int row; XPoint * pt; int * color;
8543 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8544 pt->y = lineGap + row * (squareSize + lineGap);
8546 pt->x = lineGap + column * (squareSize + lineGap);
8547 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8549 *color = SquareColor(row, column);
8552 /* Convert window coords to square */
8555 BoardSquare(x, y, column, row)
8556 int x; int y; int * column; int * row;
8558 *column = EventToSquare(x, BOARD_WIDTH);
8559 if (flipView && *column >= 0)
8560 *column = BOARD_WIDTH - 1 - *column;
8561 *row = EventToSquare(y, BOARD_HEIGHT);
8562 if (!flipView && *row >= 0)
8563 *row = BOARD_HEIGHT - 1 - *row;
8568 #undef Max /* just in case */
8570 #define Max(a, b) ((a) > (b) ? (a) : (b))
8571 #define Min(a, b) ((a) < (b) ? (a) : (b))
8574 SetRect(rect, x, y, width, height)
8575 XRectangle * rect; int x; int y; int width; int height;
8579 rect->width = width;
8580 rect->height = height;
8583 /* Test if two frames overlap. If they do, return
8584 intersection rect within old and location of
8585 that rect within new. */
8588 Intersect(old, new, size, area, pt)
8589 XPoint * old; XPoint * new;
8590 int size; XRectangle * area; XPoint * pt;
8592 if (old->x > new->x + size || new->x > old->x + size ||
8593 old->y > new->y + size || new->y > old->y + size) {
8596 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8597 size - abs(old->x - new->x), size - abs(old->y - new->y));
8598 pt->x = Max(old->x - new->x, 0);
8599 pt->y = Max(old->y - new->y, 0);
8604 /* For two overlapping frames, return the rect(s)
8605 in the old that do not intersect with the new. */
8608 CalcUpdateRects(old, new, size, update, nUpdates)
8609 XPoint * old; XPoint * new; int size;
8610 XRectangle update[]; int * nUpdates;
8614 /* If old = new (shouldn't happen) then nothing to draw */
8615 if (old->x == new->x && old->y == new->y) {
8619 /* Work out what bits overlap. Since we know the rects
8620 are the same size we don't need a full intersect calc. */
8622 /* Top or bottom edge? */
8623 if (new->y > old->y) {
8624 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8626 } else if (old->y > new->y) {
8627 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8628 size, old->y - new->y);
8631 /* Left or right edge - don't overlap any update calculated above. */
8632 if (new->x > old->x) {
8633 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8634 new->x - old->x, size - abs(new->y - old->y));
8636 } else if (old->x > new->x) {
8637 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8638 old->x - new->x, size - abs(new->y - old->y));
8645 /* Generate a series of frame coords from start->mid->finish.
8646 The movement rate doubles until the half way point is
8647 reached, then halves back down to the final destination,
8648 which gives a nice slow in/out effect. The algorithmn
8649 may seem to generate too many intermediates for short
8650 moves, but remember that the purpose is to attract the
8651 viewers attention to the piece about to be moved and
8652 then to where it ends up. Too few frames would be less
8656 Tween(start, mid, finish, factor, frames, nFrames)
8657 XPoint * start; XPoint * mid;
8658 XPoint * finish; int factor;
8659 XPoint frames[]; int * nFrames;
8661 int fraction, n, count;
8665 /* Slow in, stepping 1/16th, then 1/8th, ... */
8667 for (n = 0; n < factor; n++)
8669 for (n = 0; n < factor; n++) {
8670 frames[count].x = start->x + (mid->x - start->x) / fraction;
8671 frames[count].y = start->y + (mid->y - start->y) / fraction;
8673 fraction = fraction / 2;
8677 frames[count] = *mid;
8680 /* Slow out, stepping 1/2, then 1/4, ... */
8682 for (n = 0; n < factor; n++) {
8683 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8684 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8686 fraction = fraction * 2;
8691 /* Draw a piece on the screen without disturbing what's there */
8694 SelectGCMask(piece, clip, outline, mask)
8695 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8699 /* Bitmap for piece being moved. */
8700 if (appData.monoMode) {
8701 *mask = *pieceToSolid(piece);
8702 } else if (useImages) {
8704 *mask = xpmMask[piece];
8706 *mask = ximMaskPm[piece];
8709 *mask = *pieceToSolid(piece);
8712 /* GC for piece being moved. Square color doesn't matter, but
8713 since it gets modified we make a copy of the original. */
8715 if (appData.monoMode)
8720 if (appData.monoMode)
8725 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8727 /* Outline only used in mono mode and is not modified */
8729 *outline = bwPieceGC;
8731 *outline = wbPieceGC;
8735 OverlayPiece(piece, clip, outline, dest)
8736 ChessSquare piece; GC clip; GC outline; Drawable dest;
8741 /* Draw solid rectangle which will be clipped to shape of piece */
8742 XFillRectangle(xDisplay, dest, clip,
8743 0, 0, squareSize, squareSize);
8744 if (appData.monoMode)
8745 /* Also draw outline in contrasting color for black
8746 on black / white on white cases */
8747 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8748 0, 0, squareSize, squareSize, 0, 0, 1);
8750 /* Copy the piece */
8755 if(appData.upsideDown && flipView) kind ^= 2;
8756 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8758 0, 0, squareSize, squareSize,
8763 /* Animate the movement of a single piece */
8766 BeginAnimation(anim, piece, startColor, start)
8774 /* The old buffer is initialised with the start square (empty) */
8775 BlankSquare(start->x, start->y, startColor, EmptySquare, anim->saveBuf, 0);
8776 anim->prevFrame = *start;
8778 /* The piece will be drawn using its own bitmap as a matte */
8779 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8780 XSetClipMask(xDisplay, anim->pieceGC, mask);
8784 AnimationFrame(anim, frame, piece)
8789 XRectangle updates[4];
8794 /* Save what we are about to draw into the new buffer */
8795 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8796 frame->x, frame->y, squareSize, squareSize,
8799 /* Erase bits of the previous frame */
8800 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8801 /* Where the new frame overlapped the previous,
8802 the contents in newBuf are wrong. */
8803 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8804 overlap.x, overlap.y,
8805 overlap.width, overlap.height,
8807 /* Repaint the areas in the old that don't overlap new */
8808 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8809 for (i = 0; i < count; i++)
8810 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8811 updates[i].x - anim->prevFrame.x,
8812 updates[i].y - anim->prevFrame.y,
8813 updates[i].width, updates[i].height,
8814 updates[i].x, updates[i].y);
8816 /* Easy when no overlap */
8817 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8818 0, 0, squareSize, squareSize,
8819 anim->prevFrame.x, anim->prevFrame.y);
8822 /* Save this frame for next time round */
8823 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8824 0, 0, squareSize, squareSize,
8826 anim->prevFrame = *frame;
8828 /* Draw piece over original screen contents, not current,
8829 and copy entire rect. Wipes out overlapping piece images. */
8830 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8831 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8832 0, 0, squareSize, squareSize,
8833 frame->x, frame->y);
8837 EndAnimation (anim, finish)
8841 XRectangle updates[4];
8846 /* The main code will redraw the final square, so we
8847 only need to erase the bits that don't overlap. */
8848 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8849 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8850 for (i = 0; i < count; i++)
8851 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8852 updates[i].x - anim->prevFrame.x,
8853 updates[i].y - anim->prevFrame.y,
8854 updates[i].width, updates[i].height,
8855 updates[i].x, updates[i].y);
8857 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8858 0, 0, squareSize, squareSize,
8859 anim->prevFrame.x, anim->prevFrame.y);
8864 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8866 ChessSquare piece; int startColor;
8867 XPoint * start; XPoint * finish;
8868 XPoint frames[]; int nFrames;
8872 BeginAnimation(anim, piece, startColor, start);
8873 for (n = 0; n < nFrames; n++) {
8874 AnimationFrame(anim, &(frames[n]), piece);
8875 FrameDelay(appData.animSpeed);
8877 EndAnimation(anim, finish);
8881 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
8884 ChessSquare piece = board[fromY][toY];
8885 board[fromY][toY] = EmptySquare;
8886 DrawPosition(FALSE, board);
8888 x = lineGap + ((BOARD_WIDTH-1)-toX) * (squareSize + lineGap);
8889 y = lineGap + toY * (squareSize + lineGap);
8891 x = lineGap + toX * (squareSize + lineGap);
8892 y = lineGap + ((BOARD_HEIGHT-1)-toY) * (squareSize + lineGap);
8894 for(i=1; i<4*kFactor; i++) {
8895 int r = squareSize * 9 * i/(20*kFactor - 5);
8896 XFillArc(xDisplay, xBoardWindow, highlineGC,
8897 x + squareSize/2 - r, y+squareSize/2 - r, 2*r, 2*r, 0, 64*360);
8898 FrameDelay(appData.animSpeed);
8900 board[fromY][toY] = piece;
8903 /* Main control logic for deciding what to animate and how */
8906 AnimateMove(board, fromX, fromY, toX, toY)
8915 XPoint start, finish, mid;
8916 XPoint frames[kFactor * 2 + 1];
8917 int nFrames, startColor, endColor;
8919 /* Are we animating? */
8920 if (!appData.animate || appData.blindfold)
8923 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8924 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8925 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8927 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8928 piece = board[fromY][fromX];
8929 if (piece >= EmptySquare) return;
8934 hop = abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1;
8937 if (appData.debugMode) {
8938 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8939 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8940 piece, fromX, fromY, toX, toY); }
8942 ScreenSquare(fromX, fromY, &start, &startColor);
8943 ScreenSquare(toX, toY, &finish, &endColor);
8946 /* Knight: make straight movement then diagonal */
8947 if (abs(toY - fromY) < abs(toX - fromX)) {
8948 mid.x = start.x + (finish.x - start.x) / 2;
8952 mid.y = start.y + (finish.y - start.y) / 2;
8955 mid.x = start.x + (finish.x - start.x) / 2;
8956 mid.y = start.y + (finish.y - start.y) / 2;
8959 /* Don't use as many frames for very short moves */
8960 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8961 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8963 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8964 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8965 if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged
8967 for(i=0; i<BOARD_WIDTH; i++) for(j=0; j<BOARD_HEIGHT; j++)
8968 if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] = True;
8971 /* Be sure end square is redrawn */
8972 damage[0][toY][toX] = True;
8976 DragPieceBegin(x, y)
8979 int boardX, boardY, color;
8982 /* Are we animating? */
8983 if (!appData.animateDragging || appData.blindfold)
8986 /* Figure out which square we start in and the
8987 mouse position relative to top left corner. */
8988 BoardSquare(x, y, &boardX, &boardY);
8989 player.startBoardX = boardX;
8990 player.startBoardY = boardY;
8991 ScreenSquare(boardX, boardY, &corner, &color);
8992 player.startSquare = corner;
8993 player.startColor = color;
8994 /* As soon as we start dragging, the piece will jump slightly to
8995 be centered over the mouse pointer. */
8996 player.mouseDelta.x = squareSize/2;
8997 player.mouseDelta.y = squareSize/2;
8998 /* Initialise animation */
8999 player.dragPiece = PieceForSquare(boardX, boardY);
9001 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
9002 player.dragActive = True;
9003 BeginAnimation(&player, player.dragPiece, color, &corner);
9004 /* Mark this square as needing to be redrawn. Note that
9005 we don't remove the piece though, since logically (ie
9006 as seen by opponent) the move hasn't been made yet. */
9007 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
9008 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
9009 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
9010 corner.x, corner.y, squareSize, squareSize,
9011 0, 0); // [HGM] zh: unstack in stead of grab
9012 if(gatingPiece != EmptySquare) {
9013 /* Kludge alert: When gating we want the introduced
9014 piece to appear on the from square. To generate an
9015 image of it, we draw it on the board, copy the image,
9016 and draw the original piece again. */
9017 ChessSquare piece = boards[currentMove][boardY][boardX];
9018 DrawSquare(boardY, boardX, gatingPiece, 0);
9019 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
9020 corner.x, corner.y, squareSize, squareSize, 0, 0);
9021 DrawSquare(boardY, boardX, piece, 0);
9023 damage[0][boardY][boardX] = True;
9025 player.dragActive = False;
9035 /* Are we animating? */
9036 if (!appData.animateDragging || appData.blindfold)
9040 if (! player.dragActive)
9042 /* Move piece, maintaining same relative position
9043 of mouse within square */
9044 corner.x = x - player.mouseDelta.x;
9045 corner.y = y - player.mouseDelta.y;
9046 AnimationFrame(&player, &corner, player.dragPiece);
9048 if (appData.highlightDragging) {
9050 BoardSquare(x, y, &boardX, &boardY);
9051 SetHighlights(fromX, fromY, boardX, boardY);
9060 int boardX, boardY, color;
9063 /* Are we animating? */
9064 if (!appData.animateDragging || appData.blindfold)
9068 if (! player.dragActive)
9070 /* Last frame in sequence is square piece is
9071 placed on, which may not match mouse exactly. */
9072 BoardSquare(x, y, &boardX, &boardY);
9073 ScreenSquare(boardX, boardY, &corner, &color);
9074 EndAnimation(&player, &corner);
9076 /* Be sure end square is redrawn */
9077 damage[0][boardY][boardX] = True;
9079 /* This prevents weird things happening with fast successive
9080 clicks which on my Sun at least can cause motion events
9081 without corresponding press/release. */
9082 player.dragActive = False;
9085 /* Handle expose event while piece being dragged */
9090 if (!player.dragActive || appData.blindfold)
9093 /* What we're doing: logically, the move hasn't been made yet,
9094 so the piece is still in it's original square. But visually
9095 it's being dragged around the board. So we erase the square
9096 that the piece is on and draw it at the last known drag point. */
9097 BlankSquare(player.startSquare.x, player.startSquare.y,
9098 player.startColor, EmptySquare, xBoardWindow, 1);
9099 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
9100 damage[0][player.startBoardY][player.startBoardX] = TRUE;
9103 #include <sys/ioctl.h>
9104 int get_term_width()
9106 int fd, default_width;
9109 default_width = 79; // this is FICS default anyway...
9111 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
9113 if (!ioctl(fd, TIOCGSIZE, &win))
9114 default_width = win.ts_cols;
9115 #elif defined(TIOCGWINSZ)
9117 if (!ioctl(fd, TIOCGWINSZ, &win))
9118 default_width = win.ws_col;
9120 return default_width;
9126 static int old_width = 0;
9127 int new_width = get_term_width();
9129 if (old_width != new_width)
9130 ics_printf("set width %d\n", new_width);
9131 old_width = new_width;
9134 void NotifyFrontendLogin()
9139 /* [AS] Arrow highlighting support */
9141 static double A_WIDTH = 5; /* Width of arrow body */
9143 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
9144 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
9146 static double Sqr( double x )
9151 static int Round( double x )
9153 return (int) (x + 0.5);
9156 void SquareToPos(int rank, int file, int *x, int *y)
9159 *x = lineGap + ((BOARD_WIDTH-1)-file) * (squareSize + lineGap);
9160 *y = lineGap + rank * (squareSize + lineGap);
9162 *x = lineGap + file * (squareSize + lineGap);
9163 *y = lineGap + ((BOARD_HEIGHT-1)-rank) * (squareSize + lineGap);
9167 /* Draw an arrow between two points using current settings */
9168 void DrawArrowBetweenPoints( int s_x, int s_y, int d_x, int d_y )
9171 double dx, dy, j, k, x, y;
9174 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
9176 arrow[0].x = s_x + A_WIDTH + 0.5;
9179 arrow[1].x = s_x + A_WIDTH + 0.5;
9180 arrow[1].y = d_y - h;
9182 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9183 arrow[2].y = d_y - h;
9188 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
9189 arrow[5].y = d_y - h;
9191 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9192 arrow[4].y = d_y - h;
9194 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
9197 else if( d_y == s_y ) {
9198 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
9201 arrow[0].y = s_y + A_WIDTH + 0.5;
9203 arrow[1].x = d_x - w;
9204 arrow[1].y = s_y + A_WIDTH + 0.5;
9206 arrow[2].x = d_x - w;
9207 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9212 arrow[5].x = d_x - w;
9213 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
9215 arrow[4].x = d_x - w;
9216 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9219 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
9222 /* [AS] Needed a lot of paper for this! :-) */
9223 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
9224 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
9226 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
9228 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
9233 arrow[0].x = Round(x - j);
9234 arrow[0].y = Round(y + j*dx);
9236 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
9237 arrow[1].y = Round(arrow[0].y - 2*j*dx);
9240 x = (double) d_x - k;
9241 y = (double) d_y - k*dy;
9244 x = (double) d_x + k;
9245 y = (double) d_y + k*dy;
9248 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
9250 arrow[6].x = Round(x - j);
9251 arrow[6].y = Round(y + j*dx);
9253 arrow[2].x = Round(arrow[6].x + 2*j);
9254 arrow[2].y = Round(arrow[6].y - 2*j*dx);
9256 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
9257 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
9262 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
9263 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
9266 XFillPolygon(xDisplay, xBoardWindow, highlineGC, arrow, 7, Nonconvex, CoordModeOrigin);
9267 // Polygon( hdc, arrow, 7 );
9270 /* [AS] Draw an arrow between two squares */
9271 void DrawArrowBetweenSquares( int s_col, int s_row, int d_col, int d_row )
9273 int s_x, s_y, d_x, d_y, hor, vert, i;
9275 if( s_col == d_col && s_row == d_row ) {
9279 /* Get source and destination points */
9280 SquareToPos( s_row, s_col, &s_x, &s_y);
9281 SquareToPos( d_row, d_col, &d_x, &d_y);
9284 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
9286 else if( d_y < s_y ) {
9287 d_y += squareSize / 2 + squareSize / 4;
9290 d_y += squareSize / 2;
9294 d_x += squareSize / 2 - squareSize / 4;
9296 else if( d_x < s_x ) {
9297 d_x += squareSize / 2 + squareSize / 4;
9300 d_x += squareSize / 2;
9303 s_x += squareSize / 2;
9304 s_y += squareSize / 2;
9307 A_WIDTH = squareSize / 14.; //[HGM] make float
9309 DrawArrowBetweenPoints( s_x, s_y, d_x, d_y );
9312 // this is a good idea, but it only works when lineGap == 0, because 'damage' on grid lines is not repaired
9313 hor = 64*s_col + 32; vert = 64*s_row + 32;
9314 for(i=0; i<= 64; i++) {
9315 damage[0][vert+6>>6][hor+6>>6] = True;
9316 damage[0][vert-6>>6][hor+6>>6] = True;
9317 damage[0][vert+6>>6][hor-6>>6] = True;
9318 damage[0][vert-6>>6][hor-6>>6] = True;
9319 hor += d_col - s_col; vert += d_row - s_row;
9324 Boolean IsDrawArrowEnabled()
9326 return appData.highlightMoveWithArrow && squareSize >= 32;
9329 void DrawArrowHighlight(int fromX, int fromY, int toX,int toY)
9331 if( IsDrawArrowEnabled() && fromX >= 0 && fromY >= 0 && toX >= 0 && toY >= 0)
9332 DrawArrowBetweenSquares(fromX, fromY, toX, toY);