2 * xboard.c -- X front end for XBoard
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
8 * 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
10 * The following terms apply to Digital Equipment Corporation's copyright
12 * ------------------------------------------------------------------------
15 * Permission to use, copy, modify, and distribute this software and its
16 * documentation for any purpose and without fee is hereby granted,
17 * provided that the above copyright notice appear in all copies and that
18 * both that copyright notice and this permission notice appear in
19 * supporting documentation, and that the name of Digital not be
20 * used in advertising or publicity pertaining to distribution of the
21 * software without specific, written prior permission.
23 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
30 * ------------------------------------------------------------------------
32 * The following terms apply to the enhanced version of XBoard
33 * distributed by the Free Software Foundation:
34 * ------------------------------------------------------------------------
36 * GNU XBoard is free software: you can redistribute it and/or modify
37 * it under the terms of the GNU General Public License as published by
38 * the Free Software Foundation, either version 3 of the License, or (at
39 * your option) any later version.
41 * GNU XBoard is distributed in the hope that it will be useful, but
42 * WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44 * General Public License for more details.
46 * You should have received a copy of the GNU General Public License
47 * along with this program. If not, see http://www.gnu.org/licenses/. *
49 *------------------------------------------------------------------------
50 ** See the file ChangeLog for a revision history. */
60 #include <sys/types.h>
66 # if HAVE_SYS_SOCKET_H
67 # include <sys/socket.h>
68 # include <netinet/in.h>
70 # else /* not HAVE_SYS_SOCKET_H */
71 # if HAVE_LAN_SOCKET_H
72 # include <lan/socket.h>
74 # include <lan/netdb.h>
75 # else /* not HAVE_LAN_SOCKET_H */
76 # define OMIT_SOCKETS 1
77 # endif /* not HAVE_LAN_SOCKET_H */
78 # endif /* not HAVE_SYS_SOCKET_H */
79 #endif /* !OMIT_SOCKETS */
84 #else /* not STDC_HEADERS */
85 extern char *getenv();
88 # else /* not HAVE_STRING_H */
90 # endif /* not HAVE_STRING_H */
91 #endif /* not STDC_HEADERS */
94 # include <sys/fcntl.h>
95 #else /* not HAVE_SYS_FCNTL_H */
98 # endif /* HAVE_FCNTL_H */
99 #endif /* not HAVE_SYS_FCNTL_H */
101 #if HAVE_SYS_SYSTEMINFO_H
102 # include <sys/systeminfo.h>
103 #endif /* HAVE_SYS_SYSTEMINFO_H */
105 #if TIME_WITH_SYS_TIME
106 # include <sys/time.h>
110 # include <sys/time.h>
121 # include <sys/wait.h>
126 # define NAMLEN(dirent) strlen((dirent)->d_name)
127 # define HAVE_DIR_STRUCT
129 # define dirent direct
130 # define NAMLEN(dirent) (dirent)->d_namlen
132 # include <sys/ndir.h>
133 # define HAVE_DIR_STRUCT
136 # include <sys/dir.h>
137 # define HAVE_DIR_STRUCT
141 # define HAVE_DIR_STRUCT
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((int redo));
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 AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
396 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
397 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
398 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
400 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
401 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
403 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
405 void HighlightArrowProc P((Widget w, XEvent *event, String *prms,
407 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
408 //void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
409 void OneClickProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
410 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
412 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
414 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
416 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
418 //void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
419 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
421 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
423 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
425 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
427 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
428 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
429 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
430 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
431 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
432 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
433 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
434 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
435 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
436 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
437 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void DisplayMove P((int moveNumber));
439 void DisplayTitle P((char *title));
440 void ICSInitScript P((void));
441 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
442 void ErrorPopUp P((char *title, char *text, int modal));
443 void ErrorPopDown P((void));
444 static char *ExpandPathName P((char *path));
445 static void CreateAnimVars P((void));
446 static void DragPieceMove P((int x, int y));
447 static void DrawDragPiece P((void));
448 char *ModeToWidgetName P((GameMode mode));
449 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
450 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
451 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
452 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
453 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
454 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
455 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
456 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
457 void BoardOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
458 void LoadOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
459 void SaveOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
460 void GameListOptionsPopDown P(());
461 void ShufflePopDown P(());
462 void EnginePopDown P(());
463 void UciPopDown P(());
464 void TimeControlPopDown P(());
465 void NewVariantPopDown P(());
466 void SettingsPopDown P(());
467 void update_ics_width P(());
468 int get_term_width P(());
469 int CopyMemoProc P(());
470 void DrawArrowHighlight P((int fromX, int fromY, int toX,int toY));
471 Boolean IsDrawArrowEnabled P(());
474 * XBoard depends on Xt R4 or higher
476 int xtVersion = XtSpecificationRelease;
481 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
482 jailSquareColor, highlightSquareColor, premoveHighlightColor;
483 Pixel lowTimeWarningColor;
484 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
485 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
486 wjPieceGC, bjPieceGC, prelineGC, countGC;
487 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
488 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
489 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
490 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
491 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
492 ICSInputShell, fileNameShell, askQuestionShell;
493 Widget historyShell, evalGraphShell, gameListShell;
494 int hOffset; // [HGM] dual
495 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
496 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
497 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
498 Font clockFontID, coordFontID, countFontID;
499 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
500 XtAppContext appContext;
502 char *oldICSInteractionTitle;
506 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
508 Position commentX = -1, commentY = -1;
509 Dimension commentW, commentH;
510 typedef unsigned int BoardSize;
512 Boolean chessProgram;
514 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
515 int squareSize, smallLayout = 0, tinyLayout = 0,
516 marginW, marginH, // [HGM] for run-time resizing
517 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
518 ICSInputBoxUp = False, askQuestionUp = False,
519 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
520 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
521 Pixel timerForegroundPixel, timerBackgroundPixel;
522 Pixel buttonForegroundPixel, buttonBackgroundPixel;
523 char *chessDir, *programName, *programVersion,
524 *gameCopyFilename, *gamePasteFilename;
525 Boolean alwaysOnTop = False;
526 Boolean saveSettingsOnExit;
527 char *settingsFileName;
528 char *icsTextMenuString;
530 char *firstChessProgramNames;
531 char *secondChessProgramNames;
533 WindowPlacement wpMain;
534 WindowPlacement wpConsole;
535 WindowPlacement wpComment;
536 WindowPlacement wpMoveHistory;
537 WindowPlacement wpEvalGraph;
538 WindowPlacement wpEngineOutput;
539 WindowPlacement wpGameList;
540 WindowPlacement wpTags;
544 Pixmap pieceBitmap[2][(int)BlackPawn];
545 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
546 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
547 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
548 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
549 Pixmap xpmBoardBitmap[2];
550 int useImages, useImageSqs, useTexture, textureW[2], textureH[2];
551 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
552 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
553 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
554 XImage *ximLightSquare, *ximDarkSquare;
557 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
558 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
560 #define White(piece) ((int)(piece) < (int)BlackPawn)
562 /* Variables for doing smooth animation. This whole thing
563 would be much easier if the board was double-buffered,
564 but that would require a fairly major rewrite. */
569 GC blitGC, pieceGC, outlineGC;
570 XPoint startSquare, prevFrame, mouseDelta;
574 int startBoardX, startBoardY;
577 /* There can be two pieces being animated at once: a player
578 can begin dragging a piece before the remote opponent has moved. */
580 static AnimState game, player;
582 /* Bitmaps for use as masks when drawing XPM pieces.
583 Need one for each black and white piece. */
584 static Pixmap xpmMask[BlackKing + 1];
586 /* This magic number is the number of intermediate frames used
587 in each half of the animation. For short moves it's reduced
588 by 1. The total number of frames will be factor * 2 + 1. */
591 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
593 MenuItem fileMenu[] = {
594 {N_("New Game Ctrl+N"), "New Game", ResetProc},
595 {N_("New Shuffle Game ..."), "New Shuffle Game", ShuffleMenuProc},
596 {N_("New Variant ... Alt+Shift+V"), "New Variant", NewVariantProc}, // [HGM] variant: not functional yet
597 {"----", NULL, NothingProc},
598 {N_("Load Game Ctrl+O"), "Load Game", LoadGameProc},
599 {N_("Load Position Ctrl+Shift+O"), "Load Position", LoadPositionProc},
600 // {N_("Load Next Game"), "Load Next Game", LoadNextGameProc},
601 // {N_("Load Previous Game"), "Load Previous Game", LoadPrevGameProc},
602 // {N_("Reload Same Game"), "Reload Same Game", ReloadGameProc},
603 {N_("Next Position Shift+PgDn"), "Load Next Position", LoadNextPositionProc},
604 {N_("Prev Position Shift+PgUp"), "Load Previous Position", LoadPrevPositionProc},
605 {"----", NULL, NothingProc},
606 // {N_("Reload Same Position"), "Reload Same Position", ReloadPositionProc},
607 {N_("Save Game Ctrl+S"), "Save Game", SaveGameProc},
608 {N_("Save Position Ctrl+Shift+S"), "Save Position", SavePositionProc},
609 {"----", NULL, NothingProc},
610 {N_("Mail Move"), "Mail Move", MailMoveProc},
611 {N_("Reload CMail Message"), "Reload CMail Message", ReloadCmailMsgProc},
612 {"----", NULL, NothingProc},
613 {N_("Quit Ctr+Q"), "Exit", QuitProc},
617 MenuItem editMenu[] = {
618 {N_("Copy Game Ctrl+C"), "Copy Game", CopyGameProc},
619 {N_("Copy Position Ctrl+Shift+C"), "Copy Position", CopyPositionProc},
620 {"----", NULL, NothingProc},
621 {N_("Paste Game Ctrl+V"), "Paste Game", PasteGameProc},
622 {N_("Paste Position Ctrl+Shift+V"), "Paste Position", PastePositionProc},
623 {"----", NULL, NothingProc},
624 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
625 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
626 {N_("Edit Tags"), "Edit Tags", EditTagsProc},
627 {N_("Edit Comment"), "Edit Comment", EditCommentProc},
628 {"----", NULL, NothingProc},
629 {N_("Revert Home"), "Revert", RevertProc},
630 {N_("Annotate"), "Annotate", AnnotateProc},
631 {N_("Truncate Game End"), "Truncate Game", TruncateGameProc},
632 {"----", NULL, NothingProc},
633 {N_("Backward Alt+Left"), "Backward", BackwardProc},
634 {N_("Forward Alt+Right"), "Forward", ForwardProc},
635 {N_("Back to Start Alt+Home"), "Back to Start", ToStartProc},
636 {N_("Forward to End Alt+End"), "Forward to End", ToEndProc},
640 MenuItem viewMenu[] = {
641 {N_("Flip View F2"), "Flip View", FlipViewProc},
642 {"----", NULL, NothingProc},
643 {N_("Engine Output Alt+Shift+O"), "Show Engine Output", EngineOutputProc},
644 {N_("Move History Alt+Shift+H"), "Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
645 {N_("Evaluation Graph Alt+Shift+E"), "Show Evaluation Graph", EvalGraphProc},
646 {N_("Game List Alt+Shift+G"), "Show Game List", ShowGameListProc},
647 {"----", NULL, NothingProc},
648 {N_("Tags"), "Show Tags", EditTagsProc},
649 {N_("Comments"), "Show Comments", EditCommentProc},
650 {N_("ICS Input Box"), "ICS Input Box", IcsInputBoxProc},
651 {"----", NULL, NothingProc},
652 {N_("Board..."), "Board Options", BoardOptionsProc},
653 {N_("Game List Tags..."), "Game List", GameListOptionsPopUp},
657 MenuItem modeMenu[] = {
658 {N_("Machine White Ctrl+W"), "Machine White", MachineWhiteProc},
659 {N_("Machine Black Ctrl+B"), "Machine Black", MachineBlackProc},
660 {N_("Two Machines Ctrl+T"), "Two Machines", TwoMachinesProc},
661 {N_("Analysis Mode Ctrl+A"), "Analysis Mode", AnalyzeModeProc},
662 {N_("Analyze File Ctrl+F"), "Analyze File", AnalyzeFileProc },
663 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
664 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
665 {N_("Training"), "Training", TrainingProc},
666 {N_("ICS Client"), "ICS Client", IcsClientProc},
667 {"----", NULL, NothingProc},
668 {N_("Pause Pause"), "Pause", PauseProc},
672 MenuItem actionMenu[] = {
673 {N_("Accept F3"), "Accept", AcceptProc},
674 {N_("Decline F4"), "Decline", DeclineProc},
675 {N_("Rematch F12"), "Rematch", RematchProc},
676 {"----", NULL, NothingProc},
677 {N_("Call Flag F5"), "Call Flag", CallFlagProc},
678 {N_("Draw F6"), "Draw", DrawProc},
679 {N_("Adjourn F7"), "Adjourn", AdjournProc},
680 {N_("Abort F8"),"Abort", AbortProc},
681 {N_("Resign F9"), "Resign", ResignProc},
682 {"----", NULL, NothingProc},
683 {N_("Stop Observing F10"), "Stop Observing", StopObservingProc},
684 {N_("Stop Examining F11"), "Stop Examining", StopExaminingProc},
685 {N_("Upload to Examine"), "Upload to Examine", UploadProc},
686 {"----", NULL, NothingProc},
687 {N_("Adjudicate to White"), "Adjudicate to White", AdjuWhiteProc},
688 {N_("Adjudicate to Black"), "Adjudicate to Black", AdjuBlackProc},
689 {N_("Adjudicate Draw"), "Adjudicate Draw", AdjuDrawProc},
693 MenuItem engineMenu[] = {
694 {N_("Engine #1 Settings ..."), "Engine #1 Settings", FirstSettingsProc},
695 {N_("Engine #2 Settings ..."), "Engine #2 Settings", SecondSettingsProc},
696 {"----", NULL, NothingProc},
697 {N_("Hint"), "Hint", HintProc},
698 {N_("Book"), "Book", BookProc},
699 {"----", NULL, NothingProc},
700 {N_("Move Now Ctrl+M"), "Move Now", MoveNowProc},
701 {N_("Retract Move Ctrl+X"), "Retract Move", RetractMoveProc},
705 MenuItem optionsMenu[] = {
706 {N_("Time Control ... Alt+Shift+T"), "Time Control", TimeControlProc},
707 {N_("Common Engine ... Alt+Shift+U"), "Common Engine", UciMenuProc},
708 {N_("Adjudications ... Alt+Shift+J"), "Adjudications", EngineMenuProc},
709 {N_("Load Game ..."), "Load Game", LoadOptionsProc},
710 {N_("Save Game ..."), "Save Game", SaveOptionsProc},
711 // {N_(" ..."), "", OptionsProc},
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 Flag Ctrl+Shift+F"), "Auto Flag", AutoflagProc},
718 {N_("Auto Flip View"), "Auto Flip View", AutoflipProc},
719 {N_("Blindfold"), "Blindfold", BlindfoldProc},
720 {N_("Flash Moves"), "Flash Moves", FlashMovesProc},
722 {N_("Highlight Dragging"), "Highlight Dragging", HighlightDraggingProc},
724 {N_("Highlight Last Move"), "Highlight Last Move", HighlightLastMoveProc},
725 {N_("Highlight With Arrow"), "Arrow", HighlightArrowProc},
726 {N_("Move Sound"), "Move Sound", MoveSoundProc},
727 // {N_("ICS Alarm"), "ICS Alarm", IcsAlarmProc},
728 {N_("One-Click Moving"), "OneClick", OneClickProc},
729 {N_("Periodic Updates"), "Periodic Updates", PeriodicUpdatesProc},
730 {N_("Ponder Next Move Ctrl+Shift+P"), "Ponder Next Move", PonderNextMoveProc},
731 {N_("Popup Exit Message"), "Popup Exit Message", PopupExitMessageProc},
732 {N_("Popup Move Errors"), "Popup Move Errors", PopupMoveErrorsProc},
733 // {N_("Premove"), "Premove", PremoveProc},
734 {N_("Show Coords"), "Show Coords", ShowCoordsProc},
735 {N_("Hide Thinking Ctrl+Shift+H"), "Hide Thinking", HideThinkingProc},
736 {N_("Test Legality Ctrl+Shift+L"), "Test Legality", TestLegalityProc},
737 {"----", NULL, NothingProc},
738 {N_("Save Settings Now"), "Save Settings Now", SaveSettingsProc},
739 {N_("Save Settings on Exit"), "Save Settings on Exit", SaveOnExitProc},
743 MenuItem helpMenu[] = {
744 {N_("Info XBoard"), "Info XBoard", InfoProc},
745 {N_("Man XBoard F1"), "Man XBoard", ManProc},
746 {"----", NULL, NothingProc},
747 {N_("About XBoard"), "About XBoard", AboutProc},
752 {N_("File"), "File", fileMenu},
753 {N_("Edit"), "Edit", editMenu},
754 {N_("View"), "View", viewMenu},
755 {N_("Mode"), "Mode", modeMenu},
756 {N_("Action"), "Action", actionMenu},
757 {N_("Engine"), "Engine", engineMenu},
758 {N_("Options"), "Options", optionsMenu},
759 {N_("Help"), "Help", helpMenu},
763 #define PAUSE_BUTTON "P"
764 MenuItem buttonBar[] = {
765 {"<<", "<<", ToStartProc},
766 {"<", "<", BackwardProc},
767 {PAUSE_BUTTON, PAUSE_BUTTON, PauseProc},
768 {">", ">", ForwardProc},
769 {">>", ">>", ToEndProc},
773 #define PIECE_MENU_SIZE 18
774 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
775 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
776 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
777 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
778 N_("Empty square"), N_("Clear board") },
779 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
780 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
781 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
782 N_("Empty square"), N_("Clear board") }
784 /* must be in same order as PieceMenuStrings! */
785 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
786 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
787 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
788 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
789 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
790 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
791 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
792 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
793 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
796 #define DROP_MENU_SIZE 6
797 String dropMenuStrings[DROP_MENU_SIZE] = {
798 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
800 /* must be in same order as PieceMenuStrings! */
801 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
802 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
803 WhiteRook, WhiteQueen
811 DropMenuEnables dmEnables[] = {
829 { XtNborderWidth, 0 },
830 { XtNdefaultDistance, 0 },
834 { XtNborderWidth, 0 },
835 { XtNresizable, (XtArgVal) True },
839 { XtNborderWidth, 0 },
845 { XtNjustify, (XtArgVal) XtJustifyRight },
846 { XtNlabel, (XtArgVal) "..." },
847 { XtNresizable, (XtArgVal) True },
848 { XtNresize, (XtArgVal) False }
851 Arg messageArgs[] = {
852 { XtNjustify, (XtArgVal) XtJustifyLeft },
853 { XtNlabel, (XtArgVal) "..." },
854 { XtNresizable, (XtArgVal) True },
855 { XtNresize, (XtArgVal) False }
859 { XtNborderWidth, 0 },
860 { XtNjustify, (XtArgVal) XtJustifyLeft }
863 XtResource clientResources[] = {
864 { "flashCount", "flashCount", XtRInt, sizeof(int),
865 XtOffset(AppDataPtr, flashCount), XtRImmediate,
866 (XtPointer) FLASH_COUNT },
869 XrmOptionDescRec shellOptions[] = {
870 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
871 { "-flash", "flashCount", XrmoptionNoArg, "3" },
872 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
875 XtActionsRec boardActions[] = {
876 { "DrawPosition", DrawPositionProc },
877 { "HandleUserMove", HandleUserMove },
878 { "AnimateUserMove", AnimateUserMove },
879 { "HandlePV", HandlePV },
880 { "SelectPV", SelectPV },
881 { "StopPV", StopPV },
882 { "FileNameAction", FileNameAction },
883 { "AskQuestionProc", AskQuestionProc },
884 { "AskQuestionReplyAction", AskQuestionReplyAction },
885 { "PieceMenuPopup", PieceMenuPopup },
886 { "WhiteClock", WhiteClock },
887 { "BlackClock", BlackClock },
888 { "Iconify", Iconify },
889 { "ResetProc", ResetProc },
890 { "NewVariantProc", NewVariantProc },
891 { "LoadGameProc", LoadGameProc },
892 { "LoadNextGameProc", LoadNextGameProc },
893 { "LoadPrevGameProc", LoadPrevGameProc },
894 { "LoadSelectedProc", LoadSelectedProc },
895 { "SetFilterProc", SetFilterProc },
896 { "ReloadGameProc", ReloadGameProc },
897 { "LoadPositionProc", LoadPositionProc },
898 { "LoadNextPositionProc", LoadNextPositionProc },
899 { "LoadPrevPositionProc", LoadPrevPositionProc },
900 { "ReloadPositionProc", ReloadPositionProc },
901 { "CopyPositionProc", CopyPositionProc },
902 { "PastePositionProc", PastePositionProc },
903 { "CopyGameProc", CopyGameProc },
904 { "PasteGameProc", PasteGameProc },
905 { "SaveGameProc", SaveGameProc },
906 { "SavePositionProc", SavePositionProc },
907 { "MailMoveProc", MailMoveProc },
908 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
909 { "QuitProc", QuitProc },
910 { "MachineWhiteProc", MachineWhiteProc },
911 { "MachineBlackProc", MachineBlackProc },
912 { "AnalysisModeProc", AnalyzeModeProc },
913 { "AnalyzeFileProc", AnalyzeFileProc },
914 { "TwoMachinesProc", TwoMachinesProc },
915 { "IcsClientProc", IcsClientProc },
916 { "EditGameProc", EditGameProc },
917 { "EditPositionProc", EditPositionProc },
918 { "TrainingProc", EditPositionProc },
919 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
920 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
921 { "ShowGameListProc", ShowGameListProc },
922 { "ShowMoveListProc", HistoryShowProc},
923 { "EditTagsProc", EditCommentProc },
924 { "EditCommentProc", EditCommentProc },
925 { "IcsInputBoxProc", IcsInputBoxProc },
926 { "PauseProc", PauseProc },
927 { "AcceptProc", AcceptProc },
928 { "DeclineProc", DeclineProc },
929 { "RematchProc", RematchProc },
930 { "CallFlagProc", CallFlagProc },
931 { "DrawProc", DrawProc },
932 { "AdjournProc", AdjournProc },
933 { "AbortProc", AbortProc },
934 { "ResignProc", ResignProc },
935 { "AdjuWhiteProc", AdjuWhiteProc },
936 { "AdjuBlackProc", AdjuBlackProc },
937 { "AdjuDrawProc", AdjuDrawProc },
938 { "EnterKeyProc", EnterKeyProc },
939 { "UpKeyProc", UpKeyProc },
940 { "DownKeyProc", DownKeyProc },
941 { "StopObservingProc", StopObservingProc },
942 { "StopExaminingProc", StopExaminingProc },
943 { "UploadProc", UploadProc },
944 { "BackwardProc", BackwardProc },
945 { "ForwardProc", ForwardProc },
946 { "ToStartProc", ToStartProc },
947 { "ToEndProc", ToEndProc },
948 { "RevertProc", RevertProc },
949 { "AnnotateProc", AnnotateProc },
950 { "TruncateGameProc", TruncateGameProc },
951 { "MoveNowProc", MoveNowProc },
952 { "RetractMoveProc", RetractMoveProc },
953 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
954 { "UciMenuProc", (XtActionProc) UciMenuProc },
955 { "TimeControlProc", (XtActionProc) TimeControlProc },
956 { "AlwaysQueenProc", AlwaysQueenProc },
957 { "AnimateDraggingProc", AnimateDraggingProc },
958 { "AnimateMovingProc", AnimateMovingProc },
959 { "AutoflagProc", AutoflagProc },
960 { "AutoflipProc", AutoflipProc },
961 { "BlindfoldProc", BlindfoldProc },
962 { "FlashMovesProc", FlashMovesProc },
963 { "FlipViewProc", FlipViewProc },
965 { "HighlightDraggingProc", HighlightDraggingProc },
967 { "HighlightLastMoveProc", HighlightLastMoveProc },
968 // { "IcsAlarmProc", IcsAlarmProc },
969 { "MoveSoundProc", MoveSoundProc },
970 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
971 { "PonderNextMoveProc", PonderNextMoveProc },
972 { "PopupExitMessageProc", PopupExitMessageProc },
973 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
974 // { "PremoveProc", PremoveProc },
975 { "ShowCoordsProc", ShowCoordsProc },
976 { "ShowThinkingProc", ShowThinkingProc },
977 { "HideThinkingProc", HideThinkingProc },
978 { "TestLegalityProc", TestLegalityProc },
979 { "SaveSettingsProc", SaveSettingsProc },
980 { "SaveOnExitProc", SaveOnExitProc },
981 { "InfoProc", InfoProc },
982 { "ManProc", ManProc },
983 { "HintProc", HintProc },
984 { "BookProc", BookProc },
985 { "AboutGameProc", AboutGameProc },
986 { "AboutProc", AboutProc },
987 { "DebugProc", DebugProc },
988 { "NothingProc", NothingProc },
989 { "CommentClick", (XtActionProc) CommentClick },
990 { "CommentPopDown", (XtActionProc) CommentPopDown },
991 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
992 { "TagsPopDown", (XtActionProc) TagsPopDown },
993 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
994 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
995 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
996 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
997 { "GameListPopDown", (XtActionProc) GameListPopDown },
998 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
999 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1000 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
1001 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1002 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1003 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
1004 { "EnginePopDown", (XtActionProc) EnginePopDown },
1005 { "UciPopDown", (XtActionProc) UciPopDown },
1006 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
1007 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
1008 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
1009 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1012 char globalTranslations[] =
1013 ":<Key>F9: ResignProc() \n \
1014 :Ctrl<Key>n: ResetProc() \n \
1015 :Meta<Key>V: NewVariantProc() \n \
1016 :Ctrl<Key>o: LoadGameProc() \n \
1017 :Meta<Key>Next: LoadNextGameProc() \n \
1018 :Meta<Key>Prior: LoadPrevGameProc() \n \
1019 :Ctrl<Key>s: SaveGameProc() \n \
1020 :Ctrl<Key>c: CopyGameProc() \n \
1021 :Ctrl<Key>v: PasteGameProc() \n \
1022 :Ctrl<Key>O: LoadPositionProc() \n \
1023 :Shift<Key>Next: LoadNextPositionProc() \n \
1024 :Shift<Key>Prior: LoadPrevPositionProc() \n \
1025 :Ctrl<Key>S: SavePositionProc() \n \
1026 :Ctrl<Key>C: CopyPositionProc() \n \
1027 :Ctrl<Key>V: PastePositionProc() \n \
1028 :Ctrl<Key>q: QuitProc() \n \
1029 :Ctrl<Key>w: MachineWhiteProc() \n \
1030 :Ctrl<Key>b: MachineBlackProc() \n \
1031 :Ctrl<Key>t: TwoMachinesProc() \n \
1032 :Ctrl<Key>a: AnalysisModeProc() \n \
1033 :Ctrl<Key>f: AnalyzeFileProc() \n \
1034 :Ctrl<Key>e: EditGameProc() \n \
1035 :Ctrl<Key>E: EditPositionProc() \n \
1036 :Meta<Key>O: EngineOutputProc() \n \
1037 :Meta<Key>E: EvalGraphProc() \n \
1038 :Meta<Key>G: ShowGameListProc() \n \
1039 :Meta<Key>H: ShowMoveListProc() \n \
1040 :<Key>Pause: PauseProc() \n \
1041 :<Key>F3: AcceptProc() \n \
1042 :<Key>F4: DeclineProc() \n \
1043 :<Key>F12: RematchProc() \n \
1044 :<Key>F5: CallFlagProc() \n \
1045 :<Key>F6: DrawProc() \n \
1046 :<Key>F7: AdjournProc() \n \
1047 :<Key>F8: AbortProc() \n \
1048 :<Key>F10: StopObservingProc() \n \
1049 :<Key>F11: StopExaminingProc() \n \
1050 :Meta Ctrl<Key>F12: DebugProc() \n \
1051 :Meta<Key>End: ToEndProc() \n \
1052 :Meta<Key>Right: ForwardProc() \n \
1053 :Meta<Key>Home: ToStartProc() \n \
1054 :Meta<Key>Left: BackwardProc() \n \
1055 :<Key>Home: RevertProc() \n \
1056 :<Key>End: TruncateGameProc() \n \
1057 :Ctrl<Key>m: MoveNowProc() \n \
1058 :Ctrl<Key>x: RetractMoveProc() \n \
1059 :Meta<Key>J: EngineMenuProc() \n \
1060 :Meta<Key>U: UciMenuProc() \n \
1061 :Meta<Key>T: TimeControlProc() \n \
1062 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1063 :Ctrl<Key>F: AutoflagProc() \n \
1064 :Ctrl<Key>A: AnimateMovingProc() \n \
1065 :Ctrl<Key>P: PonderNextMoveProc() \n \
1066 :Ctrl<Key>L: TestLegalityProc() \n \
1067 :Ctrl<Key>H: HideThinkingProc() \n \
1068 :<Key>-: Iconify() \n \
1069 :<Key>F1: ManProc() \n \
1070 :<Key>F2: FlipViewProc() \n \
1071 <KeyDown>.: BackwardProc() \n \
1072 <KeyUp>.: ForwardProc() \n \
1073 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1074 \"Send to chess program:\",,1) \n \
1075 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1076 \"Send to second chess program:\",,2) \n";
1078 char boardTranslations[] =
1079 "<Btn1Down>: HandleUserMove(0) \n \
1080 Shift<Btn1Up>: HandleUserMove(1) \n \
1081 <Btn1Up>: HandleUserMove(0) \n \
1082 <Btn1Motion>: AnimateUserMove() \n \
1083 <Btn3Motion>: HandlePV() \n \
1084 <Btn3Up>: PieceMenuPopup(menuB) \n \
1085 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1086 PieceMenuPopup(menuB) \n \
1087 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1088 PieceMenuPopup(menuW) \n \
1089 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1090 PieceMenuPopup(menuW) \n \
1091 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1092 PieceMenuPopup(menuB) \n";
1094 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1095 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1097 char ICSInputTranslations[] =
1098 "<Key>Up: UpKeyProc() \n "
1099 "<Key>Down: DownKeyProc() \n "
1100 "<Key>Return: EnterKeyProc() \n";
1102 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1103 // as the widget is destroyed before the up-click can call extend-end
1104 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1106 String xboardResources[] = {
1107 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1108 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1109 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1114 /* Max possible square size */
1115 #define MAXSQSIZE 256
1117 static int xpm_avail[MAXSQSIZE];
1119 #ifdef HAVE_DIR_STRUCT
1121 /* Extract piece size from filename */
1123 xpm_getsize(name, len, ext)
1134 if ((p=strchr(name, '.')) == NULL ||
1135 StrCaseCmp(p+1, ext) != 0)
1141 while (*p && isdigit(*p))
1148 /* Setup xpm_avail */
1150 xpm_getavail(dirname, ext)
1158 for (i=0; i<MAXSQSIZE; ++i)
1161 if (appData.debugMode)
1162 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1164 dir = opendir(dirname);
1167 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1168 programName, dirname);
1172 while ((ent=readdir(dir)) != NULL) {
1173 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1174 if (i > 0 && i < MAXSQSIZE)
1184 xpm_print_avail(fp, ext)
1190 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1191 for (i=1; i<MAXSQSIZE; ++i) {
1197 /* Return XPM piecesize closest to size */
1199 xpm_closest_to(dirname, size, ext)
1205 int sm_diff = MAXSQSIZE;
1209 xpm_getavail(dirname, ext);
1211 if (appData.debugMode)
1212 xpm_print_avail(stderr, ext);
1214 for (i=1; i<MAXSQSIZE; ++i) {
1217 diff = (diff<0) ? -diff : diff;
1218 if (diff < sm_diff) {
1226 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1232 #else /* !HAVE_DIR_STRUCT */
1233 /* If we are on a system without a DIR struct, we can't
1234 read the directory, so we can't collect a list of
1235 filenames, etc., so we can't do any size-fitting. */
1237 xpm_closest_to(dirname, size, ext)
1242 fprintf(stderr, _("\
1243 Warning: No DIR structure found on this system --\n\
1244 Unable to autosize for XPM/XIM pieces.\n\
1245 Please report this error to frankm@hiwaay.net.\n\
1246 Include system type & operating system in message.\n"));
1249 #endif /* HAVE_DIR_STRUCT */
1251 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1252 "magenta", "cyan", "white" };
1256 TextColors textColors[(int)NColorClasses];
1258 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1260 parse_color(str, which)
1264 char *p, buf[100], *d;
1267 if (strlen(str) > 99) /* watch bounds on buf */
1272 for (i=0; i<which; ++i) {
1279 /* Could be looking at something like:
1281 .. in which case we want to stop on a comma also */
1282 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1286 return -1; /* Use default for empty field */
1289 if (which == 2 || isdigit(*p))
1292 while (*p && isalpha(*p))
1297 for (i=0; i<8; ++i) {
1298 if (!StrCaseCmp(buf, cnames[i]))
1299 return which? (i+40) : (i+30);
1301 if (!StrCaseCmp(buf, "default")) return -1;
1303 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1308 parse_cpair(cc, str)
1312 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1313 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1318 /* bg and attr are optional */
1319 textColors[(int)cc].bg = parse_color(str, 1);
1320 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1321 textColors[(int)cc].attr = 0;
1327 /* Arrange to catch delete-window events */
1328 Atom wm_delete_window;
1330 CatchDeleteWindow(Widget w, String procname)
1333 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1334 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1335 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1342 XtSetArg(args[0], XtNiconic, False);
1343 XtSetValues(shellWidget, args, 1);
1345 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1348 //---------------------------------------------------------------------------------------------------------
1349 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1352 #define CW_USEDEFAULT (1<<31)
1353 #define ICS_TEXT_MENU_SIZE 90
1354 #define DEBUG_FILE "xboard.debug"
1355 #define SetCurrentDirectory chdir
1356 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1360 // these two must some day move to frontend.h, when they are implemented
1361 Boolean GameListIsUp();
1363 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1366 // front-end part of option handling
1368 // [HGM] This platform-dependent table provides the location for storing the color info
1369 extern char *crWhite, * crBlack;
1373 &appData.whitePieceColor,
1374 &appData.blackPieceColor,
1375 &appData.lightSquareColor,
1376 &appData.darkSquareColor,
1377 &appData.highlightSquareColor,
1378 &appData.premoveHighlightColor,
1379 &appData.lowTimeWarningColor,
1390 // [HGM] font: keep a font for each square size, even non-stndard ones
1391 #define NUM_SIZES 18
1392 #define MAX_SIZE 130
1393 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1394 char *fontTable[NUM_FONTS][MAX_SIZE];
1397 ParseFont(char *name, int number)
1398 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1400 if(sscanf(name, "size%d:", &size)) {
1401 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1402 // defer processing it until we know if it matches our board size
1403 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1404 fontTable[number][size] = strdup(strchr(name, ':')+1);
1405 fontValid[number][size] = True;
1410 case 0: // CLOCK_FONT
1411 appData.clockFont = strdup(name);
1413 case 1: // MESSAGE_FONT
1414 appData.font = strdup(name);
1416 case 2: // COORD_FONT
1417 appData.coordFont = strdup(name);
1422 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1427 { // only 2 fonts currently
1428 appData.clockFont = CLOCK_FONT_NAME;
1429 appData.coordFont = COORD_FONT_NAME;
1430 appData.font = DEFAULT_FONT_NAME;
1435 { // no-op, until we identify the code for this already in XBoard and move it here
1439 ParseColor(int n, char *name)
1440 { // in XBoard, just copy the color-name string
1441 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1445 ParseTextAttribs(ColorClass cc, char *s)
1447 (&appData.colorShout)[cc] = strdup(s);
1451 ParseBoardSize(void *addr, char *name)
1453 appData.boardSize = strdup(name);
1458 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1462 SetCommPortDefaults()
1463 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1466 // [HGM] args: these three cases taken out to stay in front-end
1468 SaveFontArg(FILE *f, ArgDescriptor *ad)
1471 int i, n = (int)(intptr_t)ad->argLoc;
1473 case 0: // CLOCK_FONT
1474 name = appData.clockFont;
1476 case 1: // MESSAGE_FONT
1477 name = appData.font;
1479 case 2: // COORD_FONT
1480 name = appData.coordFont;
1485 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1486 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1487 fontTable[n][squareSize] = strdup(name);
1488 fontValid[n][squareSize] = True;
1491 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1492 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1497 { // nothing to do, as the sounds are at all times represented by their text-string names already
1501 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1502 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1503 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
1507 SaveColor(FILE *f, ArgDescriptor *ad)
1508 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1509 if(colorVariable[(int)(intptr_t)ad->argLoc])
1510 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
1514 SaveBoardSize(FILE *f, char *name, void *addr)
1515 { // wrapper to shield back-end from BoardSize & sizeInfo
1516 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1520 ParseCommPortSettings(char *s)
1521 { // no such option in XBoard (yet)
1524 extern Widget engineOutputShell;
1525 extern Widget tagsShell, editTagsShell;
1527 GetActualPlacement(Widget wg, WindowPlacement *wp)
1537 XtSetArg(args[i], XtNx, &x); i++;
1538 XtSetArg(args[i], XtNy, &y); i++;
1539 XtSetArg(args[i], XtNwidth, &w); i++;
1540 XtSetArg(args[i], XtNheight, &h); i++;
1541 XtGetValues(wg, args, i);
1550 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1551 // In XBoard this will have to wait until awareness of window parameters is implemented
1552 GetActualPlacement(shellWidget, &wpMain);
1553 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1554 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1555 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1556 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1557 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1558 else GetActualPlacement(editShell, &wpComment);
1559 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1560 else GetActualPlacement(editTagsShell, &wpTags);
1564 PrintCommPortSettings(FILE *f, char *name)
1565 { // This option does not exist in XBoard
1569 MySearchPath(char *installDir, char *name, char *fullname)
1570 { // just append installDir and name. Perhaps ExpandPath should be used here?
1571 name = ExpandPathName(name);
1572 if(name && name[0] == '/')
1573 safeStrCpy(fullname, name, MSG_SIZ );
1575 sprintf(fullname, "%s%c%s", installDir, '/', name);
1581 MyGetFullPathName(char *name, char *fullname)
1582 { // should use ExpandPath?
1583 name = ExpandPathName(name);
1584 safeStrCpy(fullname, name, MSG_SIZ );
1589 EnsureOnScreen(int *x, int *y, int minX, int minY)
1596 { // [HGM] args: allows testing if main window is realized from back-end
1597 return xBoardWindow != 0;
1601 PopUpStartupDialog()
1602 { // start menu not implemented in XBoard
1606 ConvertToLine(int argc, char **argv)
1608 static char line[128*1024], buf[1024];
1612 for(i=1; i<argc; i++)
1614 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1615 && argv[i][0] != '{' )
1616 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1618 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1619 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1622 line[strlen(line)-1] = NULLCHAR;
1626 //--------------------------------------------------------------------------------------------
1628 extern Boolean twoBoards, partnerUp;
1631 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1633 #define BoardSize int
1634 void InitDrawingSizes(BoardSize boardSize, int flags)
1635 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1636 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1638 XtGeometryResult gres;
1641 if(!formWidget) return;
1644 * Enable shell resizing.
1646 shellArgs[0].value = (XtArgVal) &w;
1647 shellArgs[1].value = (XtArgVal) &h;
1648 XtGetValues(shellWidget, shellArgs, 2);
1650 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1651 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1652 XtSetValues(shellWidget, &shellArgs[2], 4);
1654 XtSetArg(args[0], XtNdefaultDistance, &sep);
1655 XtGetValues(formWidget, args, 1);
1657 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1658 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1659 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1661 hOffset = boardWidth + 10;
1662 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1663 secondSegments[i] = gridSegments[i];
1664 secondSegments[i].x1 += hOffset;
1665 secondSegments[i].x2 += hOffset;
1668 XtSetArg(args[0], XtNwidth, boardWidth);
1669 XtSetArg(args[1], XtNheight, boardHeight);
1670 XtSetValues(boardWidget, args, 2);
1672 timerWidth = (boardWidth - sep) / 2;
1673 XtSetArg(args[0], XtNwidth, timerWidth);
1674 XtSetValues(whiteTimerWidget, args, 1);
1675 XtSetValues(blackTimerWidget, args, 1);
1677 XawFormDoLayout(formWidget, False);
1679 if (appData.titleInWindow) {
1681 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1682 XtSetArg(args[i], XtNheight, &h); i++;
1683 XtGetValues(titleWidget, args, i);
1685 w = boardWidth - 2*bor;
1687 XtSetArg(args[0], XtNwidth, &w);
1688 XtGetValues(menuBarWidget, args, 1);
1689 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1692 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1693 if (gres != XtGeometryYes && appData.debugMode) {
1695 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1696 programName, gres, w, h, wr, hr);
1700 XawFormDoLayout(formWidget, True);
1703 * Inhibit shell resizing.
1705 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1706 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1707 shellArgs[4].value = shellArgs[2].value = w;
1708 shellArgs[5].value = shellArgs[3].value = h;
1709 XtSetValues(shellWidget, &shellArgs[0], 6);
1711 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1714 for(i=0; i<4; i++) {
1716 for(p=0; p<=(int)WhiteKing; p++)
1717 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1718 if(gameInfo.variant == VariantShogi) {
1719 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1720 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1721 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1722 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1723 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1726 if(gameInfo.variant == VariantGothic) {
1727 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1730 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1731 xpmPieceBitmap[i][(int)WhiteAngel] = xpmPieceBitmap2[i][(int)WhiteFalcon];
1732 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1735 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1736 for(p=0; p<=(int)WhiteKing; p++)
1737 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1738 if(gameInfo.variant == VariantShogi) {
1739 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1740 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1741 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1742 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1743 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1746 if(gameInfo.variant == VariantGothic) {
1747 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1750 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1751 ximMaskPm[(int)WhiteAngel] = ximMaskPm2[(int)WhiteFalcon];
1752 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1757 for(i=0; i<2; i++) {
1759 for(p=0; p<=(int)WhiteKing; p++)
1760 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1761 if(gameInfo.variant == VariantShogi) {
1762 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1763 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1764 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1765 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1766 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1769 if(gameInfo.variant == VariantGothic) {
1770 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1773 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1774 pieceBitmap[i][(int)WhiteAngel] = pieceBitmap2[i][(int)WhiteFalcon];
1775 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1785 void ParseIcsTextColors()
1786 { // [HGM] tken out of main(), so it can be called from ICS-Options dialog
1787 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1788 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1789 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1790 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1791 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1792 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1793 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1794 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1795 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1796 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1798 if (appData.colorize) {
1800 _("%s: can't parse color names; disabling colorization\n"),
1803 appData.colorize = FALSE;
1808 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
1809 XrmValue vFrom, vTo;
1810 int forceMono = False;
1812 if (!appData.monoMode) {
1813 vFrom.addr = (caddr_t) appData.lightSquareColor;
1814 vFrom.size = strlen(appData.lightSquareColor);
1815 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1816 if (vTo.addr == NULL) {
1817 appData.monoMode = True;
1820 lightSquareColor = *(Pixel *) vTo.addr;
1823 if (!appData.monoMode) {
1824 vFrom.addr = (caddr_t) appData.darkSquareColor;
1825 vFrom.size = strlen(appData.darkSquareColor);
1826 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1827 if (vTo.addr == NULL) {
1828 appData.monoMode = True;
1831 darkSquareColor = *(Pixel *) vTo.addr;
1834 if (!appData.monoMode) {
1835 vFrom.addr = (caddr_t) appData.whitePieceColor;
1836 vFrom.size = strlen(appData.whitePieceColor);
1837 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1838 if (vTo.addr == NULL) {
1839 appData.monoMode = True;
1842 whitePieceColor = *(Pixel *) vTo.addr;
1845 if (!appData.monoMode) {
1846 vFrom.addr = (caddr_t) appData.blackPieceColor;
1847 vFrom.size = strlen(appData.blackPieceColor);
1848 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1849 if (vTo.addr == NULL) {
1850 appData.monoMode = True;
1853 blackPieceColor = *(Pixel *) vTo.addr;
1857 if (!appData.monoMode) {
1858 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1859 vFrom.size = strlen(appData.highlightSquareColor);
1860 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1861 if (vTo.addr == NULL) {
1862 appData.monoMode = True;
1865 highlightSquareColor = *(Pixel *) vTo.addr;
1869 if (!appData.monoMode) {
1870 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1871 vFrom.size = strlen(appData.premoveHighlightColor);
1872 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1873 if (vTo.addr == NULL) {
1874 appData.monoMode = True;
1877 premoveHighlightColor = *(Pixel *) vTo.addr;
1888 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1889 XSetWindowAttributes window_attributes;
1891 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1892 XrmValue vFrom, vTo;
1893 XtGeometryResult gres;
1896 int forceMono = False;
1898 srandom(time(0)); // [HGM] book: make random truly random
1900 setbuf(stdout, NULL);
1901 setbuf(stderr, NULL);
1904 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1905 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1909 programName = strrchr(argv[0], '/');
1910 if (programName == NULL)
1911 programName = argv[0];
1916 XtSetLanguageProc(NULL, NULL, NULL);
1917 bindtextdomain(PACKAGE, LOCALEDIR);
1918 textdomain(PACKAGE);
1922 XtAppInitialize(&appContext, "XBoard", shellOptions,
1923 XtNumber(shellOptions),
1924 &argc, argv, xboardResources, NULL, 0);
1925 appData.boardSize = "";
1926 InitAppData(ConvertToLine(argc, argv));
1928 if (p == NULL) p = "/tmp";
1929 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1930 gameCopyFilename = (char*) malloc(i);
1931 gamePasteFilename = (char*) malloc(i);
1932 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1933 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1935 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1936 clientResources, XtNumber(clientResources),
1939 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1940 static char buf[MSG_SIZ];
1941 EscapeExpand(buf, appData.initString);
1942 appData.initString = strdup(buf);
1943 EscapeExpand(buf, appData.secondInitString);
1944 appData.secondInitString = strdup(buf);
1945 EscapeExpand(buf, appData.firstComputerString);
1946 appData.firstComputerString = strdup(buf);
1947 EscapeExpand(buf, appData.secondComputerString);
1948 appData.secondComputerString = strdup(buf);
1951 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1954 if (chdir(chessDir) != 0) {
1955 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1961 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1962 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1963 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1964 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1967 setbuf(debugFP, NULL);
1970 /* [HGM,HR] make sure board size is acceptable */
1971 if(appData.NrFiles > BOARD_FILES ||
1972 appData.NrRanks > BOARD_RANKS )
1973 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1976 /* This feature does not work; animation needs a rewrite */
1977 appData.highlightDragging = FALSE;
1981 xDisplay = XtDisplay(shellWidget);
1982 xScreen = DefaultScreen(xDisplay);
1983 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1985 gameInfo.variant = StringToVariant(appData.variant);
1986 InitPosition(FALSE);
1989 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1991 if (isdigit(appData.boardSize[0])) {
1992 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1993 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1994 &fontPxlSize, &smallLayout, &tinyLayout);
1996 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1997 programName, appData.boardSize);
2001 /* Find some defaults; use the nearest known size */
2002 SizeDefaults *szd, *nearest;
2003 int distance = 99999;
2004 nearest = szd = sizeDefaults;
2005 while (szd->name != NULL) {
2006 if (abs(szd->squareSize - squareSize) < distance) {
2008 distance = abs(szd->squareSize - squareSize);
2009 if (distance == 0) break;
2013 if (i < 2) lineGap = nearest->lineGap;
2014 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
2015 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
2016 if (i < 5) fontPxlSize = nearest->fontPxlSize;
2017 if (i < 6) smallLayout = nearest->smallLayout;
2018 if (i < 7) tinyLayout = nearest->tinyLayout;
2021 SizeDefaults *szd = sizeDefaults;
2022 if (*appData.boardSize == NULLCHAR) {
2023 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
2024 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
2027 if (szd->name == NULL) szd--;
2028 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
2030 while (szd->name != NULL &&
2031 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
2032 if (szd->name == NULL) {
2033 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
2034 programName, appData.boardSize);
2038 squareSize = szd->squareSize;
2039 lineGap = szd->lineGap;
2040 clockFontPxlSize = szd->clockFontPxlSize;
2041 coordFontPxlSize = szd->coordFontPxlSize;
2042 fontPxlSize = szd->fontPxlSize;
2043 smallLayout = szd->smallLayout;
2044 tinyLayout = szd->tinyLayout;
2045 // [HGM] font: use defaults from settings file if available and not overruled
2047 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
2048 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
2049 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
2050 appData.font = fontTable[MESSAGE_FONT][squareSize];
2051 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
2052 appData.coordFont = fontTable[COORD_FONT][squareSize];
2054 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
2055 if (strlen(appData.pixmapDirectory) > 0) {
2056 p = ExpandPathName(appData.pixmapDirectory);
2058 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
2059 appData.pixmapDirectory);
2062 if (appData.debugMode) {
2063 fprintf(stderr, _("\
2064 XBoard square size (hint): %d\n\
2065 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
2067 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
2068 if (appData.debugMode) {
2069 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
2072 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
2074 /* [HR] height treated separately (hacked) */
2075 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
2076 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
2077 if (appData.showJail == 1) {
2078 /* Jail on top and bottom */
2079 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2080 XtSetArg(boardArgs[2], XtNheight,
2081 boardHeight + 2*(lineGap + squareSize));
2082 } else if (appData.showJail == 2) {
2084 XtSetArg(boardArgs[1], XtNwidth,
2085 boardWidth + 2*(lineGap + squareSize));
2086 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2089 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2090 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2094 * Determine what fonts to use.
2096 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2097 clockFontID = XLoadFont(xDisplay, appData.clockFont);
2098 clockFontStruct = XQueryFont(xDisplay, clockFontID);
2099 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2100 coordFontID = XLoadFont(xDisplay, appData.coordFont);
2101 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2102 appData.font = FindFont(appData.font, fontPxlSize);
2103 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
2104 countFontStruct = XQueryFont(xDisplay, countFontID);
2105 // appData.font = FindFont(appData.font, fontPxlSize);
2107 xdb = XtDatabase(xDisplay);
2108 XrmPutStringResource(&xdb, "*font", appData.font);
2111 * Detect if there are not enough colors available and adapt.
2113 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2114 appData.monoMode = True;
2117 forceMono = MakeColors();
2120 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2123 if (appData.bitmapDirectory == NULL ||
2124 appData.bitmapDirectory[0] == NULLCHAR)
2125 appData.bitmapDirectory = DEF_BITMAP_DIR;
2128 if (appData.lowTimeWarning && !appData.monoMode) {
2129 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2130 vFrom.size = strlen(appData.lowTimeWarningColor);
2131 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2132 if (vTo.addr == NULL)
2133 appData.monoMode = True;
2135 lowTimeWarningColor = *(Pixel *) vTo.addr;
2138 if (appData.monoMode && appData.debugMode) {
2139 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2140 (unsigned long) XWhitePixel(xDisplay, xScreen),
2141 (unsigned long) XBlackPixel(xDisplay, xScreen));
2144 ParseIcsTextColors();
2145 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2146 textColors[ColorNone].attr = 0;
2148 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2154 layoutName = "tinyLayout";
2155 } else if (smallLayout) {
2156 layoutName = "smallLayout";
2158 layoutName = "normalLayout";
2160 /* Outer layoutWidget is there only to provide a name for use in
2161 resources that depend on the layout style */
2163 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2164 layoutArgs, XtNumber(layoutArgs));
2166 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2167 formArgs, XtNumber(formArgs));
2168 XtSetArg(args[0], XtNdefaultDistance, &sep);
2169 XtGetValues(formWidget, args, 1);
2172 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2173 XtSetArg(args[0], XtNtop, XtChainTop);
2174 XtSetArg(args[1], XtNbottom, XtChainTop);
2175 XtSetArg(args[2], XtNright, XtChainLeft);
2176 XtSetValues(menuBarWidget, args, 3);
2178 widgetList[j++] = whiteTimerWidget =
2179 XtCreateWidget("whiteTime", labelWidgetClass,
2180 formWidget, timerArgs, XtNumber(timerArgs));
2181 XtSetArg(args[0], XtNfont, clockFontStruct);
2182 XtSetArg(args[1], XtNtop, XtChainTop);
2183 XtSetArg(args[2], XtNbottom, XtChainTop);
2184 XtSetValues(whiteTimerWidget, args, 3);
2186 widgetList[j++] = blackTimerWidget =
2187 XtCreateWidget("blackTime", labelWidgetClass,
2188 formWidget, timerArgs, XtNumber(timerArgs));
2189 XtSetArg(args[0], XtNfont, clockFontStruct);
2190 XtSetArg(args[1], XtNtop, XtChainTop);
2191 XtSetArg(args[2], XtNbottom, XtChainTop);
2192 XtSetValues(blackTimerWidget, args, 3);
2194 if (appData.titleInWindow) {
2195 widgetList[j++] = titleWidget =
2196 XtCreateWidget("title", labelWidgetClass, formWidget,
2197 titleArgs, XtNumber(titleArgs));
2198 XtSetArg(args[0], XtNtop, XtChainTop);
2199 XtSetArg(args[1], XtNbottom, XtChainTop);
2200 XtSetValues(titleWidget, args, 2);
2203 if (appData.showButtonBar) {
2204 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2205 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2206 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2207 XtSetArg(args[2], XtNtop, XtChainTop);
2208 XtSetArg(args[3], XtNbottom, XtChainTop);
2209 XtSetValues(buttonBarWidget, args, 4);
2212 widgetList[j++] = messageWidget =
2213 XtCreateWidget("message", labelWidgetClass, formWidget,
2214 messageArgs, XtNumber(messageArgs));
2215 XtSetArg(args[0], XtNtop, XtChainTop);
2216 XtSetArg(args[1], XtNbottom, XtChainTop);
2217 XtSetValues(messageWidget, args, 2);
2219 widgetList[j++] = boardWidget =
2220 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2221 XtNumber(boardArgs));
2223 XtManageChildren(widgetList, j);
2225 timerWidth = (boardWidth - sep) / 2;
2226 XtSetArg(args[0], XtNwidth, timerWidth);
2227 XtSetValues(whiteTimerWidget, args, 1);
2228 XtSetValues(blackTimerWidget, args, 1);
2230 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2231 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2232 XtGetValues(whiteTimerWidget, args, 2);
2234 if (appData.showButtonBar) {
2235 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2236 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2237 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2241 * formWidget uses these constraints but they are stored
2245 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2246 XtSetValues(menuBarWidget, args, i);
2247 if (appData.titleInWindow) {
2250 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2251 XtSetValues(whiteTimerWidget, args, i);
2253 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2254 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2255 XtSetValues(blackTimerWidget, args, i);
2257 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2258 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2259 XtSetValues(titleWidget, args, i);
2261 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2262 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2263 XtSetValues(messageWidget, args, i);
2264 if (appData.showButtonBar) {
2266 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2267 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2268 XtSetValues(buttonBarWidget, args, i);
2272 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2273 XtSetValues(whiteTimerWidget, args, i);
2275 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2276 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2277 XtSetValues(blackTimerWidget, args, i);
2279 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2280 XtSetValues(titleWidget, args, i);
2282 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2283 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2284 XtSetValues(messageWidget, args, i);
2285 if (appData.showButtonBar) {
2287 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2288 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2289 XtSetValues(buttonBarWidget, args, i);
2294 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2295 XtSetValues(whiteTimerWidget, args, i);
2297 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2298 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2299 XtSetValues(blackTimerWidget, args, i);
2301 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2302 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2303 XtSetValues(messageWidget, args, i);
2304 if (appData.showButtonBar) {
2306 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2307 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2308 XtSetValues(buttonBarWidget, args, i);
2312 XtSetArg(args[0], XtNfromVert, messageWidget);
2313 XtSetArg(args[1], XtNtop, XtChainTop);
2314 XtSetArg(args[2], XtNbottom, XtChainBottom);
2315 XtSetArg(args[3], XtNleft, XtChainLeft);
2316 XtSetArg(args[4], XtNright, XtChainRight);
2317 XtSetValues(boardWidget, args, 5);
2319 XtRealizeWidget(shellWidget);
2322 XtSetArg(args[0], XtNx, wpMain.x);
2323 XtSetArg(args[1], XtNy, wpMain.y);
2324 XtSetValues(shellWidget, args, 2);
2328 * Correct the width of the message and title widgets.
2329 * It is not known why some systems need the extra fudge term.
2330 * The value "2" is probably larger than needed.
2332 XawFormDoLayout(formWidget, False);
2334 #define WIDTH_FUDGE 2
2336 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2337 XtSetArg(args[i], XtNheight, &h); i++;
2338 XtGetValues(messageWidget, args, i);
2339 if (appData.showButtonBar) {
2341 XtSetArg(args[i], XtNwidth, &w); i++;
2342 XtGetValues(buttonBarWidget, args, i);
2343 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2345 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2348 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2349 if (gres != XtGeometryYes && appData.debugMode) {
2350 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2351 programName, gres, w, h, wr, hr);
2354 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2355 /* The size used for the child widget in layout lags one resize behind
2356 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2358 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2359 if (gres != XtGeometryYes && appData.debugMode) {
2360 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2361 programName, gres, w, h, wr, hr);
2364 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2365 XtSetArg(args[1], XtNright, XtChainRight);
2366 XtSetValues(messageWidget, args, 2);
2368 if (appData.titleInWindow) {
2370 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2371 XtSetArg(args[i], XtNheight, &h); i++;
2372 XtGetValues(titleWidget, args, i);
2374 w = boardWidth - 2*bor;
2376 XtSetArg(args[0], XtNwidth, &w);
2377 XtGetValues(menuBarWidget, args, 1);
2378 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2381 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2382 if (gres != XtGeometryYes && appData.debugMode) {
2384 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2385 programName, gres, w, h, wr, hr);
2388 XawFormDoLayout(formWidget, True);
2390 xBoardWindow = XtWindow(boardWidget);
2392 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2393 // not need to go into InitDrawingSizes().
2397 * Create X checkmark bitmap and initialize option menu checks.
2399 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2400 checkmark_bits, checkmark_width, checkmark_height);
2401 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2402 if (appData.alwaysPromoteToQueen) {
2403 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2406 if (appData.animateDragging) {
2407 XtSetValues(XtNameToWidget(menuBarWidget,
2408 "menuOptions.Animate Dragging"),
2411 if (appData.animate) {
2412 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2415 if (appData.autoCallFlag) {
2416 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2419 if (appData.autoFlipView) {
2420 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2423 if (appData.blindfold) {
2424 XtSetValues(XtNameToWidget(menuBarWidget,
2425 "menuOptions.Blindfold"), args, 1);
2427 if (appData.flashCount > 0) {
2428 XtSetValues(XtNameToWidget(menuBarWidget,
2429 "menuOptions.Flash Moves"),
2433 if (appData.highlightDragging) {
2434 XtSetValues(XtNameToWidget(menuBarWidget,
2435 "menuOptions.Highlight Dragging"),
2439 if (appData.highlightLastMove) {
2440 XtSetValues(XtNameToWidget(menuBarWidget,
2441 "menuOptions.Highlight Last Move"),
2444 if (appData.highlightMoveWithArrow) {
2445 XtSetValues(XtNameToWidget(menuBarWidget,
2446 "menuOptions.Arrow"),
2449 // if (appData.icsAlarm) {
2450 // XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2453 if (appData.ringBellAfterMoves) {
2454 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2457 if (appData.oneClick) {
2458 XtSetValues(XtNameToWidget(menuBarWidget,
2459 "menuOptions.OneClick"), args, 1);
2461 if (appData.periodicUpdates) {
2462 XtSetValues(XtNameToWidget(menuBarWidget,
2463 "menuOptions.Periodic Updates"), args, 1);
2465 if (appData.ponderNextMove) {
2466 XtSetValues(XtNameToWidget(menuBarWidget,
2467 "menuOptions.Ponder Next Move"), args, 1);
2469 if (appData.popupExitMessage) {
2470 XtSetValues(XtNameToWidget(menuBarWidget,
2471 "menuOptions.Popup Exit Message"), args, 1);
2473 if (appData.popupMoveErrors) {
2474 XtSetValues(XtNameToWidget(menuBarWidget,
2475 "menuOptions.Popup Move Errors"), args, 1);
2477 // if (appData.premove) {
2478 // XtSetValues(XtNameToWidget(menuBarWidget,
2479 // "menuOptions.Premove"), args, 1);
2481 if (appData.showCoords) {
2482 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2485 if (appData.hideThinkingFromHuman) {
2486 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2489 if (appData.testLegality) {
2490 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2493 if (saveSettingsOnExit) {
2494 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2501 ReadBitmap(&wIconPixmap, "icon_white.bm",
2502 icon_white_bits, icon_white_width, icon_white_height);
2503 ReadBitmap(&bIconPixmap, "icon_black.bm",
2504 icon_black_bits, icon_black_width, icon_black_height);
2505 iconPixmap = wIconPixmap;
2507 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2508 XtSetValues(shellWidget, args, i);
2511 * Create a cursor for the board widget.
2513 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2514 XChangeWindowAttributes(xDisplay, xBoardWindow,
2515 CWCursor, &window_attributes);
2518 * Inhibit shell resizing.
2520 shellArgs[0].value = (XtArgVal) &w;
2521 shellArgs[1].value = (XtArgVal) &h;
2522 XtGetValues(shellWidget, shellArgs, 2);
2523 shellArgs[4].value = shellArgs[2].value = w;
2524 shellArgs[5].value = shellArgs[3].value = h;
2525 XtSetValues(shellWidget, &shellArgs[2], 4);
2526 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2527 marginH = h - boardHeight;
2529 CatchDeleteWindow(shellWidget, "QuitProc");
2534 if (appData.bitmapDirectory[0] != NULLCHAR) {
2538 CreateXPMBoard(appData.liteBackTextureFile, 1);
2539 CreateXPMBoard(appData.darkBackTextureFile, 0);
2543 /* Create regular pieces */
2544 if (!useImages) CreatePieces();
2549 if (appData.animate || appData.animateDragging)
2552 XtAugmentTranslations(formWidget,
2553 XtParseTranslationTable(globalTranslations));
2554 XtAugmentTranslations(boardWidget,
2555 XtParseTranslationTable(boardTranslations));
2556 XtAugmentTranslations(whiteTimerWidget,
2557 XtParseTranslationTable(whiteTranslations));
2558 XtAugmentTranslations(blackTimerWidget,
2559 XtParseTranslationTable(blackTranslations));
2561 /* Why is the following needed on some versions of X instead
2562 * of a translation? */
2563 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2564 (XtEventHandler) EventProc, NULL);
2567 /* [AS] Restore layout */
2568 if( wpMoveHistory.visible ) {
2572 if( wpEvalGraph.visible )
2577 if( wpEngineOutput.visible ) {
2578 EngineOutputPopUp();
2583 if (errorExitStatus == -1) {
2584 if (appData.icsActive) {
2585 /* We now wait until we see "login:" from the ICS before
2586 sending the logon script (problems with timestamp otherwise) */
2587 /*ICSInitScript();*/
2588 if (appData.icsInputBox) ICSInputBoxPopUp();
2592 signal(SIGWINCH, TermSizeSigHandler);
2594 signal(SIGINT, IntSigHandler);
2595 signal(SIGTERM, IntSigHandler);
2596 if (*appData.cmailGameName != NULLCHAR) {
2597 signal(SIGUSR1, CmailSigHandler);
2600 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2602 XtSetKeyboardFocus(shellWidget, formWidget);
2604 XtAppMainLoop(appContext);
2605 if (appData.debugMode) fclose(debugFP); // [DM] debug
2612 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2613 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2615 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2616 unlink(gameCopyFilename);
2617 unlink(gamePasteFilename);
2620 RETSIGTYPE TermSizeSigHandler(int sig)
2633 CmailSigHandler(sig)
2639 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2641 /* Activate call-back function CmailSigHandlerCallBack() */
2642 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2644 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2648 CmailSigHandlerCallBack(isr, closure, message, count, error)
2656 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2658 /**** end signal code ****/
2664 /* try to open the icsLogon script, either in the location given
2665 * or in the users HOME directory
2672 f = fopen(appData.icsLogon, "r");
2675 homedir = getenv("HOME");
2676 if (homedir != NULL)
2678 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2679 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2680 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2681 f = fopen(buf, "r");
2686 ProcessICSInitScript(f);
2688 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2697 EditCommentPopDown();
2712 if (!menuBarWidget) return;
2713 w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2715 DisplayError("menuEdit.Revert", 0);
2717 XtSetSensitive(w, !grey);
2719 w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2721 DisplayError("menuEdit.Annotate", 0);
2723 XtSetSensitive(w, !grey);
2728 SetMenuEnables(enab)
2732 if (!menuBarWidget) return;
2733 while (enab->name != NULL) {
2734 w = XtNameToWidget(menuBarWidget, enab->name);
2736 DisplayError(enab->name, 0);
2738 XtSetSensitive(w, enab->value);
2744 Enables icsEnables[] = {
2745 { "menuFile.Mail Move", False },
2746 { "menuFile.Reload CMail Message", False },
2747 { "menuMode.Machine Black", False },
2748 { "menuMode.Machine White", False },
2749 { "menuMode.Analysis Mode", False },
2750 { "menuMode.Analyze File", False },
2751 { "menuMode.Two Machines", False },
2753 { "menuEngine.Hint", False },
2754 { "menuEngine.Book", False },
2755 { "menuEngine.Move Now", False },
2756 { "menuOptions.Periodic Updates", False },
2757 { "menuOptions.Hide Thinking", False },
2758 { "menuOptions.Ponder Next Move", False },
2759 { "menuEngine.Engine #1 Settings", False },
2761 { "menuEngine.Engine #2 Settings", False },
2762 { "menuEdit.Annotate", False },
2766 Enables ncpEnables[] = {
2767 { "menuFile.Mail Move", False },
2768 { "menuFile.Reload CMail Message", False },
2769 { "menuMode.Machine White", False },
2770 { "menuMode.Machine Black", False },
2771 { "menuMode.Analysis Mode", False },
2772 { "menuMode.Analyze File", False },
2773 { "menuMode.Two Machines", False },
2774 { "menuMode.ICS Client", False },
2775 { "menuView.ICS Input Box", False },
2776 { "Action", False },
2777 { "menuEdit.Revert", False },
2778 { "menuEdit.Annotate", False },
2779 { "menuEngine.Engine #1 Settings", False },
2780 { "menuEngine.Engine #2 Settings", False },
2781 { "menuEngine.Move Now", False },
2782 { "menuEngine.Retract Move", False },
2783 { "menuOptions.Auto Flag", False },
2784 { "menuOptions.Auto Flip View", False },
2785 // { "menuOptions.ICS Alarm", False },
2786 { "menuOptions.Move Sound", False },
2787 { "menuOptions.Hide Thinking", False },
2788 { "menuOptions.Periodic Updates", False },
2789 { "menuOptions.Ponder Next Move", False },
2790 { "menuEngine.Hint", False },
2791 { "menuEngine.Book", False },
2795 Enables gnuEnables[] = {
2796 { "menuMode.ICS Client", False },
2797 { "menuView.ICS Input Box", False },
2798 { "menuAction.Accept", False },
2799 { "menuAction.Decline", False },
2800 { "menuAction.Rematch", False },
2801 { "menuAction.Adjourn", False },
2802 { "menuAction.Stop Examining", False },
2803 { "menuAction.Stop Observing", False },
2804 { "menuAction.Upload to Examine", False },
2805 { "menuEdit.Revert", False },
2806 { "menuEdit.Annotate", False },
2808 /* The next two options rely on SetCmailMode being called *after* */
2809 /* SetGNUMode so that when GNU is being used to give hints these */
2810 /* menu options are still available */
2812 { "menuFile.Mail Move", False },
2813 { "menuFile.Reload CMail Message", False },
2817 Enables cmailEnables[] = {
2819 { "menuAction.Call Flag", False },
2820 { "menuAction.Draw", True },
2821 { "menuAction.Adjourn", False },
2822 { "menuAction.Abort", False },
2823 { "menuAction.Stop Observing", False },
2824 { "menuAction.Stop Examining", False },
2825 { "menuFile.Mail Move", True },
2826 { "menuFile.Reload CMail Message", True },
2830 Enables trainingOnEnables[] = {
2831 { "menuMode.Edit Comment", False },
2832 { "menuMode.Pause", False },
2833 { "menuEdit.Forward", False },
2834 { "menuEdit.Backward", False },
2835 { "menuEdit.Forward to End", False },
2836 { "menuEdit.Back to Start", False },
2837 { "menuEngine.Move Now", False },
2838 { "menuEdit.Truncate Game", False },
2842 Enables trainingOffEnables[] = {
2843 { "menuMode.Edit Comment", True },
2844 { "menuMode.Pause", True },
2845 { "menuEdit.Forward", True },
2846 { "menuEdit.Backward", True },
2847 { "menuEdit.Forward to End", True },
2848 { "menuEdit.Back to Start", True },
2849 { "menuEngine.Move Now", True },
2850 { "menuEdit.Truncate Game", True },
2854 Enables machineThinkingEnables[] = {
2855 { "menuFile.Load Game", False },
2856 // { "menuFile.Load Next Game", False },
2857 // { "menuFile.Load Previous Game", False },
2858 // { "menuFile.Reload Same Game", False },
2859 { "menuEdit.Paste Game", False },
2860 { "menuFile.Load Position", False },
2861 // { "menuFile.Load Next Position", False },
2862 // { "menuFile.Load Previous Position", False },
2863 // { "menuFile.Reload Same Position", False },
2864 { "menuEdit.Paste Position", False },
2865 { "menuMode.Machine White", False },
2866 { "menuMode.Machine Black", False },
2867 { "menuMode.Two Machines", False },
2868 { "menuEngine.Retract Move", False },
2872 Enables userThinkingEnables[] = {
2873 { "menuFile.Load Game", True },
2874 // { "menuFile.Load Next Game", True },
2875 // { "menuFile.Load Previous Game", True },
2876 // { "menuFile.Reload Same Game", True },
2877 { "menuEdit.Paste Game", True },
2878 { "menuFile.Load Position", True },
2879 // { "menuFile.Load Next Position", True },
2880 // { "menuFile.Load Previous Position", True },
2881 // { "menuFile.Reload Same Position", True },
2882 { "menuEdit.Paste Position", True },
2883 { "menuMode.Machine White", True },
2884 { "menuMode.Machine Black", True },
2885 { "menuMode.Two Machines", True },
2886 { "menuEngine.Retract Move", True },
2892 SetMenuEnables(icsEnables);
2895 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2896 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2903 SetMenuEnables(ncpEnables);
2909 SetMenuEnables(gnuEnables);
2915 SetMenuEnables(cmailEnables);
2921 SetMenuEnables(trainingOnEnables);
2922 if (appData.showButtonBar) {
2923 XtSetSensitive(buttonBarWidget, False);
2929 SetTrainingModeOff()
2931 SetMenuEnables(trainingOffEnables);
2932 if (appData.showButtonBar) {
2933 XtSetSensitive(buttonBarWidget, True);
2938 SetUserThinkingEnables()
2940 if (appData.noChessProgram) return;
2941 SetMenuEnables(userThinkingEnables);
2945 SetMachineThinkingEnables()
2947 if (appData.noChessProgram) return;
2948 SetMenuEnables(machineThinkingEnables);
2950 case MachinePlaysBlack:
2951 case MachinePlaysWhite:
2952 case TwoMachinesPlay:
2953 XtSetSensitive(XtNameToWidget(menuBarWidget,
2954 ModeToWidgetName(gameMode)), True);
2961 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2962 #define HISTORY_SIZE 64
2963 static char *history[HISTORY_SIZE];
2964 int histIn = 0, histP = 0;
2967 SaveInHistory(char *cmd)
2969 if (history[histIn] != NULL) {
2970 free(history[histIn]);
2971 history[histIn] = NULL;
2973 if (*cmd == NULLCHAR) return;
2974 history[histIn] = StrSave(cmd);
2975 histIn = (histIn + 1) % HISTORY_SIZE;
2976 if (history[histIn] != NULL) {
2977 free(history[histIn]);
2978 history[histIn] = NULL;
2984 PrevInHistory(char *cmd)
2987 if (histP == histIn) {
2988 if (history[histIn] != NULL) free(history[histIn]);
2989 history[histIn] = StrSave(cmd);
2991 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
2992 if (newhp == histIn || history[newhp] == NULL) return NULL;
2994 return history[histP];
3000 if (histP == histIn) return NULL;
3001 histP = (histP + 1) % HISTORY_SIZE;
3002 return history[histP];
3004 // end of borrowed code
3006 #define Abs(n) ((n)<0 ? -(n) : (n))
3009 * Find a font that matches "pattern" that is as close as
3010 * possible to the targetPxlSize. Prefer fonts that are k
3011 * pixels smaller to fonts that are k pixels larger. The
3012 * pattern must be in the X Consortium standard format,
3013 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3014 * The return value should be freed with XtFree when no
3018 FindFont(pattern, targetPxlSize)
3022 char **fonts, *p, *best, *scalable, *scalableTail;
3023 int i, j, nfonts, minerr, err, pxlSize;
3026 char **missing_list;
3028 char *def_string, *base_fnt_lst, strInt[3];
3030 XFontStruct **fnt_list;
3032 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3033 snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize);
3034 p = strstr(pattern, "--");
3035 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3036 strcat(base_fnt_lst, strInt);
3037 strcat(base_fnt_lst, strchr(p + 2, '-'));
3039 if ((fntSet = XCreateFontSet(xDisplay,
3043 &def_string)) == NULL) {
3045 fprintf(stderr, _("Unable to create font set.\n"));
3049 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3051 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3053 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3054 programName, pattern);
3062 for (i=0; i<nfonts; i++) {
3065 if (*p != '-') continue;
3067 if (*p == NULLCHAR) break;
3068 if (*p++ == '-') j++;
3070 if (j < 7) continue;
3073 scalable = fonts[i];
3076 err = pxlSize - targetPxlSize;
3077 if (Abs(err) < Abs(minerr) ||
3078 (minerr > 0 && err < 0 && -err == minerr)) {
3084 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3085 /* If the error is too big and there is a scalable font,
3086 use the scalable font. */
3087 int headlen = scalableTail - scalable;
3088 p = (char *) XtMalloc(strlen(scalable) + 10);
3089 while (isdigit(*scalableTail)) scalableTail++;
3090 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3092 p = (char *) XtMalloc(strlen(best) + 2);
3093 safeStrCpy(p, best, strlen(best)+1 );
3095 if (appData.debugMode) {
3096 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3097 pattern, targetPxlSize, p);
3100 if (missing_count > 0)
3101 XFreeStringList(missing_list);
3102 XFreeFontSet(xDisplay, fntSet);
3104 XFreeFontNames(fonts);
3110 { // [HGM] deletes GCs that are to be remade, to prevent resource leak;
3111 // must be called before all non-first callse to CreateGCs()
3112 XtReleaseGC(shellWidget, highlineGC);
3113 XtReleaseGC(shellWidget, lightSquareGC);
3114 XtReleaseGC(shellWidget, darkSquareGC);
3115 if (appData.monoMode) {
3116 if (DefaultDepth(xDisplay, xScreen) == 1) {
3117 XtReleaseGC(shellWidget, wbPieceGC);
3119 XtReleaseGC(shellWidget, bwPieceGC);
3122 XtReleaseGC(shellWidget, prelineGC);
3123 XtReleaseGC(shellWidget, jailSquareGC);
3124 XtReleaseGC(shellWidget, wdPieceGC);
3125 XtReleaseGC(shellWidget, wlPieceGC);
3126 XtReleaseGC(shellWidget, wjPieceGC);
3127 XtReleaseGC(shellWidget, bdPieceGC);
3128 XtReleaseGC(shellWidget, blPieceGC);
3129 XtReleaseGC(shellWidget, bjPieceGC);
3133 void CreateGCs(int redo)
3135 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3136 | GCBackground | GCFunction | GCPlaneMask;
3137 XGCValues gc_values;
3140 gc_values.plane_mask = AllPlanes;
3141 gc_values.line_width = lineGap;
3142 gc_values.line_style = LineSolid;
3143 gc_values.function = GXcopy;
3146 DeleteGCs(); // called a second time; clean up old GCs first
3147 } else { // [HGM] grid and font GCs created on first call only
3148 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3149 gc_values.background = XBlackPixel(xDisplay, xScreen);
3150 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3152 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3153 gc_values.background = XWhitePixel(xDisplay, xScreen);
3154 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3155 XSetFont(xDisplay, coordGC, coordFontID);
3157 // [HGM] make font for holdings counts (white on black)
3158 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3159 gc_values.background = XBlackPixel(xDisplay, xScreen);
3160 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3161 XSetFont(xDisplay, countGC, countFontID);
3163 if (appData.monoMode) {
3164 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3165 gc_values.background = XWhitePixel(xDisplay, xScreen);
3166 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3168 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3169 gc_values.background = XBlackPixel(xDisplay, xScreen);
3170 lightSquareGC = wbPieceGC
3171 = XtGetGC(shellWidget, value_mask, &gc_values);
3173 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3174 gc_values.background = XWhitePixel(xDisplay, xScreen);
3175 darkSquareGC = bwPieceGC
3176 = XtGetGC(shellWidget, value_mask, &gc_values);
3178 if (DefaultDepth(xDisplay, xScreen) == 1) {
3179 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3180 gc_values.function = GXcopyInverted;
3181 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3182 gc_values.function = GXcopy;
3183 if (XBlackPixel(xDisplay, xScreen) == 1) {
3184 bwPieceGC = darkSquareGC;
3185 wbPieceGC = copyInvertedGC;
3187 bwPieceGC = copyInvertedGC;
3188 wbPieceGC = lightSquareGC;
3192 gc_values.foreground = highlightSquareColor;
3193 gc_values.background = highlightSquareColor;
3194 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3196 gc_values.foreground = premoveHighlightColor;
3197 gc_values.background = premoveHighlightColor;
3198 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3200 gc_values.foreground = lightSquareColor;
3201 gc_values.background = darkSquareColor;
3202 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3204 gc_values.foreground = darkSquareColor;
3205 gc_values.background = lightSquareColor;
3206 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3208 gc_values.foreground = jailSquareColor;
3209 gc_values.background = jailSquareColor;
3210 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3212 gc_values.foreground = whitePieceColor;
3213 gc_values.background = darkSquareColor;
3214 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3216 gc_values.foreground = whitePieceColor;
3217 gc_values.background = lightSquareColor;
3218 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3220 gc_values.foreground = whitePieceColor;
3221 gc_values.background = jailSquareColor;
3222 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3224 gc_values.foreground = blackPieceColor;
3225 gc_values.background = darkSquareColor;
3226 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3228 gc_values.foreground = blackPieceColor;
3229 gc_values.background = lightSquareColor;
3230 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3232 gc_values.foreground = blackPieceColor;
3233 gc_values.background = jailSquareColor;
3234 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3238 void loadXIM(xim, xmask, filename, dest, mask)
3251 fp = fopen(filename, "rb");
3253 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3260 for (y=0; y<h; ++y) {
3261 for (x=0; x<h; ++x) {
3266 XPutPixel(xim, x, y, blackPieceColor);
3268 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3271 XPutPixel(xim, x, y, darkSquareColor);
3273 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3276 XPutPixel(xim, x, y, whitePieceColor);
3278 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3281 XPutPixel(xim, x, y, lightSquareColor);
3283 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3291 /* create Pixmap of piece */
3292 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3294 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3297 /* create Pixmap of clipmask
3298 Note: We assume the white/black pieces have the same
3299 outline, so we make only 6 masks. This is okay
3300 since the XPM clipmask routines do the same. */
3302 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3304 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3307 /* now create the 1-bit version */
3308 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3311 values.foreground = 1;
3312 values.background = 0;
3314 /* Don't use XtGetGC, not read only */
3315 maskGC = XCreateGC(xDisplay, *mask,
3316 GCForeground | GCBackground, &values);
3317 XCopyPlane(xDisplay, temp, *mask, maskGC,
3318 0, 0, squareSize, squareSize, 0, 0, 1);
3319 XFreePixmap(xDisplay, temp);
3324 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3326 void CreateXIMPieces()
3331 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3336 /* The XSynchronize calls were copied from CreatePieces.
3337 Not sure if needed, but can't hurt */
3338 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3341 /* temp needed by loadXIM() */
3342 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3343 0, 0, ss, ss, AllPlanes, XYPixmap);
3345 if (strlen(appData.pixmapDirectory) == 0) {
3349 if (appData.monoMode) {
3350 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3354 fprintf(stderr, _("\nLoading XIMs...\n"));
3356 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3357 fprintf(stderr, "%d", piece+1);
3358 for (kind=0; kind<4; kind++) {
3359 fprintf(stderr, ".");
3360 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3361 ExpandPathName(appData.pixmapDirectory),
3362 piece <= (int) WhiteKing ? "" : "w",
3363 pieceBitmapNames[piece],
3365 ximPieceBitmap[kind][piece] =
3366 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3367 0, 0, ss, ss, AllPlanes, XYPixmap);
3368 if (appData.debugMode)
3369 fprintf(stderr, _("(File:%s:) "), buf);
3370 loadXIM(ximPieceBitmap[kind][piece],
3372 &(xpmPieceBitmap2[kind][piece]),
3373 &(ximMaskPm2[piece]));
3374 if(piece <= (int)WhiteKing)
3375 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3377 fprintf(stderr," ");
3379 /* Load light and dark squares */
3380 /* If the LSQ and DSQ pieces don't exist, we will
3381 draw them with solid squares. */
3382 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3383 if (access(buf, 0) != 0) {
3387 fprintf(stderr, _("light square "));
3389 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3390 0, 0, ss, ss, AllPlanes, XYPixmap);
3391 if (appData.debugMode)
3392 fprintf(stderr, _("(File:%s:) "), buf);
3394 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3395 fprintf(stderr, _("dark square "));
3396 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3397 ExpandPathName(appData.pixmapDirectory), ss);
3398 if (appData.debugMode)
3399 fprintf(stderr, _("(File:%s:) "), buf);
3401 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3402 0, 0, ss, ss, AllPlanes, XYPixmap);
3403 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3404 xpmJailSquare = xpmLightSquare;
3406 fprintf(stderr, _("Done.\n"));
3408 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3412 void CreateXPMBoard(char *s, int kind)
3416 if(s == NULL || *s == 0 || *s == '*') { useTexture &= ~(kind+1); return; }
3417 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3418 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3422 void FreeXPMPieces()
3423 { // [HGM] to prevent resoucre leak on calling CreaeXPMPieces() a second time,
3424 // thisroutine has to be called t free the old piece pixmaps
3426 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++)
3427 for (kind=0; kind<4; kind++) XFreePixmap(xDisplay, xpmPieceBitmap2[kind][piece]);
3429 XFreePixmap(xDisplay, xpmLightSquare);
3430 XFreePixmap(xDisplay, xpmDarkSquare);
3434 void CreateXPMPieces()
3438 u_int ss = squareSize;
3440 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3441 XpmColorSymbol symbols[4];
3442 static int redo = False;
3444 if(redo) FreeXPMPieces(); else redo = 1;
3446 /* The XSynchronize calls were copied from CreatePieces.
3447 Not sure if needed, but can't hurt */
3448 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3450 /* Setup translations so piece colors match square colors */
3451 symbols[0].name = "light_piece";
3452 symbols[0].value = appData.whitePieceColor;
3453 symbols[1].name = "dark_piece";
3454 symbols[1].value = appData.blackPieceColor;
3455 symbols[2].name = "light_square";
3456 symbols[2].value = appData.lightSquareColor;
3457 symbols[3].name = "dark_square";
3458 symbols[3].value = appData.darkSquareColor;
3460 attr.valuemask = XpmColorSymbols;
3461 attr.colorsymbols = symbols;
3462 attr.numsymbols = 4;
3464 if (appData.monoMode) {
3465 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3469 if (strlen(appData.pixmapDirectory) == 0) {
3470 XpmPieces* pieces = builtInXpms;
3473 while (pieces->size != squareSize && pieces->size) pieces++;
3474 if (!pieces->size) {
3475 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3478 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3479 for (kind=0; kind<4; kind++) {
3481 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3482 pieces->xpm[piece][kind],
3483 &(xpmPieceBitmap2[kind][piece]),
3484 NULL, &attr)) != 0) {
3485 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3489 if(piece <= (int) WhiteKing)
3490 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3494 xpmJailSquare = xpmLightSquare;
3498 fprintf(stderr, _("\nLoading XPMs...\n"));
3501 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3502 fprintf(stderr, "%d ", piece+1);
3503 for (kind=0; kind<4; kind++) {
3504 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3505 ExpandPathName(appData.pixmapDirectory),
3506 piece > (int) WhiteKing ? "w" : "",
3507 pieceBitmapNames[piece],
3509 if (appData.debugMode) {
3510 fprintf(stderr, _("(File:%s:) "), buf);
3512 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3513 &(xpmPieceBitmap2[kind][piece]),
3514 NULL, &attr)) != 0) {
3515 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3516 // [HGM] missing: read of unorthodox piece failed; substitute King.
3517 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3518 ExpandPathName(appData.pixmapDirectory),
3520 if (appData.debugMode) {
3521 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3523 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3524 &(xpmPieceBitmap2[kind][piece]),
3528 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3533 if(piece <= (int) WhiteKing)
3534 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3537 /* Load light and dark squares */
3538 /* If the LSQ and DSQ pieces don't exist, we will
3539 draw them with solid squares. */
3540 fprintf(stderr, _("light square "));
3541 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3542 if (access(buf, 0) != 0) {
3546 if (appData.debugMode)
3547 fprintf(stderr, _("(File:%s:) "), buf);
3549 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3550 &xpmLightSquare, NULL, &attr)) != 0) {
3551 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3554 fprintf(stderr, _("dark square "));
3555 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3556 ExpandPathName(appData.pixmapDirectory), ss);
3557 if (appData.debugMode) {
3558 fprintf(stderr, _("(File:%s:) "), buf);
3560 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3561 &xpmDarkSquare, NULL, &attr)) != 0) {
3562 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3566 xpmJailSquare = xpmLightSquare;
3567 fprintf(stderr, _("Done.\n"));
3569 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3572 #endif /* HAVE_LIBXPM */
3575 /* No built-in bitmaps */
3580 u_int ss = squareSize;
3582 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3585 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3586 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3587 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3588 pieceBitmapNames[piece],
3589 ss, kind == SOLID ? 's' : 'o');
3590 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3591 if(piece <= (int)WhiteKing)
3592 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3596 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3600 /* With built-in bitmaps */
3603 BuiltInBits* bib = builtInBits;
3606 u_int ss = squareSize;
3608 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3611 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3613 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3614 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3615 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3616 pieceBitmapNames[piece],
3617 ss, kind == SOLID ? 's' : 'o');
3618 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3619 bib->bits[kind][piece], ss, ss);
3620 if(piece <= (int)WhiteKing)
3621 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3625 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3630 void ReadBitmap(pm, name, bits, wreq, hreq)
3633 unsigned char bits[];
3639 char msg[MSG_SIZ], fullname[MSG_SIZ];
3641 if (*appData.bitmapDirectory != NULLCHAR) {
3642 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3643 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3644 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3645 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3646 &w, &h, pm, &x_hot, &y_hot);
3647 fprintf(stderr, "load %s\n", name);
3648 if (errcode != BitmapSuccess) {
3650 case BitmapOpenFailed:
3651 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3653 case BitmapFileInvalid:
3654 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3656 case BitmapNoMemory:
3657 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3661 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3665 fprintf(stderr, _("%s: %s...using built-in\n"),
3667 } else if (w != wreq || h != hreq) {
3669 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3670 programName, fullname, w, h, wreq, hreq);
3676 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3685 if (lineGap == 0) return;
3687 /* [HR] Split this into 2 loops for non-square boards. */
3689 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3690 gridSegments[i].x1 = 0;
3691 gridSegments[i].x2 =
3692 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3693 gridSegments[i].y1 = gridSegments[i].y2
3694 = lineGap / 2 + (i * (squareSize + lineGap));
3697 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3698 gridSegments[j + i].y1 = 0;
3699 gridSegments[j + i].y2 =
3700 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3701 gridSegments[j + i].x1 = gridSegments[j + i].x2
3702 = lineGap / 2 + (j * (squareSize + lineGap));
3706 static void MenuBarSelect(w, addr, index)
3711 XtActionProc proc = (XtActionProc) addr;
3713 (proc)(NULL, NULL, NULL, NULL);
3716 void CreateMenuBarPopup(parent, name, mb)
3726 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3729 XtSetArg(args[j], XtNleftMargin, 20); j++;
3730 XtSetArg(args[j], XtNrightMargin, 20); j++;
3732 while (mi->string != NULL) {
3733 if (strcmp(mi->string, "----") == 0) {
3734 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3737 XtSetArg(args[j], XtNlabel, XtNewString(mi->string));
3738 entry = XtCreateManagedWidget(mi->ref, smeBSBObjectClass,
3740 XtAddCallback(entry, XtNcallback,
3741 (XtCallbackProc) MenuBarSelect,
3742 (caddr_t) mi->proc);
3748 Widget CreateMenuBar(mb)
3752 Widget anchor, menuBar;
3754 char menuName[MSG_SIZ];
3757 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3758 XtSetArg(args[j], XtNvSpace, 0); j++;
3759 XtSetArg(args[j], XtNborderWidth, 0); j++;
3760 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3761 formWidget, args, j);
3763 while (mb->name != NULL) {
3764 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3765 strncat(menuName, mb->ref, MSG_SIZ - strlen(menuName) - 1);
3767 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3770 shortName[0] = mb->name[0];
3771 shortName[1] = NULLCHAR;
3772 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3775 XtSetArg(args[j], XtNlabel, XtNewString(mb->name)); j++;
3778 XtSetArg(args[j], XtNborderWidth, 0); j++;
3779 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3781 CreateMenuBarPopup(menuBar, menuName, mb);
3787 Widget CreateButtonBar(mi)
3791 Widget button, buttonBar;
3795 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3797 XtSetArg(args[j], XtNhSpace, 0); j++;
3799 XtSetArg(args[j], XtNborderWidth, 0); j++;
3800 XtSetArg(args[j], XtNvSpace, 0); j++;
3801 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3802 formWidget, args, j);
3804 while (mi->string != NULL) {
3807 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3808 XtSetArg(args[j], XtNborderWidth, 0); j++;
3810 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3811 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3812 buttonBar, args, j);
3813 XtAddCallback(button, XtNcallback,
3814 (XtCallbackProc) MenuBarSelect,
3815 (caddr_t) mi->proc);
3822 CreatePieceMenu(name, color)
3829 ChessSquare selection;
3831 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3832 boardWidget, args, 0);
3834 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3835 String item = pieceMenuStrings[color][i];
3837 if (strcmp(item, "----") == 0) {
3838 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3841 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3842 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3844 selection = pieceMenuTranslation[color][i];
3845 XtAddCallback(entry, XtNcallback,
3846 (XtCallbackProc) PieceMenuSelect,
3847 (caddr_t) selection);
3848 if (selection == WhitePawn || selection == BlackPawn) {
3849 XtSetArg(args[0], XtNpopupOnEntry, entry);
3850 XtSetValues(menu, args, 1);
3863 ChessSquare selection;
3865 whitePieceMenu = CreatePieceMenu("menuW", 0);
3866 blackPieceMenu = CreatePieceMenu("menuB", 1);
3868 XtRegisterGrabAction(PieceMenuPopup, True,
3869 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3870 GrabModeAsync, GrabModeAsync);
3872 XtSetArg(args[0], XtNlabel, _("Drop"));
3873 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3874 boardWidget, args, 1);
3875 for (i = 0; i < DROP_MENU_SIZE; i++) {
3876 String item = dropMenuStrings[i];
3878 if (strcmp(item, "----") == 0) {
3879 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3882 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3883 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3885 selection = dropMenuTranslation[i];
3886 XtAddCallback(entry, XtNcallback,
3887 (XtCallbackProc) DropMenuSelect,
3888 (caddr_t) selection);
3893 void SetupDropMenu()
3901 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3902 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3903 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3904 dmEnables[i].piece);
3905 XtSetSensitive(entry, p != NULL || !appData.testLegality
3906 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3907 && !appData.icsActive));
3909 while (p && *p++ == dmEnables[i].piece) count++;
3910 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3912 XtSetArg(args[j], XtNlabel, label); j++;
3913 XtSetValues(entry, args, j);
3917 void PieceMenuPopup(w, event, params, num_params)
3921 Cardinal *num_params;
3923 String whichMenu; int menuNr;
3924 if (event->type == ButtonRelease)
3925 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3926 else if (event->type == ButtonPress)
3927 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3929 case 0: whichMenu = params[0]; break;
3930 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3932 case -1: if (errorUp) ErrorPopDown();
3935 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3938 static void PieceMenuSelect(w, piece, junk)
3943 if (pmFromX < 0 || pmFromY < 0) return;
3944 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3947 static void DropMenuSelect(w, piece, junk)
3952 if (pmFromX < 0 || pmFromY < 0) return;
3953 DropMenuEvent(piece, pmFromX, pmFromY);
3956 void WhiteClock(w, event, prms, nprms)
3965 void BlackClock(w, event, prms, nprms)
3976 * If the user selects on a border boundary, return -1; if off the board,
3977 * return -2. Otherwise map the event coordinate to the square.
3979 int EventToSquare(x, limit)
3987 if ((x % (squareSize + lineGap)) >= squareSize)
3989 x /= (squareSize + lineGap);
3995 static void do_flash_delay(msec)
4001 static void drawHighlight(file, rank, gc)
4007 if (lineGap == 0) return;
4010 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
4011 (squareSize + lineGap);
4012 y = lineGap/2 + rank * (squareSize + lineGap);
4014 x = lineGap/2 + file * (squareSize + lineGap);
4015 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
4016 (squareSize + lineGap);
4019 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
4020 squareSize+lineGap, squareSize+lineGap);
4023 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
4024 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4027 SetHighlights(fromX, fromY, toX, toY)
4028 int fromX, fromY, toX, toY;
4030 if (hi1X != fromX || hi1Y != fromY) {
4031 if (hi1X >= 0 && hi1Y >= 0) {
4032 drawHighlight(hi1X, hi1Y, lineGC);
4034 } // [HGM] first erase both, then draw new!
4035 if (hi2X != toX || hi2Y != toY) {
4036 if (hi2X >= 0 && hi2Y >= 0) {
4037 drawHighlight(hi2X, hi2Y, lineGC);
4040 if (hi1X != fromX || hi1Y != fromY) {
4041 if (fromX >= 0 && fromY >= 0) {
4042 drawHighlight(fromX, fromY, highlineGC);
4045 if (hi2X != toX || hi2Y != toY) {
4046 if (toX >= 0 && toY >= 0) {
4047 drawHighlight(toX, toY, highlineGC);
4059 SetHighlights(-1, -1, -1, -1);
4064 SetPremoveHighlights(fromX, fromY, toX, toY)
4065 int fromX, fromY, toX, toY;
4067 if (pm1X != fromX || pm1Y != fromY) {
4068 if (pm1X >= 0 && pm1Y >= 0) {
4069 drawHighlight(pm1X, pm1Y, lineGC);
4071 if (fromX >= 0 && fromY >= 0) {
4072 drawHighlight(fromX, fromY, prelineGC);
4075 if (pm2X != toX || pm2Y != toY) {
4076 if (pm2X >= 0 && pm2Y >= 0) {
4077 drawHighlight(pm2X, pm2Y, lineGC);
4079 if (toX >= 0 && toY >= 0) {
4080 drawHighlight(toX, toY, prelineGC);
4090 ClearPremoveHighlights()
4092 SetPremoveHighlights(-1, -1, -1, -1);
4095 static int CutOutSquare(x, y, x0, y0, kind)
4096 int x, y, *x0, *y0, kind;
4098 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
4099 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
4101 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
4102 if(textureW[kind] < W*squareSize)
4103 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
4105 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
4106 if(textureH[kind] < H*squareSize)
4107 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
4109 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
4113 static void BlankSquare(x, y, color, piece, dest, fac)
4114 int x, y, color, fac;
4117 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
4119 if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
4120 XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
4121 squareSize, squareSize, x*fac, y*fac);
4123 if (useImages && useImageSqs) {
4127 pm = xpmLightSquare;
4132 case 2: /* neutral */
4137 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4138 squareSize, squareSize, x*fac, y*fac);
4148 case 2: /* neutral */
4153 XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
4158 I split out the routines to draw a piece so that I could
4159 make a generic flash routine.
4161 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4163 int square_color, x, y;
4166 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4167 switch (square_color) {
4169 case 2: /* neutral */
4171 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4172 ? *pieceToOutline(piece)
4173 : *pieceToSolid(piece),
4174 dest, bwPieceGC, 0, 0,
4175 squareSize, squareSize, x, y);
4178 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4179 ? *pieceToSolid(piece)
4180 : *pieceToOutline(piece),
4181 dest, wbPieceGC, 0, 0,
4182 squareSize, squareSize, x, y);
4187 static void monoDrawPiece(piece, square_color, x, y, dest)
4189 int square_color, x, y;
4192 switch (square_color) {
4194 case 2: /* neutral */
4196 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4197 ? *pieceToOutline(piece)
4198 : *pieceToSolid(piece),
4199 dest, bwPieceGC, 0, 0,
4200 squareSize, squareSize, x, y, 1);
4203 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4204 ? *pieceToSolid(piece)
4205 : *pieceToOutline(piece),
4206 dest, wbPieceGC, 0, 0,
4207 squareSize, squareSize, x, y, 1);
4212 static void colorDrawPiece(piece, square_color, x, y, dest)
4214 int square_color, x, y;
4217 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4218 switch (square_color) {
4220 XCopyPlane(xDisplay, *pieceToSolid(piece),
4221 dest, (int) piece < (int) BlackPawn
4222 ? wlPieceGC : blPieceGC, 0, 0,
4223 squareSize, squareSize, x, y, 1);
4226 XCopyPlane(xDisplay, *pieceToSolid(piece),
4227 dest, (int) piece < (int) BlackPawn
4228 ? wdPieceGC : bdPieceGC, 0, 0,
4229 squareSize, squareSize, x, y, 1);
4231 case 2: /* neutral */
4233 XCopyPlane(xDisplay, *pieceToSolid(piece),
4234 dest, (int) piece < (int) BlackPawn
4235 ? wjPieceGC : bjPieceGC, 0, 0,
4236 squareSize, squareSize, x, y, 1);
4241 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4243 int square_color, x, y;
4246 int kind, p = piece;
4248 switch (square_color) {
4250 case 2: /* neutral */
4252 if ((int)piece < (int) BlackPawn) {
4260 if ((int)piece < (int) BlackPawn) {
4268 if(appData.upsideDown && flipView) { kind ^= 2; p += p < BlackPawn ? BlackPawn : -BlackPawn; }// swap white and black pieces
4269 if(useTexture & square_color+1) {
4270 BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background
4271 XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]);
4272 XSetClipOrigin(xDisplay, wlPieceGC, x, y);
4273 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y);
4274 XSetClipMask(xDisplay, wlPieceGC, None);
4275 XSetClipOrigin(xDisplay, wlPieceGC, 0, 0);
4277 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4278 dest, wlPieceGC, 0, 0,
4279 squareSize, squareSize, x, y);
4282 typedef void (*DrawFunc)();
4284 DrawFunc ChooseDrawFunc()
4286 if (appData.monoMode) {
4287 if (DefaultDepth(xDisplay, xScreen) == 1) {
4288 return monoDrawPiece_1bit;
4290 return monoDrawPiece;
4294 return colorDrawPieceImage;
4296 return colorDrawPiece;
4300 /* [HR] determine square color depending on chess variant. */
4301 static int SquareColor(row, column)
4306 if (gameInfo.variant == VariantXiangqi) {
4307 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4309 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4311 } else if (row <= 4) {
4317 square_color = ((column + row) % 2) == 1;
4320 /* [hgm] holdings: next line makes all holdings squares light */
4321 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4323 return square_color;
4326 void DrawSquare(row, column, piece, do_flash)
4327 int row, column, do_flash;
4330 int square_color, x, y, direction, font_ascent, font_descent;
4333 XCharStruct overall;
4337 /* Calculate delay in milliseconds (2-delays per complete flash) */
4338 flash_delay = 500 / appData.flashRate;
4341 x = lineGap + ((BOARD_WIDTH-1)-column) *
4342 (squareSize + lineGap);
4343 y = lineGap + row * (squareSize + lineGap);
4345 x = lineGap + column * (squareSize + lineGap);
4346 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4347 (squareSize + lineGap);
4350 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4352 square_color = SquareColor(row, column);
4354 if ( // [HGM] holdings: blank out area between board and holdings
4355 column == BOARD_LEFT-1 || column == BOARD_RGHT
4356 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4357 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4358 BlankSquare(x, y, 2, EmptySquare, xBoardWindow, 1);
4360 // [HGM] print piece counts next to holdings
4361 string[1] = NULLCHAR;
4362 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4363 string[0] = '0' + piece;
4364 XTextExtents(countFontStruct, string, 1, &direction,
4365 &font_ascent, &font_descent, &overall);
4366 if (appData.monoMode) {
4367 XDrawImageString(xDisplay, xBoardWindow, countGC,
4368 x + squareSize - overall.width - 2,
4369 y + font_ascent + 1, string, 1);
4371 XDrawString(xDisplay, xBoardWindow, countGC,
4372 x + squareSize - overall.width - 2,
4373 y + font_ascent + 1, string, 1);
4376 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4377 string[0] = '0' + piece;
4378 XTextExtents(countFontStruct, string, 1, &direction,
4379 &font_ascent, &font_descent, &overall);
4380 if (appData.monoMode) {
4381 XDrawImageString(xDisplay, xBoardWindow, countGC,
4382 x + 2, y + font_ascent + 1, string, 1);
4384 XDrawString(xDisplay, xBoardWindow, countGC,
4385 x + 2, y + font_ascent + 1, string, 1);
4389 if (piece == EmptySquare || appData.blindfold) {
4390 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4392 drawfunc = ChooseDrawFunc();
4393 if (do_flash && appData.flashCount > 0) {
4394 for (i=0; i<appData.flashCount; ++i) {
4396 drawfunc(piece, square_color, x, y, xBoardWindow);
4397 XSync(xDisplay, False);
4398 do_flash_delay(flash_delay);
4400 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4401 XSync(xDisplay, False);
4402 do_flash_delay(flash_delay);
4405 drawfunc(piece, square_color, x, y, xBoardWindow);
4409 string[1] = NULLCHAR;
4410 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4411 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4412 string[0] = 'a' + column - BOARD_LEFT;
4413 XTextExtents(coordFontStruct, string, 1, &direction,
4414 &font_ascent, &font_descent, &overall);
4415 if (appData.monoMode) {
4416 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4417 x + squareSize - overall.width - 2,
4418 y + squareSize - font_descent - 1, string, 1);
4420 XDrawString(xDisplay, xBoardWindow, coordGC,
4421 x + squareSize - overall.width - 2,
4422 y + squareSize - font_descent - 1, string, 1);
4425 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4426 string[0] = ONE + row;
4427 XTextExtents(coordFontStruct, string, 1, &direction,
4428 &font_ascent, &font_descent, &overall);
4429 if (appData.monoMode) {
4430 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4431 x + 2, y + font_ascent + 1, string, 1);
4433 XDrawString(xDisplay, xBoardWindow, coordGC,
4434 x + 2, y + font_ascent + 1, string, 1);
4437 if(!partnerUp && marker[row][column]) {
4438 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4439 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4444 /* Why is this needed on some versions of X? */
4445 void EventProc(widget, unused, event)
4450 if (!XtIsRealized(widget))
4453 switch (event->type) {
4455 if (event->xexpose.count > 0) return; /* no clipping is done */
4456 XDrawPosition(widget, True, NULL);
4457 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4458 flipView = !flipView; partnerUp = !partnerUp;
4459 XDrawPosition(widget, True, NULL);
4460 flipView = !flipView; partnerUp = !partnerUp;
4464 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
4471 void DrawPosition(fullRedraw, board)
4472 /*Boolean*/int fullRedraw;
4475 XDrawPosition(boardWidget, fullRedraw, board);
4478 /* Returns 1 if there are "too many" differences between b1 and b2
4479 (i.e. more than 1 move was made) */
4480 static int too_many_diffs(b1, b2)
4486 for (i=0; i<BOARD_HEIGHT; ++i) {
4487 for (j=0; j<BOARD_WIDTH; ++j) {
4488 if (b1[i][j] != b2[i][j]) {
4489 if (++c > 4) /* Castling causes 4 diffs */
4498 /* Matrix describing castling maneuvers */
4499 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4500 static int castling_matrix[4][5] = {
4501 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4502 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4503 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4504 { 7, 7, 4, 5, 6 } /* 0-0, black */
4507 /* Checks whether castling occurred. If it did, *rrow and *rcol
4508 are set to the destination (row,col) of the rook that moved.
4510 Returns 1 if castling occurred, 0 if not.
4512 Note: Only handles a max of 1 castling move, so be sure
4513 to call too_many_diffs() first.
4515 static int check_castle_draw(newb, oldb, rrow, rcol)
4522 /* For each type of castling... */
4523 for (i=0; i<4; ++i) {
4524 r = castling_matrix[i];
4526 /* Check the 4 squares involved in the castling move */
4528 for (j=1; j<=4; ++j) {
4529 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4536 /* All 4 changed, so it must be a castling move */
4545 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4546 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4548 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4551 void DrawSeekBackground( int left, int top, int right, int bottom )
4553 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4556 void DrawSeekText(char *buf, int x, int y)
4558 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4561 void DrawSeekDot(int x, int y, int colorNr)
4563 int square = colorNr & 0x80;
4566 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4568 XFillRectangle(xDisplay, xBoardWindow, color,
4569 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4571 XFillArc(xDisplay, xBoardWindow, color,
4572 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4575 static int damage[2][BOARD_RANKS][BOARD_FILES];
4578 * event handler for redrawing the board
4580 void XDrawPosition(w, repaint, board)
4582 /*Boolean*/int repaint;
4586 static int lastFlipView = 0;
4587 static int lastBoardValid[2] = {0, 0};
4588 static Board lastBoard[2];
4591 int nr = twoBoards*partnerUp;
4593 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4595 if (board == NULL) {
4596 if (!lastBoardValid[nr]) return;
4597 board = lastBoard[nr];
4599 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4600 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4601 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Flip View"),
4606 * It would be simpler to clear the window with XClearWindow()
4607 * but this causes a very distracting flicker.
4610 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4612 if ( lineGap && IsDrawArrowEnabled())
4613 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4614 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4616 /* If too much changes (begin observing new game, etc.), don't
4618 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4620 /* Special check for castling so we don't flash both the king
4621 and the rook (just flash the king). */
4623 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4624 /* Draw rook with NO flashing. King will be drawn flashing later */
4625 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4626 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4630 /* First pass -- Draw (newly) empty squares and repair damage.
4631 This prevents you from having a piece show up twice while it
4632 is flashing on its new square */
4633 for (i = 0; i < BOARD_HEIGHT; i++)
4634 for (j = 0; j < BOARD_WIDTH; j++)
4635 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4636 || damage[nr][i][j]) {
4637 DrawSquare(i, j, board[i][j], 0);
4638 damage[nr][i][j] = False;
4641 /* Second pass -- Draw piece(s) in new position and flash them */
4642 for (i = 0; i < BOARD_HEIGHT; i++)
4643 for (j = 0; j < BOARD_WIDTH; j++)
4644 if (board[i][j] != lastBoard[nr][i][j]) {
4645 DrawSquare(i, j, board[i][j], do_flash);
4649 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4650 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4651 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4653 for (i = 0; i < BOARD_HEIGHT; i++)
4654 for (j = 0; j < BOARD_WIDTH; j++) {
4655 DrawSquare(i, j, board[i][j], 0);
4656 damage[nr][i][j] = False;
4660 CopyBoard(lastBoard[nr], board);
4661 lastBoardValid[nr] = 1;
4662 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4663 lastFlipView = flipView;
4665 /* Draw highlights */
4666 if (pm1X >= 0 && pm1Y >= 0) {
4667 drawHighlight(pm1X, pm1Y, prelineGC);
4669 if (pm2X >= 0 && pm2Y >= 0) {
4670 drawHighlight(pm2X, pm2Y, prelineGC);
4672 if (hi1X >= 0 && hi1Y >= 0) {
4673 drawHighlight(hi1X, hi1Y, highlineGC);
4675 if (hi2X >= 0 && hi2Y >= 0) {
4676 drawHighlight(hi2X, hi2Y, highlineGC);
4678 DrawArrowHighlight(hi1X, hi1Y, hi2X, hi2Y);
4680 /* If piece being dragged around board, must redraw that too */
4683 XSync(xDisplay, False);
4688 * event handler for redrawing the board
4690 void DrawPositionProc(w, event, prms, nprms)
4696 XDrawPosition(w, True, NULL);
4701 * event handler for parsing user moves
4703 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4704 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4705 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4706 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4707 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4708 // and at the end FinishMove() to perform the move after optional promotion popups.
4709 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4710 void HandleUserMove(w, event, prms, nprms)
4716 if (w != boardWidget || errorExitStatus != -1) return;
4717 if(nprms) shiftKey = !strcmp(prms[0], "1");
4720 if (event->type == ButtonPress) {
4721 XtPopdown(promotionShell);
4722 XtDestroyWidget(promotionShell);
4723 promotionUp = False;
4731 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4732 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4733 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4736 void AnimateUserMove (Widget w, XEvent * event,
4737 String * params, Cardinal * nParams)
4739 DragPieceMove(event->xmotion.x, event->xmotion.y);
4742 void HandlePV (Widget w, XEvent * event,
4743 String * params, Cardinal * nParams)
4744 { // [HGM] pv: walk PV
4745 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4748 Widget CommentCreate(name, text, mutable, callback, lines)
4750 int /*Boolean*/ mutable;
4751 XtCallbackProc callback;
4755 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4760 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4761 XtGetValues(boardWidget, args, j);
4764 XtSetArg(args[j], XtNresizable, True); j++;
4767 XtCreatePopupShell(name, topLevelShellWidgetClass,
4768 shellWidget, args, j);
4771 XtCreatePopupShell(name, transientShellWidgetClass,
4772 shellWidget, args, j);
4775 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4776 layoutArgs, XtNumber(layoutArgs));
4778 XtCreateManagedWidget("form", formWidgetClass, layout,
4779 formArgs, XtNumber(formArgs));
4783 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4784 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4786 XtSetArg(args[j], XtNstring, text); j++;
4787 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4788 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4789 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4790 XtSetArg(args[j], XtNright, XtChainRight); j++;
4791 XtSetArg(args[j], XtNresizable, True); j++;
4792 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4793 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4794 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4795 XtSetArg(args[j], XtNautoFill, True); j++;
4796 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4798 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4799 XtOverrideTranslations(edit, XtParseTranslationTable(commentTranslations));
4803 XtSetArg(args[j], XtNfromVert, edit); j++;
4804 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4805 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4806 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4807 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4809 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4810 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4813 XtSetArg(args[j], XtNfromVert, edit); j++;
4814 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4815 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4816 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4817 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4818 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4820 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4821 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4824 XtSetArg(args[j], XtNfromVert, edit); j++;
4825 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4826 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4827 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4828 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4829 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4831 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4832 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4835 XtSetArg(args[j], XtNfromVert, edit); j++;
4836 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4837 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4838 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4839 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4841 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4842 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4845 XtSetArg(args[j], XtNfromVert, edit); j++;
4846 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4847 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4848 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4849 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4850 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4852 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4853 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4856 XtRealizeWidget(shell);
4858 if (commentX == -1) {
4861 Dimension pw_height;
4862 Dimension ew_height;
4865 XtSetArg(args[j], XtNheight, &ew_height); j++;
4866 XtGetValues(edit, args, j);
4869 XtSetArg(args[j], XtNheight, &pw_height); j++;
4870 XtGetValues(shell, args, j);
4871 commentH = pw_height + (lines - 1) * ew_height;
4872 commentW = bw_width - 16;
4874 XSync(xDisplay, False);
4876 /* This code seems to tickle an X bug if it is executed too soon
4877 after xboard starts up. The coordinates get transformed as if
4878 the main window was positioned at (0, 0).
4880 XtTranslateCoords(shellWidget,
4881 (bw_width - commentW) / 2, 0 - commentH / 2,
4882 &commentX, &commentY);
4884 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4885 RootWindowOfScreen(XtScreen(shellWidget)),
4886 (bw_width - commentW) / 2, 0 - commentH / 2,
4891 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4894 if(wpComment.width > 0) {
4895 commentX = wpComment.x;
4896 commentY = wpComment.y;
4897 commentW = wpComment.width;
4898 commentH = wpComment.height;
4902 XtSetArg(args[j], XtNheight, commentH); j++;
4903 XtSetArg(args[j], XtNwidth, commentW); j++;
4904 XtSetArg(args[j], XtNx, commentX); j++;
4905 XtSetArg(args[j], XtNy, commentY); j++;
4906 XtSetValues(shell, args, j);
4907 XtSetKeyboardFocus(shell, edit);
4912 /* Used for analysis window and ICS input window */
4913 Widget MiscCreate(name, text, mutable, callback, lines)
4915 int /*Boolean*/ mutable;
4916 XtCallbackProc callback;
4920 Widget shell, layout, form, edit;
4922 Dimension bw_width, pw_height, ew_height, w, h;
4928 XtSetArg(args[j], XtNresizable, True); j++;
4931 XtCreatePopupShell(name, topLevelShellWidgetClass,
4932 shellWidget, args, j);
4935 XtCreatePopupShell(name, transientShellWidgetClass,
4936 shellWidget, args, j);
4939 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4940 layoutArgs, XtNumber(layoutArgs));
4942 XtCreateManagedWidget("form", formWidgetClass, layout,
4943 formArgs, XtNumber(formArgs));
4947 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4948 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4950 XtSetArg(args[j], XtNstring, text); j++;
4951 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4952 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4953 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4954 XtSetArg(args[j], XtNright, XtChainRight); j++;
4955 XtSetArg(args[j], XtNresizable, True); j++;
4956 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4957 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4958 XtSetArg(args[j], XtNautoFill, True); j++;
4959 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4961 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4963 XtRealizeWidget(shell);
4966 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4967 XtGetValues(boardWidget, args, j);
4970 XtSetArg(args[j], XtNheight, &ew_height); j++;
4971 XtGetValues(edit, args, j);
4974 XtSetArg(args[j], XtNheight, &pw_height); j++;
4975 XtGetValues(shell, args, j);
4976 h = pw_height + (lines - 1) * ew_height;
4979 XSync(xDisplay, False);
4981 /* This code seems to tickle an X bug if it is executed too soon
4982 after xboard starts up. The coordinates get transformed as if
4983 the main window was positioned at (0, 0).
4985 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4987 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4988 RootWindowOfScreen(XtScreen(shellWidget)),
4989 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4993 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4996 XtSetArg(args[j], XtNheight, h); j++;
4997 XtSetArg(args[j], XtNwidth, w); j++;
4998 XtSetArg(args[j], XtNx, x); j++;
4999 XtSetArg(args[j], XtNy, y); j++;
5000 XtSetValues(shell, args, j);
5006 static int savedIndex; /* gross that this is global */
5008 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
5011 XawTextPosition index, dummy;
5014 XawTextGetSelectionPos(w, &index, &dummy);
5015 XtSetArg(arg, XtNstring, &val);
5016 XtGetValues(w, &arg, 1);
5017 ReplaceComment(savedIndex, val);
5018 if(savedIndex != currentMove) ToNrEvent(savedIndex);
5019 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
5022 void EditCommentPopUp(index, title, text)
5031 if (text == NULL) text = "";
5033 if (editShell == NULL) {
5035 CommentCreate(title, text, True, EditCommentCallback, 4);
5036 XtRealizeWidget(editShell);
5037 CatchDeleteWindow(editShell, "EditCommentPopDown");
5039 edit = XtNameToWidget(editShell, "*form.text");
5041 XtSetArg(args[j], XtNstring, text); j++;
5042 XtSetValues(edit, args, j);
5044 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5045 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5046 XtSetValues(editShell, args, j);
5049 XtPopup(editShell, XtGrabNone);
5053 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5054 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"),
5056 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"),
5060 void EditCommentCallback(w, client_data, call_data)
5062 XtPointer client_data, call_data;
5070 XtSetArg(args[j], XtNlabel, &name); j++;
5071 XtGetValues(w, args, j);
5073 if (strcmp(name, _("ok")) == 0) {
5074 edit = XtNameToWidget(editShell, "*form.text");
5076 XtSetArg(args[j], XtNstring, &val); j++;
5077 XtGetValues(edit, args, j);
5078 ReplaceComment(savedIndex, val);
5079 EditCommentPopDown();
5080 } else if (strcmp(name, _("cancel")) == 0) {
5081 EditCommentPopDown();
5082 } else if (strcmp(name, _("clear")) == 0) {
5083 edit = XtNameToWidget(editShell, "*form.text");
5084 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5085 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5089 void EditCommentPopDown()
5094 if (!editUp) return;
5096 XtSetArg(args[j], XtNx, &commentX); j++;
5097 XtSetArg(args[j], XtNy, &commentY); j++;
5098 XtSetArg(args[j], XtNheight, &commentH); j++;
5099 XtSetArg(args[j], XtNwidth, &commentW); j++;
5100 XtGetValues(editShell, args, j);
5101 XtPopdown(editShell);
5104 XtSetArg(args[j], XtNleftBitmap, None); j++;
5105 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"),
5107 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"),
5111 void ICSInputBoxPopUp()
5116 char *title = _("ICS Input");
5119 if (ICSInputShell == NULL) {
5120 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
5121 tr = XtParseTranslationTable(ICSInputTranslations);
5122 edit = XtNameToWidget(ICSInputShell, "*form.text");
5123 XtOverrideTranslations(edit, tr);
5124 XtRealizeWidget(ICSInputShell);
5125 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
5128 edit = XtNameToWidget(ICSInputShell, "*form.text");
5130 XtSetArg(args[j], XtNstring, ""); j++;
5131 XtSetValues(edit, args, j);
5133 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5134 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5135 XtSetValues(ICSInputShell, args, j);
5138 XtPopup(ICSInputShell, XtGrabNone);
5139 XtSetKeyboardFocus(ICSInputShell, edit);
5141 ICSInputBoxUp = True;
5143 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5144 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.ICS Input Box"),
5148 void ICSInputSendText()
5155 edit = XtNameToWidget(ICSInputShell, "*form.text");
5157 XtSetArg(args[j], XtNstring, &val); j++;
5158 XtGetValues(edit, args, j);
5160 SendMultiLineToICS(val);
5161 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5162 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5165 void ICSInputBoxPopDown()
5170 if (!ICSInputBoxUp) return;
5172 XtPopdown(ICSInputShell);
5173 ICSInputBoxUp = False;
5175 XtSetArg(args[j], XtNleftBitmap, None); j++;
5176 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.ICS Input Box"),
5180 void CommentPopUp(title, text)
5187 savedIndex = currentMove; // [HGM] vari
5188 if (commentShell == NULL) {
5190 CommentCreate(title, text, False, CommentCallback, 4);
5191 XtRealizeWidget(commentShell);
5192 CatchDeleteWindow(commentShell, "CommentPopDown");
5194 edit = XtNameToWidget(commentShell, "*form.text");
5196 XtSetArg(args[j], XtNstring, text); j++;
5197 XtSetValues(edit, args, j);
5199 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5200 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5201 XtSetValues(commentShell, args, j);
5204 XtPopup(commentShell, XtGrabNone);
5205 XSync(xDisplay, False);
5210 void CommentCallback(w, client_data, call_data)
5212 XtPointer client_data, call_data;
5219 XtSetArg(args[j], XtNlabel, &name); j++;
5220 XtGetValues(w, args, j);
5222 if (strcmp(name, _("close")) == 0) {
5224 } else if (strcmp(name, _("edit")) == 0) {
5231 void CommentPopDown()
5236 if (!commentUp) return;
5238 XtSetArg(args[j], XtNx, &commentX); j++;
5239 XtSetArg(args[j], XtNy, &commentY); j++;
5240 XtSetArg(args[j], XtNwidth, &commentW); j++;
5241 XtSetArg(args[j], XtNheight, &commentH); j++;
5242 XtGetValues(commentShell, args, j);
5243 XtPopdown(commentShell);
5244 XSync(xDisplay, False);
5248 void FileNamePopUp(label, def, proc, openMode)
5254 fileProc = proc; /* I can't see a way not */
5255 fileOpenMode = openMode; /* to use globals here */
5256 { // [HGM] use file-selector dialog stolen from Ghostview
5258 int index; // this is not supported yet
5260 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5261 def, openMode, NULL, &name))
5262 (void) (*fileProc)(f, index=0, name);
5266 void FileNamePopDown()
5268 if (!filenameUp) return;
5269 XtPopdown(fileNameShell);
5270 XtDestroyWidget(fileNameShell);
5275 void FileNameCallback(w, client_data, call_data)
5277 XtPointer client_data, call_data;
5282 XtSetArg(args[0], XtNlabel, &name);
5283 XtGetValues(w, args, 1);
5285 if (strcmp(name, _("cancel")) == 0) {
5290 FileNameAction(w, NULL, NULL, NULL);
5293 void FileNameAction(w, event, prms, nprms)
5305 name = XawDialogGetValueString(w = XtParent(w));
5307 if ((name != NULL) && (*name != NULLCHAR)) {
5308 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
5309 XtPopdown(w = XtParent(XtParent(w)));
5313 p = strrchr(buf, ' ');
5320 fullname = ExpandPathName(buf);
5322 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5325 f = fopen(fullname, fileOpenMode);
5327 DisplayError(_("Failed to open file"), errno);
5329 (void) (*fileProc)(f, index, buf);
5336 XtPopdown(w = XtParent(XtParent(w)));
5342 void PromotionPopUp()
5345 Widget dialog, layout;
5347 Dimension bw_width, pw_width;
5351 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5352 XtGetValues(boardWidget, args, j);
5355 XtSetArg(args[j], XtNresizable, True); j++;
5356 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5358 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5359 shellWidget, args, j);
5361 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5362 layoutArgs, XtNumber(layoutArgs));
5365 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5366 XtSetArg(args[j], XtNborderWidth, 0); j++;
5367 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5370 if(gameInfo.variant != VariantShogi) {
5371 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) {
5372 XawDialogAddButton(dialog, _("Warlord"), PromotionCallback,
5373 (XtPointer) dialog);
5374 XawDialogAddButton(dialog, _("General"), PromotionCallback,
5375 (XtPointer) dialog);
5376 XawDialogAddButton(dialog, _("Lieutenant"), PromotionCallback,
5377 (XtPointer) dialog);
5378 XawDialogAddButton(dialog, _("Captain"), PromotionCallback,
5379 (XtPointer) dialog);
5381 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5382 (XtPointer) dialog);
5383 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5384 (XtPointer) dialog);
5385 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5386 (XtPointer) dialog);
5387 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5388 (XtPointer) dialog);
5390 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5391 gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
\r
5392 gameInfo.variant == VariantGiveaway) {
5393 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5394 (XtPointer) dialog);
5396 if(gameInfo.variant == VariantCapablanca ||
5397 gameInfo.variant == VariantGothic ||
5398 gameInfo.variant == VariantCapaRandom) {
5399 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5400 (XtPointer) dialog);
5401 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5402 (XtPointer) dialog);
5404 } else // [HGM] shogi
5406 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5407 (XtPointer) dialog);
5408 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5409 (XtPointer) dialog);
5411 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5412 (XtPointer) dialog);
5414 XtRealizeWidget(promotionShell);
5415 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5418 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5419 XtGetValues(promotionShell, args, j);
5421 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5422 lineGap + squareSize/3 +
5423 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5424 0 : 6*(squareSize + lineGap)), &x, &y);
5427 XtSetArg(args[j], XtNx, x); j++;
5428 XtSetArg(args[j], XtNy, y); j++;
5429 XtSetValues(promotionShell, args, j);
5431 XtPopup(promotionShell, XtGrabNone);
5436 void PromotionPopDown()
5438 if (!promotionUp) return;
5439 XtPopdown(promotionShell);
5440 XtDestroyWidget(promotionShell);
5441 promotionUp = False;
5444 void PromotionCallback(w, client_data, call_data)
5446 XtPointer client_data, call_data;
5452 XtSetArg(args[0], XtNlabel, &name);
5453 XtGetValues(w, args, 1);
5457 if (fromX == -1) return;
5459 if (strcmp(name, _("cancel")) == 0) {
5463 } else if (strcmp(name, _("Knight")) == 0) {
5465 } else if (strcmp(name, _("Promote")) == 0) {
5467 } else if (strcmp(name, _("Defer")) == 0) {
5470 promoChar = ToLower(name[0]);
5473 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5475 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5476 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5481 void ErrorCallback(w, client_data, call_data)
5483 XtPointer client_data, call_data;
5486 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5488 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5494 if (!errorUp) return;
5496 XtPopdown(errorShell);
5497 XtDestroyWidget(errorShell);
5498 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5501 void ErrorPopUp(title, label, modal)
5502 char *title, *label;
5506 Widget dialog, layout;
5510 Dimension bw_width, pw_width;
5511 Dimension pw_height;
5515 XtSetArg(args[i], XtNresizable, True); i++;
5516 XtSetArg(args[i], XtNtitle, title); i++;
5518 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5519 shellWidget, args, i);
5521 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5522 layoutArgs, XtNumber(layoutArgs));
5525 XtSetArg(args[i], XtNlabel, label); i++;
5526 XtSetArg(args[i], XtNborderWidth, 0); i++;
5527 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5530 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5532 XtRealizeWidget(errorShell);
5533 CatchDeleteWindow(errorShell, "ErrorPopDown");
5536 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5537 XtGetValues(boardWidget, args, i);
5539 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5540 XtSetArg(args[i], XtNheight, &pw_height); i++;
5541 XtGetValues(errorShell, args, i);
5544 /* This code seems to tickle an X bug if it is executed too soon
5545 after xboard starts up. The coordinates get transformed as if
5546 the main window was positioned at (0, 0).
5548 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5549 0 - pw_height + squareSize / 3, &x, &y);
5551 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5552 RootWindowOfScreen(XtScreen(boardWidget)),
5553 (bw_width - pw_width) / 2,
5554 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5558 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5561 XtSetArg(args[i], XtNx, x); i++;
5562 XtSetArg(args[i], XtNy, y); i++;
5563 XtSetValues(errorShell, args, i);
5566 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5569 /* Disable all user input other than deleting the window */
5570 static int frozen = 0;
5574 /* Grab by a widget that doesn't accept input */
5575 XtAddGrab(messageWidget, TRUE, FALSE);
5579 /* Undo a FreezeUI */
5582 if (!frozen) return;
5583 XtRemoveGrab(messageWidget);
5587 char *ModeToWidgetName(mode)
5591 case BeginningOfGame:
5592 if (appData.icsActive)
5593 return "menuMode.ICS Client";
5594 else if (appData.noChessProgram ||
5595 *appData.cmailGameName != NULLCHAR)
5596 return "menuMode.Edit Game";
5598 return "menuMode.Machine Black";
5599 case MachinePlaysBlack:
5600 return "menuMode.Machine Black";
5601 case MachinePlaysWhite:
5602 return "menuMode.Machine White";
5604 return "menuMode.Analysis Mode";
5606 return "menuMode.Analyze File";
5607 case TwoMachinesPlay:
5608 return "menuMode.Two Machines";
5610 return "menuMode.Edit Game";
5611 case PlayFromGameFile:
5612 return "menuFile.Load Game";
5614 return "menuMode.Edit Position";
5616 return "menuMode.Training";
5617 case IcsPlayingWhite:
5618 case IcsPlayingBlack:
5622 return "menuMode.ICS Client";
5629 void ModeHighlight()
5632 static int oldPausing = FALSE;
5633 static GameMode oldmode = (GameMode) -1;
5636 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5638 if (pausing != oldPausing) {
5639 oldPausing = pausing;
5641 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5643 XtSetArg(args[0], XtNleftBitmap, None);
5645 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5648 if (appData.showButtonBar) {
5649 /* Always toggle, don't set. Previous code messes up when
5650 invoked while the button is pressed, as releasing it
5651 toggles the state again. */
5654 XtSetArg(args[0], XtNbackground, &oldbg);
5655 XtSetArg(args[1], XtNforeground, &oldfg);
5656 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5658 XtSetArg(args[0], XtNbackground, oldfg);
5659 XtSetArg(args[1], XtNforeground, oldbg);
5661 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5665 wname = ModeToWidgetName(oldmode);
5666 if (wname != NULL) {
5667 XtSetArg(args[0], XtNleftBitmap, None);
5668 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5670 wname = ModeToWidgetName(gameMode);
5671 if (wname != NULL) {
5672 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5673 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5677 /* Maybe all the enables should be handled here, not just this one */
5678 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5679 gameMode == Training || gameMode == PlayFromGameFile);
5684 * Button/menu procedures
5686 void ResetProc(w, event, prms, nprms)
5695 int LoadGamePopUp(f, gameNumber, title)
5700 cmailMsgLoaded = FALSE;
5701 if (gameNumber == 0) {
5702 int error = GameListBuild(f);
5704 DisplayError(_("Cannot build game list"), error);
5705 } else if (!ListEmpty(&gameList) &&
5706 ((ListGame *) gameList.tailPred)->number > 1) {
5707 GameListPopUp(f, title);
5713 return LoadGame(f, gameNumber, title, FALSE);
5716 void LoadGameProc(w, event, prms, nprms)
5722 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5725 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5728 void LoadNextGameProc(w, event, prms, nprms)
5737 void LoadPrevGameProc(w, event, prms, nprms)
5746 void ReloadGameProc(w, event, prms, nprms)
5755 void LoadNextPositionProc(w, event, prms, nprms)
5764 void LoadPrevPositionProc(w, event, prms, nprms)
5773 void ReloadPositionProc(w, event, prms, nprms)
5782 void LoadPositionProc(w, event, prms, nprms)
5788 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5791 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5794 void SaveGameProc(w, event, prms, nprms)
5800 FileNamePopUp(_("Save game file name?"),
5801 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5805 void SavePositionProc(w, event, prms, nprms)
5811 FileNamePopUp(_("Save position file name?"),
5812 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5816 void ReloadCmailMsgProc(w, event, prms, nprms)
5822 ReloadCmailMsgEvent(FALSE);
5825 void MailMoveProc(w, event, prms, nprms)
5834 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5835 char *selected_fen_position=NULL;
5838 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5839 Atom *type_return, XtPointer *value_return,
5840 unsigned long *length_return, int *format_return)
5842 char *selection_tmp;
5844 if (!selected_fen_position) return False; /* should never happen */
5845 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5846 /* note: since no XtSelectionDoneProc was registered, Xt will
5847 * automatically call XtFree on the value returned. So have to
5848 * make a copy of it allocated with XtMalloc */
5849 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5850 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
5852 *value_return=selection_tmp;
5853 *length_return=strlen(selection_tmp);
5854 *type_return=*target;
5855 *format_return = 8; /* bits per byte */
5857 } else if (*target == XA_TARGETS(xDisplay)) {
5858 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5859 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5860 targets_tmp[1] = XA_STRING;
5861 *value_return = targets_tmp;
5862 *type_return = XA_ATOM;
5864 *format_return = 8 * sizeof(Atom);
5865 if (*format_return > 32) {
5866 *length_return *= *format_return / 32;
5867 *format_return = 32;
5875 /* note: when called from menu all parameters are NULL, so no clue what the
5876 * Widget which was clicked on was, or what the click event was
5878 void CopyPositionProc(w, event, prms, nprms)
5885 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5886 * have a notion of a position that is selected but not copied.
5887 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5889 if(gameMode == EditPosition) EditPositionDone(TRUE);
5890 if (selected_fen_position) free(selected_fen_position);
5891 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5892 if (!selected_fen_position) return;
5893 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5895 SendPositionSelection,
5896 NULL/* lose_ownership_proc */ ,
5897 NULL/* transfer_done_proc */);
5898 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5900 SendPositionSelection,
5901 NULL/* lose_ownership_proc */ ,
5902 NULL/* transfer_done_proc */);
5905 /* function called when the data to Paste is ready */
5907 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5908 Atom *type, XtPointer value, unsigned long *len, int *format)
5911 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5912 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5913 EditPositionPasteFEN(fenstr);
5917 /* called when Paste Position button is pressed,
5918 * all parameters will be NULL */
5919 void PastePositionProc(w, event, prms, nprms)
5925 XtGetSelectionValue(menuBarWidget,
5926 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5927 /* (XtSelectionCallbackProc) */ PastePositionCB,
5928 NULL, /* client_data passed to PastePositionCB */
5930 /* better to use the time field from the event that triggered the
5931 * call to this function, but that isn't trivial to get
5939 SendGameSelection(Widget w, Atom *selection, Atom *target,
5940 Atom *type_return, XtPointer *value_return,
5941 unsigned long *length_return, int *format_return)
5943 char *selection_tmp;
5945 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5946 FILE* f = fopen(gameCopyFilename, "r");
5949 if (f == NULL) return False;
5953 selection_tmp = XtMalloc(len + 1);
5954 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 AutoflagProc(w, event, prms, nprms)
6571 appData.autoCallFlag = !appData.autoCallFlag;
6573 if (appData.autoCallFlag) {
6574 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6576 XtSetArg(args[0], XtNleftBitmap, None);
6578 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6582 void AutoflipProc(w, event, prms, nprms)
6590 appData.autoFlipView = !appData.autoFlipView;
6592 if (appData.autoFlipView) {
6593 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6595 XtSetArg(args[0], XtNleftBitmap, None);
6597 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6601 void BlindfoldProc(w, event, prms, nprms)
6609 appData.blindfold = !appData.blindfold;
6611 if (appData.blindfold) {
6612 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6614 XtSetArg(args[0], XtNleftBitmap, None);
6616 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6619 DrawPosition(True, NULL);
6622 void TestLegalityProc(w, event, prms, nprms)
6630 appData.testLegality = !appData.testLegality;
6632 if (appData.testLegality) {
6633 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6635 XtSetArg(args[0], XtNleftBitmap, None);
6637 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6642 void FlashMovesProc(w, event, prms, nprms)
6650 if (appData.flashCount == 0) {
6651 appData.flashCount = 3;
6653 appData.flashCount = -appData.flashCount;
6656 if (appData.flashCount > 0) {
6657 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6659 XtSetArg(args[0], XtNleftBitmap, None);
6661 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6665 void FlipViewProc(w, event, prms, nprms)
6671 flipView = !flipView;
6672 DrawPosition(True, NULL);
6676 void HighlightDraggingProc(w, event, prms, nprms)
6684 appData.highlightDragging = !appData.highlightDragging;
6686 if (appData.highlightDragging) {
6687 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6689 XtSetArg(args[0], XtNleftBitmap, None);
6691 XtSetValues(XtNameToWidget(menuBarWidget,
6692 "menuOptions.Highlight Dragging"), args, 1);
6696 void HighlightLastMoveProc(w, event, prms, nprms)
6704 appData.highlightLastMove = !appData.highlightLastMove;
6706 if (appData.highlightLastMove) {
6707 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6709 XtSetArg(args[0], XtNleftBitmap, None);
6711 XtSetValues(XtNameToWidget(menuBarWidget,
6712 "menuOptions.Highlight Last Move"), args, 1);
6715 void HighlightArrowProc(w, event, prms, nprms)
6723 appData.highlightMoveWithArrow = !appData.highlightMoveWithArrow;
6725 if (appData.highlightMoveWithArrow) {
6726 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6728 XtSetArg(args[0], XtNleftBitmap, None);
6730 XtSetValues(XtNameToWidget(menuBarWidget,
6731 "menuOptions.Arrow"), args, 1);
6735 void IcsAlarmProc(w, event, prms, nprms)
6743 appData.icsAlarm = !appData.icsAlarm;
6745 if (appData.icsAlarm) {
6746 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6748 XtSetArg(args[0], XtNleftBitmap, None);
6750 XtSetValues(XtNameToWidget(menuBarWidget,
6751 "menuOptions.ICS Alarm"), args, 1);
6755 void MoveSoundProc(w, event, prms, nprms)
6763 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6765 if (appData.ringBellAfterMoves) {
6766 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6768 XtSetArg(args[0], XtNleftBitmap, None);
6770 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6774 void OneClickProc(w, event, prms, nprms)
6782 appData.oneClick = !appData.oneClick;
6784 if (appData.oneClick) {
6785 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6787 XtSetArg(args[0], XtNleftBitmap, None);
6789 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.OneClick"),
6793 void PeriodicUpdatesProc(w, event, prms, nprms)
6801 PeriodicUpdatesEvent(!appData.periodicUpdates);
6803 if (appData.periodicUpdates) {
6804 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6806 XtSetArg(args[0], XtNleftBitmap, None);
6808 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6812 void PonderNextMoveProc(w, event, prms, nprms)
6820 PonderNextMoveEvent(!appData.ponderNextMove);
6822 if (appData.ponderNextMove) {
6823 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6825 XtSetArg(args[0], XtNleftBitmap, None);
6827 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6831 void PopupExitMessageProc(w, event, prms, nprms)
6839 appData.popupExitMessage = !appData.popupExitMessage;
6841 if (appData.popupExitMessage) {
6842 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6844 XtSetArg(args[0], XtNleftBitmap, None);
6846 XtSetValues(XtNameToWidget(menuBarWidget,
6847 "menuOptions.Popup Exit Message"), args, 1);
6850 void PopupMoveErrorsProc(w, event, prms, nprms)
6858 appData.popupMoveErrors = !appData.popupMoveErrors;
6860 if (appData.popupMoveErrors) {
6861 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6863 XtSetArg(args[0], XtNleftBitmap, None);
6865 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6870 void PremoveProc(w, event, prms, nprms)
6878 appData.premove = !appData.premove;
6880 if (appData.premove) {
6881 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6883 XtSetArg(args[0], XtNleftBitmap, None);
6885 XtSetValues(XtNameToWidget(menuBarWidget,
6886 "menuOptions.Premove"), args, 1);
6890 void ShowCoordsProc(w, event, prms, nprms)
6898 appData.showCoords = !appData.showCoords;
6900 if (appData.showCoords) {
6901 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6903 XtSetArg(args[0], XtNleftBitmap, None);
6905 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6908 DrawPosition(True, NULL);
6911 void ShowThinkingProc(w, event, prms, nprms)
6917 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6918 ShowThinkingEvent();
6921 void HideThinkingProc(w, event, prms, nprms)
6929 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6930 ShowThinkingEvent();
6932 if (appData.hideThinkingFromHuman) {
6933 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6935 XtSetArg(args[0], XtNleftBitmap, None);
6937 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6941 void SaveOnExitProc(w, event, prms, nprms)
6949 saveSettingsOnExit = !saveSettingsOnExit;
6951 if (saveSettingsOnExit) {
6952 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6954 XtSetArg(args[0], XtNleftBitmap, None);
6956 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6960 void SaveSettingsProc(w, event, prms, nprms)
6966 SaveSettings(settingsFileName);
6969 void InfoProc(w, event, prms, nprms)
6976 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6981 void ManProc(w, event, prms, nprms)
6989 if (nprms && *nprms > 0)
6993 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6997 void HintProc(w, event, prms, nprms)
7006 void BookProc(w, event, prms, nprms)
7015 void AboutProc(w, event, prms, nprms)
7023 char *zippy = " (with Zippy code)";
7027 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
7028 programVersion, zippy,
7029 "Copyright 1991 Digital Equipment Corporation",
7030 "Enhancements Copyright 1992-2009 Free Software Foundation",
7031 "Enhancements Copyright 2005 Alessandro Scotti",
7032 PACKAGE, " is free software and carries NO WARRANTY;",
7033 "see the file COPYING for more information.");
7034 ErrorPopUp(_("About XBoard"), buf, FALSE);
7037 void DebugProc(w, event, prms, nprms)
7043 appData.debugMode = !appData.debugMode;
7046 void AboutGameProc(w, event, prms, nprms)
7055 void NothingProc(w, event, prms, nprms)
7064 void Iconify(w, event, prms, nprms)
7073 XtSetArg(args[0], XtNiconic, True);
7074 XtSetValues(shellWidget, args, 1);
7077 void DisplayMessage(message, extMessage)
7078 char *message, *extMessage;
7080 /* display a message in the message widget */
7089 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
7094 message = extMessage;
7098 /* need to test if messageWidget already exists, since this function
7099 can also be called during the startup, if for example a Xresource
7100 is not set up correctly */
7103 XtSetArg(arg, XtNlabel, message);
7104 XtSetValues(messageWidget, &arg, 1);
7110 void DisplayTitle(text)
7115 char title[MSG_SIZ];
7118 if (text == NULL) text = "";
7120 if (appData.titleInWindow) {
7122 XtSetArg(args[i], XtNlabel, text); i++;
7123 XtSetValues(titleWidget, args, i);
7126 if (*text != NULLCHAR) {
7127 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
7128 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
7129 } else if (appData.icsActive) {
7130 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7131 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7132 } else if (appData.cmailGameName[0] != NULLCHAR) {
7133 snprintf(icon, sizeof(icon), "%s", "CMail");
7134 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7136 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7137 } else if (gameInfo.variant == VariantGothic) {
7138 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7139 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
7142 } else if (gameInfo.variant == VariantFalcon) {
7143 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7144 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
7146 } else if (appData.noChessProgram) {
7147 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7148 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
7150 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
7151 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7154 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7155 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7156 XtSetValues(shellWidget, args, i);
7161 DisplayError(message, error)
7168 if (appData.debugMode || appData.matchMode) {
7169 fprintf(stderr, "%s: %s\n", programName, message);
7172 if (appData.debugMode || appData.matchMode) {
7173 fprintf(stderr, "%s: %s: %s\n",
7174 programName, message, strerror(error));
7176 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7179 ErrorPopUp(_("Error"), message, FALSE);
7183 void DisplayMoveError(message)
7188 DrawPosition(FALSE, NULL);
7189 if (appData.debugMode || appData.matchMode) {
7190 fprintf(stderr, "%s: %s\n", programName, message);
7192 if (appData.popupMoveErrors) {
7193 ErrorPopUp(_("Error"), message, FALSE);
7195 DisplayMessage(message, "");
7200 void DisplayFatalError(message, error, status)
7206 errorExitStatus = status;
7208 fprintf(stderr, "%s: %s\n", programName, message);
7210 fprintf(stderr, "%s: %s: %s\n",
7211 programName, message, strerror(error));
7212 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7215 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7216 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7222 void DisplayInformation(message)
7226 ErrorPopUp(_("Information"), message, TRUE);
7229 void DisplayNote(message)
7233 ErrorPopUp(_("Note"), message, FALSE);
7237 NullXErrorCheck(dpy, error_event)
7239 XErrorEvent *error_event;
7244 void DisplayIcsInteractionTitle(message)
7247 if (oldICSInteractionTitle == NULL) {
7248 /* Magic to find the old window title, adapted from vim */
7249 char *wina = getenv("WINDOWID");
7251 Window win = (Window) atoi(wina);
7252 Window root, parent, *children;
7253 unsigned int nchildren;
7254 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7256 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7257 if (!XQueryTree(xDisplay, win, &root, &parent,
7258 &children, &nchildren)) break;
7259 if (children) XFree((void *)children);
7260 if (parent == root || parent == 0) break;
7263 XSetErrorHandler(oldHandler);
7265 if (oldICSInteractionTitle == NULL) {
7266 oldICSInteractionTitle = "xterm";
7269 printf("\033]0;%s\007", message);
7273 char pendingReplyPrefix[MSG_SIZ];
7274 ProcRef pendingReplyPR;
7276 void AskQuestionProc(w, event, prms, nprms)
7283 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7287 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7290 void AskQuestionPopDown()
7292 if (!askQuestionUp) return;
7293 XtPopdown(askQuestionShell);
7294 XtDestroyWidget(askQuestionShell);
7295 askQuestionUp = False;
7298 void AskQuestionReplyAction(w, event, prms, nprms)
7308 reply = XawDialogGetValueString(w = XtParent(w));
7309 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
7310 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
7311 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
7312 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
7313 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7314 AskQuestionPopDown();
7316 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7319 void AskQuestionCallback(w, client_data, call_data)
7321 XtPointer client_data, call_data;
7326 XtSetArg(args[0], XtNlabel, &name);
7327 XtGetValues(w, args, 1);
7329 if (strcmp(name, _("cancel")) == 0) {
7330 AskQuestionPopDown();
7332 AskQuestionReplyAction(w, NULL, NULL, NULL);
7336 void AskQuestion(title, question, replyPrefix, pr)
7337 char *title, *question, *replyPrefix;
7341 Widget popup, layout, dialog, edit;
7347 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
7348 pendingReplyPR = pr;
7351 XtSetArg(args[i], XtNresizable, True); i++;
7352 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7353 askQuestionShell = popup =
7354 XtCreatePopupShell(title, transientShellWidgetClass,
7355 shellWidget, args, i);
7358 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7359 layoutArgs, XtNumber(layoutArgs));
7362 XtSetArg(args[i], XtNlabel, question); i++;
7363 XtSetArg(args[i], XtNvalue, ""); i++;
7364 XtSetArg(args[i], XtNborderWidth, 0); i++;
7365 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7368 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7369 (XtPointer) dialog);
7370 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7371 (XtPointer) dialog);
7373 XtRealizeWidget(popup);
7374 CatchDeleteWindow(popup, "AskQuestionPopDown");
7376 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7377 &x, &y, &win_x, &win_y, &mask);
7379 XtSetArg(args[0], XtNx, x - 10);
7380 XtSetArg(args[1], XtNy, y - 30);
7381 XtSetValues(popup, args, 2);
7383 XtPopup(popup, XtGrabExclusive);
7384 askQuestionUp = True;
7386 edit = XtNameToWidget(dialog, "*value");
7387 XtSetKeyboardFocus(popup, edit);
7395 if (*name == NULLCHAR) {
7397 } else if (strcmp(name, "$") == 0) {
7398 putc(BELLCHAR, stderr);
7401 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7409 PlaySound(appData.soundMove);
7415 PlaySound(appData.soundIcsWin);
7421 PlaySound(appData.soundIcsLoss);
7427 PlaySound(appData.soundIcsDraw);
7431 PlayIcsUnfinishedSound()
7433 PlaySound(appData.soundIcsUnfinished);
7439 PlaySound(appData.soundIcsAlarm);
7445 system("stty echo");
7451 system("stty -echo");
7455 Colorize(cc, continuation)
7460 int count, outCount, error;
7462 if (textColors[(int)cc].bg > 0) {
7463 if (textColors[(int)cc].fg > 0) {
7464 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7465 textColors[(int)cc].fg, textColors[(int)cc].bg);
7467 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7468 textColors[(int)cc].bg);
7471 if (textColors[(int)cc].fg > 0) {
7472 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7473 textColors[(int)cc].fg);
7475 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7478 count = strlen(buf);
7479 outCount = OutputToProcess(NoProc, buf, count, &error);
7480 if (outCount < count) {
7481 DisplayFatalError(_("Error writing to display"), error, 1);
7484 if (continuation) return;
7487 PlaySound(appData.soundShout);
7490 PlaySound(appData.soundSShout);
7493 PlaySound(appData.soundChannel1);
7496 PlaySound(appData.soundChannel);
7499 PlaySound(appData.soundKibitz);
7502 PlaySound(appData.soundTell);
7504 case ColorChallenge:
7505 PlaySound(appData.soundChallenge);
7508 PlaySound(appData.soundRequest);
7511 PlaySound(appData.soundSeek);
7522 return getpwuid(getuid())->pw_name;
7526 ExpandPathName(path)
7529 static char static_buf[4*MSG_SIZ];
7530 char *d, *s, buf[4*MSG_SIZ];
7536 while (*s && isspace(*s))
7545 if (*(s+1) == '/') {
7546 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7550 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7551 { char *p; if(p = strchr(buf, '/')) *p = 0; }
7552 pwd = getpwnam(buf);
7555 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7559 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7560 strcat(d, strchr(s+1, '/'));
7564 safeStrCpy(d, s, 4*MSG_SIZ );
7571 static char host_name[MSG_SIZ];
7573 #if HAVE_GETHOSTNAME
7574 gethostname(host_name, MSG_SIZ);
7576 #else /* not HAVE_GETHOSTNAME */
7577 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7578 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7580 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7582 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7583 #endif /* not HAVE_GETHOSTNAME */
7586 XtIntervalId delayedEventTimerXID = 0;
7587 DelayedEventCallback delayedEventCallback = 0;
7592 delayedEventTimerXID = 0;
7593 delayedEventCallback();
7597 ScheduleDelayedEvent(cb, millisec)
7598 DelayedEventCallback cb; long millisec;
7600 if(delayedEventTimerXID && delayedEventCallback == cb)
7601 // [HGM] alive: replace, rather than add or flush identical event
7602 XtRemoveTimeOut(delayedEventTimerXID);
7603 delayedEventCallback = cb;
7604 delayedEventTimerXID =
7605 XtAppAddTimeOut(appContext, millisec,
7606 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7609 DelayedEventCallback
7612 if (delayedEventTimerXID) {
7613 return delayedEventCallback;
7620 CancelDelayedEvent()
7622 if (delayedEventTimerXID) {
7623 XtRemoveTimeOut(delayedEventTimerXID);
7624 delayedEventTimerXID = 0;
7628 XtIntervalId loadGameTimerXID = 0;
7630 int LoadGameTimerRunning()
7632 return loadGameTimerXID != 0;
7635 int StopLoadGameTimer()
7637 if (loadGameTimerXID != 0) {
7638 XtRemoveTimeOut(loadGameTimerXID);
7639 loadGameTimerXID = 0;
7647 LoadGameTimerCallback(arg, id)
7651 loadGameTimerXID = 0;
7656 StartLoadGameTimer(millisec)
7660 XtAppAddTimeOut(appContext, millisec,
7661 (XtTimerCallbackProc) LoadGameTimerCallback,
7665 XtIntervalId analysisClockXID = 0;
7668 AnalysisClockCallback(arg, id)
7672 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7673 || appData.icsEngineAnalyze) { // [DM]
7674 AnalysisPeriodicEvent(0);
7675 StartAnalysisClock();
7680 StartAnalysisClock()
7683 XtAppAddTimeOut(appContext, 2000,
7684 (XtTimerCallbackProc) AnalysisClockCallback,
7688 XtIntervalId clockTimerXID = 0;
7690 int ClockTimerRunning()
7692 return clockTimerXID != 0;
7695 int StopClockTimer()
7697 if (clockTimerXID != 0) {
7698 XtRemoveTimeOut(clockTimerXID);
7707 ClockTimerCallback(arg, id)
7716 StartClockTimer(millisec)
7720 XtAppAddTimeOut(appContext, millisec,
7721 (XtTimerCallbackProc) ClockTimerCallback,
7726 DisplayTimerLabel(w, color, timer, highlight)
7735 /* check for low time warning */
7736 Pixel foregroundOrWarningColor = timerForegroundPixel;
7739 appData.lowTimeWarning &&
7740 (timer / 1000) < appData.icsAlarmTime)
7741 foregroundOrWarningColor = lowTimeWarningColor;
7743 if (appData.clockMode) {
7744 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7745 XtSetArg(args[0], XtNlabel, buf);
7747 snprintf(buf, MSG_SIZ, "%s ", color);
7748 XtSetArg(args[0], XtNlabel, buf);
7753 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7754 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7756 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7757 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7760 XtSetValues(w, args, 3);
7764 DisplayWhiteClock(timeRemaining, highlight)
7770 if(appData.noGUI) return;
7771 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7772 if (highlight && iconPixmap == bIconPixmap) {
7773 iconPixmap = wIconPixmap;
7774 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7775 XtSetValues(shellWidget, args, 1);
7780 DisplayBlackClock(timeRemaining, highlight)
7786 if(appData.noGUI) return;
7787 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7788 if (highlight && iconPixmap == wIconPixmap) {
7789 iconPixmap = bIconPixmap;
7790 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7791 XtSetValues(shellWidget, args, 1);
7809 int StartChildProcess(cmdLine, dir, pr)
7816 int to_prog[2], from_prog[2];
7820 if (appData.debugMode) {
7821 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7824 /* We do NOT feed the cmdLine to the shell; we just
7825 parse it into blank-separated arguments in the
7826 most simple-minded way possible.
7829 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7832 while(*p == ' ') p++;
7834 if(*p == '"' || *p == '\'')
7835 p = strchr(++argv[i-1], *p);
7836 else p = strchr(p, ' ');
7837 if (p == NULL) break;
7842 SetUpChildIO(to_prog, from_prog);
7844 if ((pid = fork()) == 0) {
7846 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7847 close(to_prog[1]); // first close the unused pipe ends
7848 close(from_prog[0]);
7849 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7850 dup2(from_prog[1], 1);
7851 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7852 close(from_prog[1]); // and closing again loses one of the pipes!
7853 if(fileno(stderr) >= 2) // better safe than sorry...
7854 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7856 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7861 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7863 execvp(argv[0], argv);
7865 /* If we get here, exec failed */
7870 /* Parent process */
7872 close(from_prog[1]);
7874 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7877 cp->fdFrom = from_prog[0];
7878 cp->fdTo = to_prog[1];
7883 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7884 static RETSIGTYPE AlarmCallBack(int n)
7890 DestroyChildProcess(pr, signalType)
7894 ChildProc *cp = (ChildProc *) pr;
7896 if (cp->kind != CPReal) return;
7898 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7899 signal(SIGALRM, AlarmCallBack);
7901 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7902 kill(cp->pid, SIGKILL); // kill it forcefully
7903 wait((int *) 0); // and wait again
7907 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7909 /* Process is exiting either because of the kill or because of
7910 a quit command sent by the backend; either way, wait for it to die.
7919 InterruptChildProcess(pr)
7922 ChildProc *cp = (ChildProc *) pr;
7924 if (cp->kind != CPReal) return;
7925 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7928 int OpenTelnet(host, port, pr)
7933 char cmdLine[MSG_SIZ];
7935 if (port[0] == NULLCHAR) {
7936 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7938 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7940 return StartChildProcess(cmdLine, "", pr);
7943 int OpenTCP(host, port, pr)
7949 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7950 #else /* !OMIT_SOCKETS */
7952 struct sockaddr_in sa;
7954 unsigned short uport;
7957 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7961 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7962 sa.sin_family = AF_INET;
7963 sa.sin_addr.s_addr = INADDR_ANY;
7964 uport = (unsigned short) 0;
7965 sa.sin_port = htons(uport);
7966 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7970 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7971 if (!(hp = gethostbyname(host))) {
7973 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7974 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7975 hp->h_addrtype = AF_INET;
7977 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7978 hp->h_addr_list[0] = (char *) malloc(4);
7979 hp->h_addr_list[0][0] = b0;
7980 hp->h_addr_list[0][1] = b1;
7981 hp->h_addr_list[0][2] = b2;
7982 hp->h_addr_list[0][3] = b3;
7987 sa.sin_family = hp->h_addrtype;
7988 uport = (unsigned short) atoi(port);
7989 sa.sin_port = htons(uport);
7990 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7992 if (connect(s, (struct sockaddr *) &sa,
7993 sizeof(struct sockaddr_in)) < 0) {
7997 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8004 #endif /* !OMIT_SOCKETS */
8009 int OpenCommPort(name, pr)
8016 fd = open(name, 2, 0);
8017 if (fd < 0) return errno;
8019 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8029 int OpenLoopback(pr)
8035 SetUpChildIO(to, from);
8037 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8040 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
8047 int OpenRcmd(host, user, cmd, pr)
8048 char *host, *user, *cmd;
8051 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
8055 #define INPUT_SOURCE_BUF_SIZE 8192
8064 char buf[INPUT_SOURCE_BUF_SIZE];
8069 DoInputCallback(closure, source, xid)
8074 InputSource *is = (InputSource *) closure;
8079 if (is->lineByLine) {
8080 count = read(is->fd, is->unused,
8081 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
8083 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
8086 is->unused += count;
8088 while (p < is->unused) {
8089 q = memchr(p, '\n', is->unused - p);
8090 if (q == NULL) break;
8092 (is->func)(is, is->closure, p, q - p, 0);
8096 while (p < is->unused) {
8101 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8106 (is->func)(is, is->closure, is->buf, count, error);
8110 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8117 ChildProc *cp = (ChildProc *) pr;
8119 is = (InputSource *) calloc(1, sizeof(InputSource));
8120 is->lineByLine = lineByLine;
8124 is->fd = fileno(stdin);
8126 is->kind = cp->kind;
8127 is->fd = cp->fdFrom;
8130 is->unused = is->buf;
8133 is->xid = XtAppAddInput(appContext, is->fd,
8134 (XtPointer) (XtInputReadMask),
8135 (XtInputCallbackProc) DoInputCallback,
8137 is->closure = closure;
8138 return (InputSourceRef) is;
8142 RemoveInputSource(isr)
8145 InputSource *is = (InputSource *) isr;
8147 if (is->xid == 0) return;
8148 XtRemoveInput(is->xid);
8152 int OutputToProcess(pr, message, count, outError)
8158 static int line = 0;
8159 ChildProc *cp = (ChildProc *) pr;
8164 if (appData.noJoin || !appData.useInternalWrap)
8165 outCount = fwrite(message, 1, count, stdout);
8168 int width = get_term_width();
8169 int len = wrap(NULL, message, count, width, &line);
8170 char *msg = malloc(len);
8174 outCount = fwrite(message, 1, count, stdout);
8177 dbgchk = wrap(msg, message, count, width, &line);
8178 if (dbgchk != len && appData.debugMode)
8179 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8180 outCount = fwrite(msg, 1, dbgchk, stdout);
8186 outCount = write(cp->fdTo, message, count);
8196 /* Output message to process, with "ms" milliseconds of delay
8197 between each character. This is needed when sending the logon
8198 script to ICC, which for some reason doesn't like the
8199 instantaneous send. */
8200 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8207 ChildProc *cp = (ChildProc *) pr;
8212 r = write(cp->fdTo, message++, 1);
8225 /**** Animation code by Hugh Fisher, DCS, ANU.
8227 Known problem: if a window overlapping the board is
8228 moved away while a piece is being animated underneath,
8229 the newly exposed area won't be updated properly.
8230 I can live with this.
8232 Known problem: if you look carefully at the animation
8233 of pieces in mono mode, they are being drawn as solid
8234 shapes without interior detail while moving. Fixing
8235 this would be a major complication for minimal return.
8238 /* Masks for XPM pieces. Black and white pieces can have
8239 different shapes, but in the interest of retaining my
8240 sanity pieces must have the same outline on both light
8241 and dark squares, and all pieces must use the same
8242 background square colors/images. */
8244 static int xpmDone = 0;
8247 CreateAnimMasks (pieceDepth)
8254 unsigned long plane;
8257 /* Need a bitmap just to get a GC with right depth */
8258 buf = XCreatePixmap(xDisplay, xBoardWindow,
8260 values.foreground = 1;
8261 values.background = 0;
8262 /* Don't use XtGetGC, not read only */
8263 maskGC = XCreateGC(xDisplay, buf,
8264 GCForeground | GCBackground, &values);
8265 XFreePixmap(xDisplay, buf);
8267 buf = XCreatePixmap(xDisplay, xBoardWindow,
8268 squareSize, squareSize, pieceDepth);
8269 values.foreground = XBlackPixel(xDisplay, xScreen);
8270 values.background = XWhitePixel(xDisplay, xScreen);
8271 bufGC = XCreateGC(xDisplay, buf,
8272 GCForeground | GCBackground, &values);
8274 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8275 /* Begin with empty mask */
8276 if(!xpmDone) // [HGM] pieces: keep using existing
8277 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8278 squareSize, squareSize, 1);
8279 XSetFunction(xDisplay, maskGC, GXclear);
8280 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8281 0, 0, squareSize, squareSize);
8283 /* Take a copy of the piece */
8288 XSetFunction(xDisplay, bufGC, GXcopy);
8289 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8291 0, 0, squareSize, squareSize, 0, 0);
8293 /* XOR the background (light) over the piece */
8294 XSetFunction(xDisplay, bufGC, GXxor);
8296 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8297 0, 0, squareSize, squareSize, 0, 0);
8299 XSetForeground(xDisplay, bufGC, lightSquareColor);
8300 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8303 /* We now have an inverted piece image with the background
8304 erased. Construct mask by just selecting all the non-zero
8305 pixels - no need to reconstruct the original image. */
8306 XSetFunction(xDisplay, maskGC, GXor);
8308 /* Might be quicker to download an XImage and create bitmap
8309 data from it rather than this N copies per piece, but it
8310 only takes a fraction of a second and there is a much
8311 longer delay for loading the pieces. */
8312 for (n = 0; n < pieceDepth; n ++) {
8313 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8314 0, 0, squareSize, squareSize,
8320 XFreePixmap(xDisplay, buf);
8321 XFreeGC(xDisplay, bufGC);
8322 XFreeGC(xDisplay, maskGC);
8326 InitAnimState (anim, info)
8328 XWindowAttributes * info;
8333 /* Each buffer is square size, same depth as window */
8334 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8335 squareSize, squareSize, info->depth);
8336 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8337 squareSize, squareSize, info->depth);
8339 /* Create a plain GC for blitting */
8340 mask = GCForeground | GCBackground | GCFunction |
8341 GCPlaneMask | GCGraphicsExposures;
8342 values.foreground = XBlackPixel(xDisplay, xScreen);
8343 values.background = XWhitePixel(xDisplay, xScreen);
8344 values.function = GXcopy;
8345 values.plane_mask = AllPlanes;
8346 values.graphics_exposures = False;
8347 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8349 /* Piece will be copied from an existing context at
8350 the start of each new animation/drag. */
8351 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8353 /* Outline will be a read-only copy of an existing */
8354 anim->outlineGC = None;
8360 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8361 XWindowAttributes info;
8363 if (xpmDone && gameInfo.variant == old) return;
8364 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8365 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8367 InitAnimState(&game, &info);
8368 InitAnimState(&player, &info);
8370 /* For XPM pieces, we need bitmaps to use as masks. */
8372 CreateAnimMasks(info.depth);
8378 static Boolean frameWaiting;
8380 static RETSIGTYPE FrameAlarm (sig)
8383 frameWaiting = False;
8384 /* In case System-V style signals. Needed?? */
8385 signal(SIGALRM, FrameAlarm);
8392 struct itimerval delay;
8394 XSync(xDisplay, False);
8397 frameWaiting = True;
8398 signal(SIGALRM, FrameAlarm);
8399 delay.it_interval.tv_sec =
8400 delay.it_value.tv_sec = time / 1000;
8401 delay.it_interval.tv_usec =
8402 delay.it_value.tv_usec = (time % 1000) * 1000;
8403 setitimer(ITIMER_REAL, &delay, NULL);
8404 while (frameWaiting) pause();
8405 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8406 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8407 setitimer(ITIMER_REAL, &delay, NULL);
8417 XSync(xDisplay, False);
8419 usleep(time * 1000);
8424 /* Convert board position to corner of screen rect and color */
8427 ScreenSquare(column, row, pt, color)
8428 int column; int row; XPoint * pt; int * color;
8431 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8432 pt->y = lineGap + row * (squareSize + lineGap);
8434 pt->x = lineGap + column * (squareSize + lineGap);
8435 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8437 *color = SquareColor(row, column);
8440 /* Convert window coords to square */
8443 BoardSquare(x, y, column, row)
8444 int x; int y; int * column; int * row;
8446 *column = EventToSquare(x, BOARD_WIDTH);
8447 if (flipView && *column >= 0)
8448 *column = BOARD_WIDTH - 1 - *column;
8449 *row = EventToSquare(y, BOARD_HEIGHT);
8450 if (!flipView && *row >= 0)
8451 *row = BOARD_HEIGHT - 1 - *row;
8456 #undef Max /* just in case */
8458 #define Max(a, b) ((a) > (b) ? (a) : (b))
8459 #define Min(a, b) ((a) < (b) ? (a) : (b))
8462 SetRect(rect, x, y, width, height)
8463 XRectangle * rect; int x; int y; int width; int height;
8467 rect->width = width;
8468 rect->height = height;
8471 /* Test if two frames overlap. If they do, return
8472 intersection rect within old and location of
8473 that rect within new. */
8476 Intersect(old, new, size, area, pt)
8477 XPoint * old; XPoint * new;
8478 int size; XRectangle * area; XPoint * pt;
8480 if (old->x > new->x + size || new->x > old->x + size ||
8481 old->y > new->y + size || new->y > old->y + size) {
8484 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8485 size - abs(old->x - new->x), size - abs(old->y - new->y));
8486 pt->x = Max(old->x - new->x, 0);
8487 pt->y = Max(old->y - new->y, 0);
8492 /* For two overlapping frames, return the rect(s)
8493 in the old that do not intersect with the new. */
8496 CalcUpdateRects(old, new, size, update, nUpdates)
8497 XPoint * old; XPoint * new; int size;
8498 XRectangle update[]; int * nUpdates;
8502 /* If old = new (shouldn't happen) then nothing to draw */
8503 if (old->x == new->x && old->y == new->y) {
8507 /* Work out what bits overlap. Since we know the rects
8508 are the same size we don't need a full intersect calc. */
8510 /* Top or bottom edge? */
8511 if (new->y > old->y) {
8512 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8514 } else if (old->y > new->y) {
8515 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8516 size, old->y - new->y);
8519 /* Left or right edge - don't overlap any update calculated above. */
8520 if (new->x > old->x) {
8521 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8522 new->x - old->x, size - abs(new->y - old->y));
8524 } else if (old->x > new->x) {
8525 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8526 old->x - new->x, size - abs(new->y - old->y));
8533 /* Generate a series of frame coords from start->mid->finish.
8534 The movement rate doubles until the half way point is
8535 reached, then halves back down to the final destination,
8536 which gives a nice slow in/out effect. The algorithmn
8537 may seem to generate too many intermediates for short
8538 moves, but remember that the purpose is to attract the
8539 viewers attention to the piece about to be moved and
8540 then to where it ends up. Too few frames would be less
8544 Tween(start, mid, finish, factor, frames, nFrames)
8545 XPoint * start; XPoint * mid;
8546 XPoint * finish; int factor;
8547 XPoint frames[]; int * nFrames;
8549 int fraction, n, count;
8553 /* Slow in, stepping 1/16th, then 1/8th, ... */
8555 for (n = 0; n < factor; n++)
8557 for (n = 0; n < factor; n++) {
8558 frames[count].x = start->x + (mid->x - start->x) / fraction;
8559 frames[count].y = start->y + (mid->y - start->y) / fraction;
8561 fraction = fraction / 2;
8565 frames[count] = *mid;
8568 /* Slow out, stepping 1/2, then 1/4, ... */
8570 for (n = 0; n < factor; n++) {
8571 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8572 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8574 fraction = fraction * 2;
8579 /* Draw a piece on the screen without disturbing what's there */
8582 SelectGCMask(piece, clip, outline, mask)
8583 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8587 /* Bitmap for piece being moved. */
8588 if (appData.monoMode) {
8589 *mask = *pieceToSolid(piece);
8590 } else if (useImages) {
8592 *mask = xpmMask[piece];
8594 *mask = ximMaskPm[piece];
8597 *mask = *pieceToSolid(piece);
8600 /* GC for piece being moved. Square color doesn't matter, but
8601 since it gets modified we make a copy of the original. */
8603 if (appData.monoMode)
8608 if (appData.monoMode)
8613 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8615 /* Outline only used in mono mode and is not modified */
8617 *outline = bwPieceGC;
8619 *outline = wbPieceGC;
8623 OverlayPiece(piece, clip, outline, dest)
8624 ChessSquare piece; GC clip; GC outline; Drawable dest;
8629 /* Draw solid rectangle which will be clipped to shape of piece */
8630 XFillRectangle(xDisplay, dest, clip,
8631 0, 0, squareSize, squareSize);
8632 if (appData.monoMode)
8633 /* Also draw outline in contrasting color for black
8634 on black / white on white cases */
8635 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8636 0, 0, squareSize, squareSize, 0, 0, 1);
8638 /* Copy the piece */
8643 if(appData.upsideDown && flipView) kind ^= 2;
8644 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8646 0, 0, squareSize, squareSize,
8651 /* Animate the movement of a single piece */
8654 BeginAnimation(anim, piece, startColor, start)
8662 if(appData.upsideDown && flipView) piece += piece < BlackPawn ? BlackPawn : -BlackPawn;
8663 /* The old buffer is initialised with the start square (empty) */
8664 BlankSquare(start->x, start->y, startColor, EmptySquare, anim->saveBuf, 0);
8665 anim->prevFrame = *start;
8667 /* The piece will be drawn using its own bitmap as a matte */
8668 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8669 XSetClipMask(xDisplay, anim->pieceGC, mask);
8673 AnimationFrame(anim, frame, piece)
8678 XRectangle updates[4];
8683 /* Save what we are about to draw into the new buffer */
8684 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8685 frame->x, frame->y, squareSize, squareSize,
8688 /* Erase bits of the previous frame */
8689 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8690 /* Where the new frame overlapped the previous,
8691 the contents in newBuf are wrong. */
8692 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8693 overlap.x, overlap.y,
8694 overlap.width, overlap.height,
8696 /* Repaint the areas in the old that don't overlap new */
8697 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8698 for (i = 0; i < count; i++)
8699 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8700 updates[i].x - anim->prevFrame.x,
8701 updates[i].y - anim->prevFrame.y,
8702 updates[i].width, updates[i].height,
8703 updates[i].x, updates[i].y);
8705 /* Easy when no overlap */
8706 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8707 0, 0, squareSize, squareSize,
8708 anim->prevFrame.x, anim->prevFrame.y);
8711 /* Save this frame for next time round */
8712 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8713 0, 0, squareSize, squareSize,
8715 anim->prevFrame = *frame;
8717 /* Draw piece over original screen contents, not current,
8718 and copy entire rect. Wipes out overlapping piece images. */
8719 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8720 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8721 0, 0, squareSize, squareSize,
8722 frame->x, frame->y);
8726 EndAnimation (anim, finish)
8730 XRectangle updates[4];
8735 /* The main code will redraw the final square, so we
8736 only need to erase the bits that don't overlap. */
8737 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8738 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8739 for (i = 0; i < count; i++)
8740 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8741 updates[i].x - anim->prevFrame.x,
8742 updates[i].y - anim->prevFrame.y,
8743 updates[i].width, updates[i].height,
8744 updates[i].x, updates[i].y);
8746 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8747 0, 0, squareSize, squareSize,
8748 anim->prevFrame.x, anim->prevFrame.y);
8753 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8755 ChessSquare piece; int startColor;
8756 XPoint * start; XPoint * finish;
8757 XPoint frames[]; int nFrames;
8761 BeginAnimation(anim, piece, startColor, start);
8762 for (n = 0; n < nFrames; n++) {
8763 AnimationFrame(anim, &(frames[n]), piece);
8764 FrameDelay(appData.animSpeed);
8766 EndAnimation(anim, finish);
8770 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
8773 ChessSquare piece = board[fromY][toY];
8774 board[fromY][toY] = EmptySquare;
8775 DrawPosition(FALSE, board);
8777 x = lineGap + ((BOARD_WIDTH-1)-toX) * (squareSize + lineGap);
8778 y = lineGap + toY * (squareSize + lineGap);
8780 x = lineGap + toX * (squareSize + lineGap);
8781 y = lineGap + ((BOARD_HEIGHT-1)-toY) * (squareSize + lineGap);
8783 for(i=1; i<4*kFactor; i++) {
8784 int r = squareSize * 9 * i/(20*kFactor - 5);
8785 XFillArc(xDisplay, xBoardWindow, highlineGC,
8786 x + squareSize/2 - r, y+squareSize/2 - r, 2*r, 2*r, 0, 64*360);
8787 FrameDelay(appData.animSpeed);
8789 board[fromY][toY] = piece;
8792 /* Main control logic for deciding what to animate and how */
8795 AnimateMove(board, fromX, fromY, toX, toY)
8804 XPoint start, finish, mid;
8805 XPoint frames[kFactor * 2 + 1];
8806 int nFrames, startColor, endColor;
8808 /* Are we animating? */
8809 if (!appData.animate || appData.blindfold)
8812 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8813 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8814 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8816 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8817 piece = board[fromY][fromX];
8818 if (piece >= EmptySquare) return;
8823 hop = abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1;
8826 if (appData.debugMode) {
8827 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8828 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8829 piece, fromX, fromY, toX, toY); }
8831 ScreenSquare(fromX, fromY, &start, &startColor);
8832 ScreenSquare(toX, toY, &finish, &endColor);
8835 /* Knight: make straight movement then diagonal */
8836 if (abs(toY - fromY) < abs(toX - fromX)) {
8837 mid.x = start.x + (finish.x - start.x) / 2;
8841 mid.y = start.y + (finish.y - start.y) / 2;
8844 mid.x = start.x + (finish.x - start.x) / 2;
8845 mid.y = start.y + (finish.y - start.y) / 2;
8848 /* Don't use as many frames for very short moves */
8849 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8850 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8852 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8853 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8854 if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged
8856 for(i=0; i<BOARD_WIDTH; i++) for(j=0; j<BOARD_HEIGHT; j++)
8857 if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] = True;
8860 /* Be sure end square is redrawn */
8861 damage[0][toY][toX] = True;
8865 DragPieceBegin(x, y)
8868 int boardX, boardY, color;
8871 /* Are we animating? */
8872 if (!appData.animateDragging || appData.blindfold)
8875 /* Figure out which square we start in and the
8876 mouse position relative to top left corner. */
8877 BoardSquare(x, y, &boardX, &boardY);
8878 player.startBoardX = boardX;
8879 player.startBoardY = boardY;
8880 ScreenSquare(boardX, boardY, &corner, &color);
8881 player.startSquare = corner;
8882 player.startColor = color;
8883 /* As soon as we start dragging, the piece will jump slightly to
8884 be centered over the mouse pointer. */
8885 player.mouseDelta.x = squareSize/2;
8886 player.mouseDelta.y = squareSize/2;
8887 /* Initialise animation */
8888 player.dragPiece = PieceForSquare(boardX, boardY);
8890 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8891 player.dragActive = True;
8892 BeginAnimation(&player, player.dragPiece, color, &corner);
8893 /* Mark this square as needing to be redrawn. Note that
8894 we don't remove the piece though, since logically (ie
8895 as seen by opponent) the move hasn't been made yet. */
8896 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8897 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8898 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8899 corner.x, corner.y, squareSize, squareSize,
8900 0, 0); // [HGM] zh: unstack in stead of grab
8901 if(gatingPiece != EmptySquare) {
8902 /* Kludge alert: When gating we want the introduced
8903 piece to appear on the from square. To generate an
8904 image of it, we draw it on the board, copy the image,
8905 and draw the original piece again. */
8906 ChessSquare piece = boards[currentMove][boardY][boardX];
8907 DrawSquare(boardY, boardX, gatingPiece, 0);
8908 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8909 corner.x, corner.y, squareSize, squareSize, 0, 0);
8910 DrawSquare(boardY, boardX, piece, 0);
8912 damage[0][boardY][boardX] = True;
8914 player.dragActive = False;
8924 /* Are we animating? */
8925 if (!appData.animateDragging || appData.blindfold)
8929 if (! player.dragActive)
8931 /* Move piece, maintaining same relative position
8932 of mouse within square */
8933 corner.x = x - player.mouseDelta.x;
8934 corner.y = y - player.mouseDelta.y;
8935 AnimationFrame(&player, &corner, player.dragPiece);
8937 if (appData.highlightDragging) {
8939 BoardSquare(x, y, &boardX, &boardY);
8940 SetHighlights(fromX, fromY, boardX, boardY);
8949 int boardX, boardY, color;
8952 /* Are we animating? */
8953 if (!appData.animateDragging || appData.blindfold)
8957 if (! player.dragActive)
8959 /* Last frame in sequence is square piece is
8960 placed on, which may not match mouse exactly. */
8961 BoardSquare(x, y, &boardX, &boardY);
8962 ScreenSquare(boardX, boardY, &corner, &color);
8963 EndAnimation(&player, &corner);
8965 /* Be sure end square is redrawn */
8966 damage[0][boardY][boardX] = True;
8968 /* This prevents weird things happening with fast successive
8969 clicks which on my Sun at least can cause motion events
8970 without corresponding press/release. */
8971 player.dragActive = False;
8974 /* Handle expose event while piece being dragged */
8979 if (!player.dragActive || appData.blindfold)
8982 /* What we're doing: logically, the move hasn't been made yet,
8983 so the piece is still in it's original square. But visually
8984 it's being dragged around the board. So we erase the square
8985 that the piece is on and draw it at the last known drag point. */
8986 BlankSquare(player.startSquare.x, player.startSquare.y,
8987 player.startColor, EmptySquare, xBoardWindow, 1);
8988 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8989 damage[0][player.startBoardY][player.startBoardX] = TRUE;
8992 #include <sys/ioctl.h>
8993 int get_term_width()
8995 int fd, default_width;
8998 default_width = 79; // this is FICS default anyway...
9000 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
9002 if (!ioctl(fd, TIOCGSIZE, &win))
9003 default_width = win.ts_cols;
9004 #elif defined(TIOCGWINSZ)
9006 if (!ioctl(fd, TIOCGWINSZ, &win))
9007 default_width = win.ws_col;
9009 return default_width;
9015 static int old_width = 0;
9016 int new_width = get_term_width();
9018 if (old_width != new_width)
9019 ics_printf("set width %d\n", new_width);
9020 old_width = new_width;
9023 void NotifyFrontendLogin()
9028 /* [AS] Arrow highlighting support */
9030 static double A_WIDTH = 5; /* Width of arrow body */
9032 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
9033 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
9035 static double Sqr( double x )
9040 static int Round( double x )
9042 return (int) (x + 0.5);
9045 void SquareToPos(int rank, int file, int *x, int *y)
9048 *x = lineGap + ((BOARD_WIDTH-1)-file) * (squareSize + lineGap);
9049 *y = lineGap + rank * (squareSize + lineGap);
9051 *x = lineGap + file * (squareSize + lineGap);
9052 *y = lineGap + ((BOARD_HEIGHT-1)-rank) * (squareSize + lineGap);
9056 /* Draw an arrow between two points using current settings */
9057 void DrawArrowBetweenPoints( int s_x, int s_y, int d_x, int d_y )
9060 double dx, dy, j, k, x, y;
9063 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
9065 arrow[0].x = s_x + A_WIDTH + 0.5;
9068 arrow[1].x = s_x + A_WIDTH + 0.5;
9069 arrow[1].y = d_y - h;
9071 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9072 arrow[2].y = d_y - h;
9077 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
9078 arrow[5].y = d_y - h;
9080 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9081 arrow[4].y = d_y - h;
9083 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
9086 else if( d_y == s_y ) {
9087 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
9090 arrow[0].y = s_y + A_WIDTH + 0.5;
9092 arrow[1].x = d_x - w;
9093 arrow[1].y = s_y + A_WIDTH + 0.5;
9095 arrow[2].x = d_x - w;
9096 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9101 arrow[5].x = d_x - w;
9102 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
9104 arrow[4].x = d_x - w;
9105 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9108 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
9111 /* [AS] Needed a lot of paper for this! :-) */
9112 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
9113 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
9115 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
9117 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
9122 arrow[0].x = Round(x - j);
9123 arrow[0].y = Round(y + j*dx);
9125 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
9126 arrow[1].y = Round(arrow[0].y - 2*j*dx);
9129 x = (double) d_x - k;
9130 y = (double) d_y - k*dy;
9133 x = (double) d_x + k;
9134 y = (double) d_y + k*dy;
9137 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
9139 arrow[6].x = Round(x - j);
9140 arrow[6].y = Round(y + j*dx);
9142 arrow[2].x = Round(arrow[6].x + 2*j);
9143 arrow[2].y = Round(arrow[6].y - 2*j*dx);
9145 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
9146 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
9151 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
9152 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
9155 XFillPolygon(xDisplay, xBoardWindow, highlineGC, arrow, 7, Nonconvex, CoordModeOrigin);
9156 // Polygon( hdc, arrow, 7 );
9159 /* [AS] Draw an arrow between two squares */
9160 void DrawArrowBetweenSquares( int s_col, int s_row, int d_col, int d_row )
9162 int s_x, s_y, d_x, d_y, hor, vert, i;
9164 if( s_col == d_col && s_row == d_row ) {
9168 /* Get source and destination points */
9169 SquareToPos( s_row, s_col, &s_x, &s_y);
9170 SquareToPos( d_row, d_col, &d_x, &d_y);
9173 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
9175 else if( d_y < s_y ) {
9176 d_y += squareSize / 2 + squareSize / 4;
9179 d_y += squareSize / 2;
9183 d_x += squareSize / 2 - squareSize / 4;
9185 else if( d_x < s_x ) {
9186 d_x += squareSize / 2 + squareSize / 4;
9189 d_x += squareSize / 2;
9192 s_x += squareSize / 2;
9193 s_y += squareSize / 2;
9196 A_WIDTH = squareSize / 14.; //[HGM] make float
9198 DrawArrowBetweenPoints( s_x, s_y, d_x, d_y );
9200 hor = 64*s_col + 32; vert = 64*s_row + 32;
9201 for(i=0; i<= 64; i++) {
9202 damage[0][vert+6>>6][hor+6>>6] = True;
9203 damage[0][vert-6>>6][hor+6>>6] = True;
9204 damage[0][vert+6>>6][hor-6>>6] = True;
9205 damage[0][vert-6>>6][hor-6>>6] = True;
9206 hor += d_col - s_col; vert += d_row - s_row;
9210 Boolean IsDrawArrowEnabled()
9212 return appData.highlightMoveWithArrow && squareSize >= 32;
9215 void DrawArrowHighlight(int fromX, int fromY, int toX,int toY)
9217 if( IsDrawArrowEnabled() && fromX >= 0 && fromY >= 0 && toX >= 0 && toY >= 0)
9218 DrawArrowBetweenSquares(fromX, fromY, toX, toY);