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((void));
246 void CreateXIMPieces P((void));
247 void CreateXPMPieces P((void));
248 void CreateXPMBoard P((char *s, int n));
249 void CreatePieces P((void));
250 void CreatePieceMenus P((void));
251 Widget CreateMenuBar P((Menu *mb));
252 Widget CreateButtonBar P ((MenuItem *mi));
253 char *FindFont P((char *pattern, int targetPxlSize));
254 void PieceMenuPopup P((Widget w, XEvent *event,
255 String *params, Cardinal *num_params));
256 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
257 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
258 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
259 u_int wreq, u_int hreq));
260 void CreateGrid P((void));
261 int EventToSquare P((int x, int limit));
262 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
263 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
264 void HandleUserMove P((Widget w, XEvent *event,
265 String *prms, Cardinal *nprms));
266 void AnimateUserMove P((Widget w, XEvent * event,
267 String * params, Cardinal * nParams));
268 void HandlePV P((Widget w, XEvent * event,
269 String * params, Cardinal * nParams));
270 void SelectPV P((Widget w, XEvent * event,
271 String * params, Cardinal * nParams));
272 void StopPV P((Widget w, XEvent * event,
273 String * params, Cardinal * nParams));
274 void WhiteClock P((Widget w, XEvent *event,
275 String *prms, Cardinal *nprms));
276 void BlackClock P((Widget w, XEvent *event,
277 String *prms, Cardinal *nprms));
278 void DrawPositionProc P((Widget w, XEvent *event,
279 String *prms, Cardinal *nprms));
280 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
282 void CommentClick P((Widget w, XEvent * event,
283 String * params, Cardinal * nParams));
284 void CommentPopUp P((char *title, char *label));
285 void CommentPopDown P((void));
286 void CommentCallback P((Widget w, XtPointer client_data,
287 XtPointer call_data));
288 void ICSInputBoxPopUp P((void));
289 void ICSInputBoxPopDown P((void));
290 void FileNamePopUp P((char *label, char *def,
291 FileProc proc, char *openMode));
292 void FileNamePopDown P((void));
293 void FileNameCallback P((Widget w, XtPointer client_data,
294 XtPointer call_data));
295 void FileNameAction P((Widget w, XEvent *event,
296 String *prms, Cardinal *nprms));
297 void AskQuestionReplyAction P((Widget w, XEvent *event,
298 String *prms, Cardinal *nprms));
299 void AskQuestionProc P((Widget w, XEvent *event,
300 String *prms, Cardinal *nprms));
301 void AskQuestionPopDown P((void));
302 void PromotionPopDown P((void));
303 void PromotionCallback P((Widget w, XtPointer client_data,
304 XtPointer call_data));
305 void EditCommentPopDown P((void));
306 void EditCommentCallback P((Widget w, XtPointer client_data,
307 XtPointer call_data));
308 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
309 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
310 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
311 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
313 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
315 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
317 void LoadPositionProc P((Widget w, XEvent *event,
318 String *prms, Cardinal *nprms));
319 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
321 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
323 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
325 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
327 void PastePositionProc P((Widget w, XEvent *event, String *prms,
329 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
330 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
331 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
332 void SavePositionProc P((Widget w, XEvent *event,
333 String *prms, Cardinal *nprms));
334 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
335 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
337 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
338 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
339 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
341 void MachineWhiteProc P((Widget w, XEvent *event,
342 String *prms, Cardinal *nprms));
343 void AnalyzeModeProc P((Widget w, XEvent *event,
344 String *prms, Cardinal *nprms));
345 void AnalyzeFileProc P((Widget w, XEvent *event,
346 String *prms, Cardinal *nprms));
347 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
349 void IcsClientProc P((Widget w, XEvent *event, String *prms,
351 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
352 void EditPositionProc P((Widget w, XEvent *event,
353 String *prms, Cardinal *nprms));
354 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
355 void EditCommentProc P((Widget w, XEvent *event,
356 String *prms, Cardinal *nprms));
357 void IcsInputBoxProc P((Widget w, XEvent *event,
358 String *prms, Cardinal *nprms));
359 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
365 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
369 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
370 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
371 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
372 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
373 void StopObservingProc P((Widget w, XEvent *event, String *prms,
375 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
377 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
379 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
380 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
384 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
386 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
388 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
389 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
391 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
393 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
395 void 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 LoadOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
458 void SaveOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
459 void GameListOptionsPopDown P(());
460 void ShufflePopDown P(());
461 void EnginePopDown P(());
462 void UciPopDown P(());
463 void TimeControlPopDown P(());
464 void NewVariantPopDown P(());
465 void SettingsPopDown P(());
466 void update_ics_width P(());
467 int get_term_width P(());
468 int CopyMemoProc P(());
469 void DrawArrowHighlight P((int fromX, int fromY, int toX,int toY));
470 Boolean IsDrawArrowEnabled P(());
473 * XBoard depends on Xt R4 or higher
475 int xtVersion = XtSpecificationRelease;
480 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
481 jailSquareColor, highlightSquareColor, premoveHighlightColor;
482 Pixel lowTimeWarningColor;
483 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
484 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
485 wjPieceGC, bjPieceGC, prelineGC, countGC;
486 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
487 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
488 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
489 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
490 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
491 ICSInputShell, fileNameShell, askQuestionShell;
492 Widget historyShell, evalGraphShell, gameListShell;
493 int hOffset; // [HGM] dual
494 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
495 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
496 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
497 Font clockFontID, coordFontID, countFontID;
498 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
499 XtAppContext appContext;
501 char *oldICSInteractionTitle;
505 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
507 Position commentX = -1, commentY = -1;
508 Dimension commentW, commentH;
509 typedef unsigned int BoardSize;
511 Boolean chessProgram;
513 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
514 int squareSize, smallLayout = 0, tinyLayout = 0,
515 marginW, marginH, // [HGM] for run-time resizing
516 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
517 ICSInputBoxUp = False, askQuestionUp = False,
518 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
519 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
520 Pixel timerForegroundPixel, timerBackgroundPixel;
521 Pixel buttonForegroundPixel, buttonBackgroundPixel;
522 char *chessDir, *programName, *programVersion,
523 *gameCopyFilename, *gamePasteFilename;
524 Boolean alwaysOnTop = False;
525 Boolean saveSettingsOnExit;
526 char *settingsFileName;
527 char *icsTextMenuString;
529 char *firstChessProgramNames;
530 char *secondChessProgramNames;
532 WindowPlacement wpMain;
533 WindowPlacement wpConsole;
534 WindowPlacement wpComment;
535 WindowPlacement wpMoveHistory;
536 WindowPlacement wpEvalGraph;
537 WindowPlacement wpEngineOutput;
538 WindowPlacement wpGameList;
539 WindowPlacement wpTags;
543 Pixmap pieceBitmap[2][(int)BlackPawn];
544 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
545 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
546 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
547 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
548 Pixmap xpmBoardBitmap[2];
549 int useImages, useImageSqs, useTexture, textureW[2], textureH[2];
550 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
551 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
552 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
553 XImage *ximLightSquare, *ximDarkSquare;
556 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
557 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
559 #define White(piece) ((int)(piece) < (int)BlackPawn)
561 /* Variables for doing smooth animation. This whole thing
562 would be much easier if the board was double-buffered,
563 but that would require a fairly major rewrite. */
568 GC blitGC, pieceGC, outlineGC;
569 XPoint startSquare, prevFrame, mouseDelta;
573 int startBoardX, startBoardY;
576 /* There can be two pieces being animated at once: a player
577 can begin dragging a piece before the remote opponent has moved. */
579 static AnimState game, player;
581 /* Bitmaps for use as masks when drawing XPM pieces.
582 Need one for each black and white piece. */
583 static Pixmap xpmMask[BlackKing + 1];
585 /* This magic number is the number of intermediate frames used
586 in each half of the animation. For short moves it's reduced
587 by 1. The total number of frames will be factor * 2 + 1. */
590 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
592 MenuItem fileMenu[] = {
593 {N_("New Game Ctrl+N"), "New Game", ResetProc},
594 {N_("New Shuffle Game ..."), "New Shuffle Game", ShuffleMenuProc},
595 {N_("New Variant ... Alt+Shift+V"), "New Variant", NewVariantProc}, // [HGM] variant: not functional yet
596 {"----", NULL, NothingProc},
597 {N_("Load Game Ctrl+O"), "Load Game", LoadGameProc},
598 {N_("Load Position Ctrl+Shift+O"), "Load Position", LoadPositionProc},
599 // {N_("Load Next Game"), "Load Next Game", LoadNextGameProc},
600 // {N_("Load Previous Game"), "Load Previous Game", LoadPrevGameProc},
601 // {N_("Reload Same Game"), "Reload Same Game", ReloadGameProc},
602 {N_("Next Position Shift+PgDn"), "Load Next Position", LoadNextPositionProc},
603 {N_("Prev Position Shift+PgUp"), "Load Previous Position", LoadPrevPositionProc},
604 {"----", NULL, NothingProc},
605 // {N_("Reload Same Position"), "Reload Same Position", ReloadPositionProc},
606 {N_("Save Game Ctrl+S"), "Save Game", SaveGameProc},
607 {N_("Save Position Ctrl+Shift+S"), "Save Position", SavePositionProc},
608 {"----", NULL, NothingProc},
609 {N_("Mail Move"), "Mail Move", MailMoveProc},
610 {N_("Reload CMail Message"), "Reload CMail Message", ReloadCmailMsgProc},
611 {"----", NULL, NothingProc},
612 {N_("Quit Ctr+Q"), "Exit", QuitProc},
616 MenuItem editMenu[] = {
617 {N_("Copy Game Ctrl+C"), "Copy Game", CopyGameProc},
618 {N_("Copy Position Ctrl+Shift+C"), "Copy Position", CopyPositionProc},
619 {"----", NULL, NothingProc},
620 {N_("Paste Game Ctrl+V"), "Paste Game", PasteGameProc},
621 {N_("Paste Position Ctrl+Shift+V"), "Paste Position", PastePositionProc},
622 {"----", NULL, NothingProc},
623 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
624 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
625 {N_("Edit Tags"), "Edit Tags", EditTagsProc},
626 {N_("Edit Comment"), "Edit Comment", EditCommentProc},
627 {"----", NULL, NothingProc},
628 {N_("Revert Home"), "Revert", RevertProc},
629 {N_("Annotate"), "Annotate", AnnotateProc},
630 {N_("Truncate Game End"), "Truncate Game", TruncateGameProc},
631 {"----", NULL, NothingProc},
632 {N_("Backward Alt+Left"), "Backward", BackwardProc},
633 {N_("Forward Alt+Right"), "Forward", ForwardProc},
634 {N_("Back to Start Alt+Home"), "Back to Start", ToStartProc},
635 {N_("Forward to End Alt+End"), "Forward to End", ToEndProc},
639 MenuItem viewMenu[] = {
640 {N_("Flip View F2"), "Flip View", FlipViewProc},
641 {"----", NULL, NothingProc},
642 {N_("Engine Output Alt+Shift+O"), "Show Engine Output", EngineOutputProc},
643 {N_("Move History Alt+Shift+H"), "Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
644 {N_("Evaluation Graph Alt+Shift+E"), "Show Evaluation Graph", EvalGraphProc},
645 {N_("Game List Alt+Shift+G"), "Show Game List", ShowGameListProc},
646 {"----", NULL, NothingProc},
647 {N_("Tags"), "Show Tags", EditTagsProc},
648 {N_("Comments"), "Show Comments", EditCommentProc},
649 {N_("ICS Input Box"), "ICS Input Box", IcsInputBoxProc},
653 MenuItem modeMenu[] = {
654 {N_("Machine White Ctrl+W"), "Machine White", MachineWhiteProc},
655 {N_("Machine Black Ctrl+B"), "Machine Black", MachineBlackProc},
656 {N_("Two Machines Ctrl+T"), "Two Machines", TwoMachinesProc},
657 {N_("Analysis Mode Ctrl+A"), "Analysis Mode", AnalyzeModeProc},
658 {N_("Analyze File Ctrl+F"), "Analyze File", AnalyzeFileProc },
659 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
660 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
661 {N_("Training"), "Training", TrainingProc},
662 {N_("ICS Client"), "ICS Client", IcsClientProc},
663 {"----", NULL, NothingProc},
664 {N_("Pause Pause"), "Pause", PauseProc},
668 MenuItem actionMenu[] = {
669 {N_("Accept F3"), "Accept", AcceptProc},
670 {N_("Decline F4"), "Decline", DeclineProc},
671 {N_("Rematch F12"), "Rematch", RematchProc},
672 {"----", NULL, NothingProc},
673 {N_("Call Flag F5"), "Call Flag", CallFlagProc},
674 {N_("Draw F6"), "Draw", DrawProc},
675 {N_("Adjourn F7"), "Adjourn", AdjournProc},
676 {N_("Abort F8"),"Abort", AbortProc},
677 {N_("Resign F9"), "Resign", ResignProc},
678 {"----", NULL, NothingProc},
679 {N_("Stop Observing F10"), "Stop Observing", StopObservingProc},
680 {N_("Stop Examining F11"), "Stop Examining", StopExaminingProc},
681 {N_("Upload to Examine"), "Upload to Examine", UploadProc},
682 {"----", NULL, NothingProc},
683 {N_("Adjudicate to White"), "Adjudicate to White", AdjuWhiteProc},
684 {N_("Adjudicate to Black"), "Adjudicate to Black", AdjuBlackProc},
685 {N_("Adjudicate Draw"), "Adjudicate Draw", AdjuDrawProc},
689 MenuItem engineMenu[] = {
690 {N_("Engine #1 Settings ..."), "Engine #1 Settings", FirstSettingsProc},
691 {N_("Engine #2 Settings ..."), "Engine #2 Settings", SecondSettingsProc},
692 {"----", NULL, NothingProc},
693 {N_("Hint"), "Hint", HintProc},
694 {N_("Book"), "Book", BookProc},
695 {"----", NULL, NothingProc},
696 {N_("Move Now Ctrl+M"), "Move Now", MoveNowProc},
697 {N_("Retract Move Ctrl+X"), "Retract Move", RetractMoveProc},
701 MenuItem optionsMenu[] = {
702 {N_("Time Control ... Alt+Shift+T"), "Time Control", TimeControlProc},
703 {N_("Common Engine ... Alt+Shift+U"), "Common Engine", UciMenuProc},
704 {N_("Adjudications ... Alt+Shift+J"), "Adjudications", EngineMenuProc},
705 {N_("Load Game ..."), "Load Game", LoadOptionsProc},
706 {N_("Save Game ..."), "Save Game", SaveOptionsProc},
707 // {N_(" ..."), "", OptionsProc},
708 {N_("Game List ..."), "Game List", GameListOptionsPopUp},
709 {"----", NULL, NothingProc},
710 {N_("Always Queen Ctrl+Shift+Q"), "Always Queen", AlwaysQueenProc},
711 {N_("Animate Dragging"), "Animate Dragging", AnimateDraggingProc},
712 {N_("Animate Moving Ctrl+Shift+A"), "Animate Moving", AnimateMovingProc},
713 {N_("Auto Flag Ctrl+Shift+F"), "Auto Flag", AutoflagProc},
714 {N_("Auto Flip View"), "Auto Flip View", AutoflipProc},
715 {N_("Blindfold"), "Blindfold", BlindfoldProc},
716 {N_("Flash Moves"), "Flash Moves", FlashMovesProc},
718 {N_("Highlight Dragging"), "Highlight Dragging", HighlightDraggingProc},
720 {N_("Highlight Last Move"), "Highlight Last Move", HighlightLastMoveProc},
721 {N_("Highlight With Arrow"), "Arrow", HighlightArrowProc},
722 {N_("Move Sound"), "Move Sound", MoveSoundProc},
723 // {N_("ICS Alarm"), "ICS Alarm", IcsAlarmProc},
724 {N_("One-Click Moving"), "OneClick", OneClickProc},
725 {N_("Periodic Updates"), "Periodic Updates", PeriodicUpdatesProc},
726 {N_("Ponder Next Move Ctrl+Shift+P"), "Ponder Next Move", PonderNextMoveProc},
727 {N_("Popup Exit Message"), "Popup Exit Message", PopupExitMessageProc},
728 {N_("Popup Move Errors"), "Popup Move Errors", PopupMoveErrorsProc},
729 // {N_("Premove"), "Premove", PremoveProc},
730 {N_("Show Coords"), "Show Coords", ShowCoordsProc},
731 {N_("Hide Thinking Ctrl+Shift+H"), "Hide Thinking", HideThinkingProc},
732 {N_("Test Legality Ctrl+Shift+L"), "Test Legality", TestLegalityProc},
733 {"----", NULL, NothingProc},
734 {N_("Save Settings Now"), "Save Settings Now", SaveSettingsProc},
735 {N_("Save Settings on Exit"), "Save Settings on Exit", SaveOnExitProc},
739 MenuItem helpMenu[] = {
740 {N_("Info XBoard"), "Info XBoard", InfoProc},
741 {N_("Man XBoard F1"), "Man XBoard", ManProc},
742 {"----", NULL, NothingProc},
743 {N_("About XBoard"), "About XBoard", AboutProc},
748 {N_("File"), "File", fileMenu},
749 {N_("Edit"), "Edit", editMenu},
750 {N_("View"), "View", viewMenu},
751 {N_("Mode"), "Mode", modeMenu},
752 {N_("Action"), "Action", actionMenu},
753 {N_("Engine"), "Engine", engineMenu},
754 {N_("Options"), "Options", optionsMenu},
755 {N_("Help"), "Help", helpMenu},
759 #define PAUSE_BUTTON "P"
760 MenuItem buttonBar[] = {
761 {"<<", "<<", ToStartProc},
762 {"<", "<", BackwardProc},
763 {PAUSE_BUTTON, PAUSE_BUTTON, PauseProc},
764 {">", ">", ForwardProc},
765 {">>", ">>", ToEndProc},
769 #define PIECE_MENU_SIZE 18
770 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
771 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
772 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
773 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
774 N_("Empty square"), N_("Clear board") },
775 { N_("Black"), "----", 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") }
780 /* must be in same order as PieceMenuStrings! */
781 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
782 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
783 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
784 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
785 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
786 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
787 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
788 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
789 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
792 #define DROP_MENU_SIZE 6
793 String dropMenuStrings[DROP_MENU_SIZE] = {
794 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
796 /* must be in same order as PieceMenuStrings! */
797 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
798 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
799 WhiteRook, WhiteQueen
807 DropMenuEnables dmEnables[] = {
825 { XtNborderWidth, 0 },
826 { XtNdefaultDistance, 0 },
830 { XtNborderWidth, 0 },
831 { XtNresizable, (XtArgVal) True },
835 { XtNborderWidth, 0 },
841 { XtNjustify, (XtArgVal) XtJustifyRight },
842 { XtNlabel, (XtArgVal) "..." },
843 { XtNresizable, (XtArgVal) True },
844 { XtNresize, (XtArgVal) False }
847 Arg messageArgs[] = {
848 { XtNjustify, (XtArgVal) XtJustifyLeft },
849 { XtNlabel, (XtArgVal) "..." },
850 { XtNresizable, (XtArgVal) True },
851 { XtNresize, (XtArgVal) False }
855 { XtNborderWidth, 0 },
856 { XtNjustify, (XtArgVal) XtJustifyLeft }
859 XtResource clientResources[] = {
860 { "flashCount", "flashCount", XtRInt, sizeof(int),
861 XtOffset(AppDataPtr, flashCount), XtRImmediate,
862 (XtPointer) FLASH_COUNT },
865 XrmOptionDescRec shellOptions[] = {
866 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
867 { "-flash", "flashCount", XrmoptionNoArg, "3" },
868 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
871 XtActionsRec boardActions[] = {
872 { "DrawPosition", DrawPositionProc },
873 { "HandleUserMove", HandleUserMove },
874 { "AnimateUserMove", AnimateUserMove },
875 { "HandlePV", HandlePV },
876 { "SelectPV", SelectPV },
877 { "StopPV", StopPV },
878 { "FileNameAction", FileNameAction },
879 { "AskQuestionProc", AskQuestionProc },
880 { "AskQuestionReplyAction", AskQuestionReplyAction },
881 { "PieceMenuPopup", PieceMenuPopup },
882 { "WhiteClock", WhiteClock },
883 { "BlackClock", BlackClock },
884 { "Iconify", Iconify },
885 { "ResetProc", ResetProc },
886 { "NewVariantProc", NewVariantProc },
887 { "LoadGameProc", LoadGameProc },
888 { "LoadNextGameProc", LoadNextGameProc },
889 { "LoadPrevGameProc", LoadPrevGameProc },
890 { "LoadSelectedProc", LoadSelectedProc },
891 { "SetFilterProc", SetFilterProc },
892 { "ReloadGameProc", ReloadGameProc },
893 { "LoadPositionProc", LoadPositionProc },
894 { "LoadNextPositionProc", LoadNextPositionProc },
895 { "LoadPrevPositionProc", LoadPrevPositionProc },
896 { "ReloadPositionProc", ReloadPositionProc },
897 { "CopyPositionProc", CopyPositionProc },
898 { "PastePositionProc", PastePositionProc },
899 { "CopyGameProc", CopyGameProc },
900 { "PasteGameProc", PasteGameProc },
901 { "SaveGameProc", SaveGameProc },
902 { "SavePositionProc", SavePositionProc },
903 { "MailMoveProc", MailMoveProc },
904 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
905 { "QuitProc", QuitProc },
906 { "MachineWhiteProc", MachineWhiteProc },
907 { "MachineBlackProc", MachineBlackProc },
908 { "AnalysisModeProc", AnalyzeModeProc },
909 { "AnalyzeFileProc", AnalyzeFileProc },
910 { "TwoMachinesProc", TwoMachinesProc },
911 { "IcsClientProc", IcsClientProc },
912 { "EditGameProc", EditGameProc },
913 { "EditPositionProc", EditPositionProc },
914 { "TrainingProc", EditPositionProc },
915 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
916 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
917 { "ShowGameListProc", ShowGameListProc },
918 { "ShowMoveListProc", HistoryShowProc},
919 { "EditTagsProc", EditCommentProc },
920 { "EditCommentProc", EditCommentProc },
921 { "IcsInputBoxProc", IcsInputBoxProc },
922 { "PauseProc", PauseProc },
923 { "AcceptProc", AcceptProc },
924 { "DeclineProc", DeclineProc },
925 { "RematchProc", RematchProc },
926 { "CallFlagProc", CallFlagProc },
927 { "DrawProc", DrawProc },
928 { "AdjournProc", AdjournProc },
929 { "AbortProc", AbortProc },
930 { "ResignProc", ResignProc },
931 { "AdjuWhiteProc", AdjuWhiteProc },
932 { "AdjuBlackProc", AdjuBlackProc },
933 { "AdjuDrawProc", AdjuDrawProc },
934 { "EnterKeyProc", EnterKeyProc },
935 { "UpKeyProc", UpKeyProc },
936 { "DownKeyProc", DownKeyProc },
937 { "StopObservingProc", StopObservingProc },
938 { "StopExaminingProc", StopExaminingProc },
939 { "UploadProc", UploadProc },
940 { "BackwardProc", BackwardProc },
941 { "ForwardProc", ForwardProc },
942 { "ToStartProc", ToStartProc },
943 { "ToEndProc", ToEndProc },
944 { "RevertProc", RevertProc },
945 { "AnnotateProc", AnnotateProc },
946 { "TruncateGameProc", TruncateGameProc },
947 { "MoveNowProc", MoveNowProc },
948 { "RetractMoveProc", RetractMoveProc },
949 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
950 { "UciMenuProc", (XtActionProc) UciMenuProc },
951 { "TimeControlProc", (XtActionProc) TimeControlProc },
952 { "AlwaysQueenProc", AlwaysQueenProc },
953 { "AnimateDraggingProc", AnimateDraggingProc },
954 { "AnimateMovingProc", AnimateMovingProc },
955 { "AutoflagProc", AutoflagProc },
956 { "AutoflipProc", AutoflipProc },
957 { "BlindfoldProc", BlindfoldProc },
958 { "FlashMovesProc", FlashMovesProc },
959 { "FlipViewProc", FlipViewProc },
961 { "HighlightDraggingProc", HighlightDraggingProc },
963 { "HighlightLastMoveProc", HighlightLastMoveProc },
964 // { "IcsAlarmProc", IcsAlarmProc },
965 { "MoveSoundProc", MoveSoundProc },
966 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
967 { "PonderNextMoveProc", PonderNextMoveProc },
968 { "PopupExitMessageProc", PopupExitMessageProc },
969 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
970 // { "PremoveProc", PremoveProc },
971 { "ShowCoordsProc", ShowCoordsProc },
972 { "ShowThinkingProc", ShowThinkingProc },
973 { "HideThinkingProc", HideThinkingProc },
974 { "TestLegalityProc", TestLegalityProc },
975 { "SaveSettingsProc", SaveSettingsProc },
976 { "SaveOnExitProc", SaveOnExitProc },
977 { "InfoProc", InfoProc },
978 { "ManProc", ManProc },
979 { "HintProc", HintProc },
980 { "BookProc", BookProc },
981 { "AboutGameProc", AboutGameProc },
982 { "AboutProc", AboutProc },
983 { "DebugProc", DebugProc },
984 { "NothingProc", NothingProc },
985 { "CommentClick", (XtActionProc) CommentClick },
986 { "CommentPopDown", (XtActionProc) CommentPopDown },
987 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
988 { "TagsPopDown", (XtActionProc) TagsPopDown },
989 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
990 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
991 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
992 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
993 { "GameListPopDown", (XtActionProc) GameListPopDown },
994 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
995 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
996 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
997 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
998 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
999 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
1000 { "EnginePopDown", (XtActionProc) EnginePopDown },
1001 { "UciPopDown", (XtActionProc) UciPopDown },
1002 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
1003 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
1004 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
1005 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1008 char globalTranslations[] =
1009 ":<Key>F9: ResignProc() \n \
1010 :Ctrl<Key>n: ResetProc() \n \
1011 :Meta<Key>V: NewVariantProc() \n \
1012 :Ctrl<Key>o: LoadGameProc() \n \
1013 :Meta<Key>Next: LoadNextGameProc() \n \
1014 :Meta<Key>Prior: LoadPrevGameProc() \n \
1015 :Ctrl<Key>s: SaveGameProc() \n \
1016 :Ctrl<Key>c: CopyGameProc() \n \
1017 :Ctrl<Key>v: PasteGameProc() \n \
1018 :Ctrl<Key>O: LoadPositionProc() \n \
1019 :Shift<Key>Next: LoadNextPositionProc() \n \
1020 :Shift<Key>Prior: LoadPrevPositionProc() \n \
1021 :Ctrl<Key>S: SavePositionProc() \n \
1022 :Ctrl<Key>C: CopyPositionProc() \n \
1023 :Ctrl<Key>V: PastePositionProc() \n \
1024 :Ctrl<Key>q: QuitProc() \n \
1025 :Ctrl<Key>w: MachineWhiteProc() \n \
1026 :Ctrl<Key>b: MachineBlackProc() \n \
1027 :Ctrl<Key>t: TwoMachinesProc() \n \
1028 :Ctrl<Key>a: AnalysisModeProc() \n \
1029 :Ctrl<Key>f: AnalyzeFileProc() \n \
1030 :Ctrl<Key>e: EditGameProc() \n \
1031 :Ctrl<Key>E: EditPositionProc() \n \
1032 :Meta<Key>O: EngineOutputProc() \n \
1033 :Meta<Key>E: EvalGraphProc() \n \
1034 :Meta<Key>G: ShowGameListProc() \n \
1035 :Meta<Key>H: ShowMoveListProc() \n \
1036 :<Key>Pause: PauseProc() \n \
1037 :<Key>F3: AcceptProc() \n \
1038 :<Key>F4: DeclineProc() \n \
1039 :<Key>F12: RematchProc() \n \
1040 :<Key>F5: CallFlagProc() \n \
1041 :<Key>F6: DrawProc() \n \
1042 :<Key>F7: AdjournProc() \n \
1043 :<Key>F8: AbortProc() \n \
1044 :<Key>F10: StopObservingProc() \n \
1045 :<Key>F11: StopExaminingProc() \n \
1046 :Meta Ctrl<Key>F12: DebugProc() \n \
1047 :Meta<Key>End: ToEndProc() \n \
1048 :Meta<Key>Right: ForwardProc() \n \
1049 :Meta<Key>Home: ToStartProc() \n \
1050 :Meta<Key>Left: BackwardProc() \n \
1051 :<Key>Home: RevertProc() \n \
1052 :<Key>End: TruncateGameProc() \n \
1053 :Ctrl<Key>m: MoveNowProc() \n \
1054 :Ctrl<Key>x: RetractMoveProc() \n \
1055 :Meta<Key>J: EngineMenuProc() \n \
1056 :Meta<Key>U: UciMenuProc() \n \
1057 :Meta<Key>T: TimeControlProc() \n \
1058 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1059 :Ctrl<Key>F: AutoflagProc() \n \
1060 :Ctrl<Key>A: AnimateMovingProc() \n \
1061 :Ctrl<Key>P: PonderNextMoveProc() \n \
1062 :Ctrl<Key>L: TestLegalityProc() \n \
1063 :Ctrl<Key>H: HideThinkingProc() \n \
1064 :<Key>-: Iconify() \n \
1065 :<Key>F1: ManProc() \n \
1066 :<Key>F2: FlipViewProc() \n \
1067 <KeyDown>.: BackwardProc() \n \
1068 <KeyUp>.: ForwardProc() \n \
1069 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1070 \"Send to chess program:\",,1) \n \
1071 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1072 \"Send to second chess program:\",,2) \n";
1074 char boardTranslations[] =
1075 "<Btn1Down>: HandleUserMove(0) \n \
1076 Shift<Btn1Up>: HandleUserMove(1) \n \
1077 <Btn1Up>: HandleUserMove(0) \n \
1078 <Btn1Motion>: AnimateUserMove() \n \
1079 <Btn3Motion>: HandlePV() \n \
1080 <Btn3Up>: PieceMenuPopup(menuB) \n \
1081 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1082 PieceMenuPopup(menuB) \n \
1083 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1084 PieceMenuPopup(menuW) \n \
1085 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1086 PieceMenuPopup(menuW) \n \
1087 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1088 PieceMenuPopup(menuB) \n";
1090 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1091 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1093 char ICSInputTranslations[] =
1094 "<Key>Up: UpKeyProc() \n "
1095 "<Key>Down: DownKeyProc() \n "
1096 "<Key>Return: EnterKeyProc() \n";
1098 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1099 // as the widget is destroyed before the up-click can call extend-end
1100 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1102 String xboardResources[] = {
1103 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1104 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1105 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1110 /* Max possible square size */
1111 #define MAXSQSIZE 256
1113 static int xpm_avail[MAXSQSIZE];
1115 #ifdef HAVE_DIR_STRUCT
1117 /* Extract piece size from filename */
1119 xpm_getsize(name, len, ext)
1130 if ((p=strchr(name, '.')) == NULL ||
1131 StrCaseCmp(p+1, ext) != 0)
1137 while (*p && isdigit(*p))
1144 /* Setup xpm_avail */
1146 xpm_getavail(dirname, ext)
1154 for (i=0; i<MAXSQSIZE; ++i)
1157 if (appData.debugMode)
1158 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1160 dir = opendir(dirname);
1163 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1164 programName, dirname);
1168 while ((ent=readdir(dir)) != NULL) {
1169 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1170 if (i > 0 && i < MAXSQSIZE)
1180 xpm_print_avail(fp, ext)
1186 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1187 for (i=1; i<MAXSQSIZE; ++i) {
1193 /* Return XPM piecesize closest to size */
1195 xpm_closest_to(dirname, size, ext)
1201 int sm_diff = MAXSQSIZE;
1205 xpm_getavail(dirname, ext);
1207 if (appData.debugMode)
1208 xpm_print_avail(stderr, ext);
1210 for (i=1; i<MAXSQSIZE; ++i) {
1213 diff = (diff<0) ? -diff : diff;
1214 if (diff < sm_diff) {
1222 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1228 #else /* !HAVE_DIR_STRUCT */
1229 /* If we are on a system without a DIR struct, we can't
1230 read the directory, so we can't collect a list of
1231 filenames, etc., so we can't do any size-fitting. */
1233 xpm_closest_to(dirname, size, ext)
1238 fprintf(stderr, _("\
1239 Warning: No DIR structure found on this system --\n\
1240 Unable to autosize for XPM/XIM pieces.\n\
1241 Please report this error to frankm@hiwaay.net.\n\
1242 Include system type & operating system in message.\n"));
1245 #endif /* HAVE_DIR_STRUCT */
1247 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1248 "magenta", "cyan", "white" };
1252 TextColors textColors[(int)NColorClasses];
1254 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1256 parse_color(str, which)
1260 char *p, buf[100], *d;
1263 if (strlen(str) > 99) /* watch bounds on buf */
1268 for (i=0; i<which; ++i) {
1275 /* Could be looking at something like:
1277 .. in which case we want to stop on a comma also */
1278 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1282 return -1; /* Use default for empty field */
1285 if (which == 2 || isdigit(*p))
1288 while (*p && isalpha(*p))
1293 for (i=0; i<8; ++i) {
1294 if (!StrCaseCmp(buf, cnames[i]))
1295 return which? (i+40) : (i+30);
1297 if (!StrCaseCmp(buf, "default")) return -1;
1299 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1304 parse_cpair(cc, str)
1308 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1309 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1314 /* bg and attr are optional */
1315 textColors[(int)cc].bg = parse_color(str, 1);
1316 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1317 textColors[(int)cc].attr = 0;
1323 /* Arrange to catch delete-window events */
1324 Atom wm_delete_window;
1326 CatchDeleteWindow(Widget w, String procname)
1329 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1330 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1331 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1338 XtSetArg(args[0], XtNiconic, False);
1339 XtSetValues(shellWidget, args, 1);
1341 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1344 //---------------------------------------------------------------------------------------------------------
1345 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1348 #define CW_USEDEFAULT (1<<31)
1349 #define ICS_TEXT_MENU_SIZE 90
1350 #define DEBUG_FILE "xboard.debug"
1351 #define SetCurrentDirectory chdir
1352 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1356 // these two must some day move to frontend.h, when they are implemented
1357 Boolean GameListIsUp();
1359 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1362 // front-end part of option handling
1364 // [HGM] This platform-dependent table provides the location for storing the color info
1365 extern char *crWhite, * crBlack;
1369 &appData.whitePieceColor,
1370 &appData.blackPieceColor,
1371 &appData.lightSquareColor,
1372 &appData.darkSquareColor,
1373 &appData.highlightSquareColor,
1374 &appData.premoveHighlightColor,
1375 &appData.lowTimeWarningColor,
1386 // [HGM] font: keep a font for each square size, even non-stndard ones
1387 #define NUM_SIZES 18
1388 #define MAX_SIZE 130
1389 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1390 char *fontTable[NUM_FONTS][MAX_SIZE];
1393 ParseFont(char *name, int number)
1394 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1396 if(sscanf(name, "size%d:", &size)) {
1397 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1398 // defer processing it until we know if it matches our board size
1399 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1400 fontTable[number][size] = strdup(strchr(name, ':')+1);
1401 fontValid[number][size] = True;
1406 case 0: // CLOCK_FONT
1407 appData.clockFont = strdup(name);
1409 case 1: // MESSAGE_FONT
1410 appData.font = strdup(name);
1412 case 2: // COORD_FONT
1413 appData.coordFont = strdup(name);
1418 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1423 { // only 2 fonts currently
1424 appData.clockFont = CLOCK_FONT_NAME;
1425 appData.coordFont = COORD_FONT_NAME;
1426 appData.font = DEFAULT_FONT_NAME;
1431 { // no-op, until we identify the code for this already in XBoard and move it here
1435 ParseColor(int n, char *name)
1436 { // in XBoard, just copy the color-name string
1437 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1441 ParseTextAttribs(ColorClass cc, char *s)
1443 (&appData.colorShout)[cc] = strdup(s);
1447 ParseBoardSize(void *addr, char *name)
1449 appData.boardSize = strdup(name);
1454 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1458 SetCommPortDefaults()
1459 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1462 // [HGM] args: these three cases taken out to stay in front-end
1464 SaveFontArg(FILE *f, ArgDescriptor *ad)
1467 int i, n = (int)(intptr_t)ad->argLoc;
1469 case 0: // CLOCK_FONT
1470 name = appData.clockFont;
1472 case 1: // MESSAGE_FONT
1473 name = appData.font;
1475 case 2: // COORD_FONT
1476 name = appData.coordFont;
1481 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1482 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1483 fontTable[n][squareSize] = strdup(name);
1484 fontValid[n][squareSize] = True;
1487 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1488 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1493 { // nothing to do, as the sounds are at all times represented by their text-string names already
1497 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1498 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1499 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
1503 SaveColor(FILE *f, ArgDescriptor *ad)
1504 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1505 if(colorVariable[(int)(intptr_t)ad->argLoc])
1506 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
1510 SaveBoardSize(FILE *f, char *name, void *addr)
1511 { // wrapper to shield back-end from BoardSize & sizeInfo
1512 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1516 ParseCommPortSettings(char *s)
1517 { // no such option in XBoard (yet)
1520 extern Widget engineOutputShell;
1521 extern Widget tagsShell, editTagsShell;
1523 GetActualPlacement(Widget wg, WindowPlacement *wp)
1533 XtSetArg(args[i], XtNx, &x); i++;
1534 XtSetArg(args[i], XtNy, &y); i++;
1535 XtSetArg(args[i], XtNwidth, &w); i++;
1536 XtSetArg(args[i], XtNheight, &h); i++;
1537 XtGetValues(wg, args, i);
1546 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1547 // In XBoard this will have to wait until awareness of window parameters is implemented
1548 GetActualPlacement(shellWidget, &wpMain);
1549 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1550 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1551 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1552 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1553 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1554 else GetActualPlacement(editShell, &wpComment);
1555 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1556 else GetActualPlacement(editTagsShell, &wpTags);
1560 PrintCommPortSettings(FILE *f, char *name)
1561 { // This option does not exist in XBoard
1565 MySearchPath(char *installDir, char *name, char *fullname)
1566 { // just append installDir and name. Perhaps ExpandPath should be used here?
1567 name = ExpandPathName(name);
1568 if(name && name[0] == '/')
1569 safeStrCpy(fullname, name, MSG_SIZ );
1571 sprintf(fullname, "%s%c%s", installDir, '/', name);
1577 MyGetFullPathName(char *name, char *fullname)
1578 { // should use ExpandPath?
1579 name = ExpandPathName(name);
1580 safeStrCpy(fullname, name, MSG_SIZ );
1585 EnsureOnScreen(int *x, int *y, int minX, int minY)
1592 { // [HGM] args: allows testing if main window is realized from back-end
1593 return xBoardWindow != 0;
1597 PopUpStartupDialog()
1598 { // start menu not implemented in XBoard
1602 ConvertToLine(int argc, char **argv)
1604 static char line[128*1024], buf[1024];
1608 for(i=1; i<argc; i++)
1610 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1611 && argv[i][0] != '{' )
1612 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1614 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1615 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1618 line[strlen(line)-1] = NULLCHAR;
1622 //--------------------------------------------------------------------------------------------
1624 extern Boolean twoBoards, partnerUp;
1627 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1629 #define BoardSize int
1630 void InitDrawingSizes(BoardSize boardSize, int flags)
1631 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1632 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1634 XtGeometryResult gres;
1637 if(!formWidget) return;
1640 * Enable shell resizing.
1642 shellArgs[0].value = (XtArgVal) &w;
1643 shellArgs[1].value = (XtArgVal) &h;
1644 XtGetValues(shellWidget, shellArgs, 2);
1646 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1647 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1648 XtSetValues(shellWidget, &shellArgs[2], 4);
1650 XtSetArg(args[0], XtNdefaultDistance, &sep);
1651 XtGetValues(formWidget, args, 1);
1653 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1654 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1656 hOffset = boardWidth + 10;
1657 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1658 secondSegments[i] = gridSegments[i];
1659 secondSegments[i].x1 += hOffset;
1660 secondSegments[i].x2 += hOffset;
1663 XtSetArg(args[0], XtNwidth, boardWidth);
1664 XtSetArg(args[1], XtNheight, boardHeight);
1665 XtSetValues(boardWidget, args, 2);
1667 timerWidth = (boardWidth - sep) / 2;
1668 XtSetArg(args[0], XtNwidth, timerWidth);
1669 XtSetValues(whiteTimerWidget, args, 1);
1670 XtSetValues(blackTimerWidget, args, 1);
1672 XawFormDoLayout(formWidget, False);
1674 if (appData.titleInWindow) {
1676 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1677 XtSetArg(args[i], XtNheight, &h); i++;
1678 XtGetValues(titleWidget, args, i);
1680 w = boardWidth - 2*bor;
1682 XtSetArg(args[0], XtNwidth, &w);
1683 XtGetValues(menuBarWidget, args, 1);
1684 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1687 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1688 if (gres != XtGeometryYes && appData.debugMode) {
1690 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1691 programName, gres, w, h, wr, hr);
1695 XawFormDoLayout(formWidget, True);
1698 * Inhibit shell resizing.
1700 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1701 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1702 shellArgs[4].value = shellArgs[2].value = w;
1703 shellArgs[5].value = shellArgs[3].value = h;
1704 XtSetValues(shellWidget, &shellArgs[0], 6);
1706 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1709 for(i=0; i<4; i++) {
1711 for(p=0; p<=(int)WhiteKing; p++)
1712 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1713 if(gameInfo.variant == VariantShogi) {
1714 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1715 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1716 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1717 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1718 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1721 if(gameInfo.variant == VariantGothic) {
1722 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1725 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1726 xpmPieceBitmap[i][(int)WhiteAngel] = xpmPieceBitmap2[i][(int)WhiteFalcon];
1727 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1730 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1731 for(p=0; p<=(int)WhiteKing; p++)
1732 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1733 if(gameInfo.variant == VariantShogi) {
1734 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1735 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1736 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1737 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1738 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1741 if(gameInfo.variant == VariantGothic) {
1742 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1745 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1746 ximMaskPm[(int)WhiteAngel] = ximMaskPm2[(int)WhiteFalcon];
1747 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1752 for(i=0; i<2; i++) {
1754 for(p=0; p<=(int)WhiteKing; p++)
1755 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1756 if(gameInfo.variant == VariantShogi) {
1757 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1758 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1759 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1760 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1761 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1764 if(gameInfo.variant == VariantGothic) {
1765 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1768 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1769 pieceBitmap[i][(int)WhiteAngel] = pieceBitmap2[i][(int)WhiteFalcon];
1770 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1785 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1786 XSetWindowAttributes window_attributes;
1788 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1789 XrmValue vFrom, vTo;
1790 XtGeometryResult gres;
1793 int forceMono = False;
1795 srandom(time(0)); // [HGM] book: make random truly random
1797 setbuf(stdout, NULL);
1798 setbuf(stderr, NULL);
1801 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1802 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1806 programName = strrchr(argv[0], '/');
1807 if (programName == NULL)
1808 programName = argv[0];
1813 XtSetLanguageProc(NULL, NULL, NULL);
1814 bindtextdomain(PACKAGE, LOCALEDIR);
1815 textdomain(PACKAGE);
1819 XtAppInitialize(&appContext, "XBoard", shellOptions,
1820 XtNumber(shellOptions),
1821 &argc, argv, xboardResources, NULL, 0);
1822 appData.boardSize = "";
1823 InitAppData(ConvertToLine(argc, argv));
1825 if (p == NULL) p = "/tmp";
1826 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1827 gameCopyFilename = (char*) malloc(i);
1828 gamePasteFilename = (char*) malloc(i);
1829 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1830 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1832 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1833 clientResources, XtNumber(clientResources),
1836 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1837 static char buf[MSG_SIZ];
1838 EscapeExpand(buf, appData.initString);
1839 appData.initString = strdup(buf);
1840 EscapeExpand(buf, appData.secondInitString);
1841 appData.secondInitString = strdup(buf);
1842 EscapeExpand(buf, appData.firstComputerString);
1843 appData.firstComputerString = strdup(buf);
1844 EscapeExpand(buf, appData.secondComputerString);
1845 appData.secondComputerString = strdup(buf);
1848 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1851 if (chdir(chessDir) != 0) {
1852 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1858 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1859 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1860 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1861 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1864 setbuf(debugFP, NULL);
1867 /* [HGM,HR] make sure board size is acceptable */
1868 if(appData.NrFiles > BOARD_FILES ||
1869 appData.NrRanks > BOARD_RANKS )
1870 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1873 /* This feature does not work; animation needs a rewrite */
1874 appData.highlightDragging = FALSE;
1878 xDisplay = XtDisplay(shellWidget);
1879 xScreen = DefaultScreen(xDisplay);
1880 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1882 gameInfo.variant = StringToVariant(appData.variant);
1883 InitPosition(FALSE);
1886 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1888 if (isdigit(appData.boardSize[0])) {
1889 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1890 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1891 &fontPxlSize, &smallLayout, &tinyLayout);
1893 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1894 programName, appData.boardSize);
1898 /* Find some defaults; use the nearest known size */
1899 SizeDefaults *szd, *nearest;
1900 int distance = 99999;
1901 nearest = szd = sizeDefaults;
1902 while (szd->name != NULL) {
1903 if (abs(szd->squareSize - squareSize) < distance) {
1905 distance = abs(szd->squareSize - squareSize);
1906 if (distance == 0) break;
1910 if (i < 2) lineGap = nearest->lineGap;
1911 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1912 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1913 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1914 if (i < 6) smallLayout = nearest->smallLayout;
1915 if (i < 7) tinyLayout = nearest->tinyLayout;
1918 SizeDefaults *szd = sizeDefaults;
1919 if (*appData.boardSize == NULLCHAR) {
1920 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1921 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1924 if (szd->name == NULL) szd--;
1925 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1927 while (szd->name != NULL &&
1928 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1929 if (szd->name == NULL) {
1930 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1931 programName, appData.boardSize);
1935 squareSize = szd->squareSize;
1936 lineGap = szd->lineGap;
1937 clockFontPxlSize = szd->clockFontPxlSize;
1938 coordFontPxlSize = szd->coordFontPxlSize;
1939 fontPxlSize = szd->fontPxlSize;
1940 smallLayout = szd->smallLayout;
1941 tinyLayout = szd->tinyLayout;
1942 // [HGM] font: use defaults from settings file if available and not overruled
1944 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
1945 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
1946 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
1947 appData.font = fontTable[MESSAGE_FONT][squareSize];
1948 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
1949 appData.coordFont = fontTable[COORD_FONT][squareSize];
1951 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1952 if (strlen(appData.pixmapDirectory) > 0) {
1953 p = ExpandPathName(appData.pixmapDirectory);
1955 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1956 appData.pixmapDirectory);
1959 if (appData.debugMode) {
1960 fprintf(stderr, _("\
1961 XBoard square size (hint): %d\n\
1962 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1964 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1965 if (appData.debugMode) {
1966 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1969 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1971 /* [HR] height treated separately (hacked) */
1972 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1973 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1974 if (appData.showJail == 1) {
1975 /* Jail on top and bottom */
1976 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1977 XtSetArg(boardArgs[2], XtNheight,
1978 boardHeight + 2*(lineGap + squareSize));
1979 } else if (appData.showJail == 2) {
1981 XtSetArg(boardArgs[1], XtNwidth,
1982 boardWidth + 2*(lineGap + squareSize));
1983 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1986 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1987 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1991 * Determine what fonts to use.
1993 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1994 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1995 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1996 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1997 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1998 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1999 appData.font = FindFont(appData.font, fontPxlSize);
2000 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
2001 countFontStruct = XQueryFont(xDisplay, countFontID);
2002 // appData.font = FindFont(appData.font, fontPxlSize);
2004 xdb = XtDatabase(xDisplay);
2005 XrmPutStringResource(&xdb, "*font", appData.font);
2008 * Detect if there are not enough colors available and adapt.
2010 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2011 appData.monoMode = True;
2014 if (!appData.monoMode) {
2015 vFrom.addr = (caddr_t) appData.lightSquareColor;
2016 vFrom.size = strlen(appData.lightSquareColor);
2017 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2018 if (vTo.addr == NULL) {
2019 appData.monoMode = True;
2022 lightSquareColor = *(Pixel *) vTo.addr;
2025 if (!appData.monoMode) {
2026 vFrom.addr = (caddr_t) appData.darkSquareColor;
2027 vFrom.size = strlen(appData.darkSquareColor);
2028 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2029 if (vTo.addr == NULL) {
2030 appData.monoMode = True;
2033 darkSquareColor = *(Pixel *) vTo.addr;
2036 if (!appData.monoMode) {
2037 vFrom.addr = (caddr_t) appData.whitePieceColor;
2038 vFrom.size = strlen(appData.whitePieceColor);
2039 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2040 if (vTo.addr == NULL) {
2041 appData.monoMode = True;
2044 whitePieceColor = *(Pixel *) vTo.addr;
2047 if (!appData.monoMode) {
2048 vFrom.addr = (caddr_t) appData.blackPieceColor;
2049 vFrom.size = strlen(appData.blackPieceColor);
2050 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2051 if (vTo.addr == NULL) {
2052 appData.monoMode = True;
2055 blackPieceColor = *(Pixel *) vTo.addr;
2059 if (!appData.monoMode) {
2060 vFrom.addr = (caddr_t) appData.highlightSquareColor;
2061 vFrom.size = strlen(appData.highlightSquareColor);
2062 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2063 if (vTo.addr == NULL) {
2064 appData.monoMode = True;
2067 highlightSquareColor = *(Pixel *) vTo.addr;
2071 if (!appData.monoMode) {
2072 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
2073 vFrom.size = strlen(appData.premoveHighlightColor);
2074 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2075 if (vTo.addr == NULL) {
2076 appData.monoMode = True;
2079 premoveHighlightColor = *(Pixel *) vTo.addr;
2084 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2087 if (appData.bitmapDirectory == NULL ||
2088 appData.bitmapDirectory[0] == NULLCHAR)
2089 appData.bitmapDirectory = DEF_BITMAP_DIR;
2092 if (appData.lowTimeWarning && !appData.monoMode) {
2093 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2094 vFrom.size = strlen(appData.lowTimeWarningColor);
2095 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2096 if (vTo.addr == NULL)
2097 appData.monoMode = True;
2099 lowTimeWarningColor = *(Pixel *) vTo.addr;
2102 if (appData.monoMode && appData.debugMode) {
2103 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2104 (unsigned long) XWhitePixel(xDisplay, xScreen),
2105 (unsigned long) XBlackPixel(xDisplay, xScreen));
2108 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2109 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2110 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2111 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2112 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2113 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2114 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2115 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2116 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2117 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2119 if (appData.colorize) {
2121 _("%s: can't parse color names; disabling colorization\n"),
2124 appData.colorize = FALSE;
2126 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2127 textColors[ColorNone].attr = 0;
2129 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2135 layoutName = "tinyLayout";
2136 } else if (smallLayout) {
2137 layoutName = "smallLayout";
2139 layoutName = "normalLayout";
2141 /* Outer layoutWidget is there only to provide a name for use in
2142 resources that depend on the layout style */
2144 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2145 layoutArgs, XtNumber(layoutArgs));
2147 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2148 formArgs, XtNumber(formArgs));
2149 XtSetArg(args[0], XtNdefaultDistance, &sep);
2150 XtGetValues(formWidget, args, 1);
2153 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2154 XtSetArg(args[0], XtNtop, XtChainTop);
2155 XtSetArg(args[1], XtNbottom, XtChainTop);
2156 XtSetArg(args[2], XtNright, XtChainLeft);
2157 XtSetValues(menuBarWidget, args, 3);
2159 widgetList[j++] = whiteTimerWidget =
2160 XtCreateWidget("whiteTime", labelWidgetClass,
2161 formWidget, timerArgs, XtNumber(timerArgs));
2162 XtSetArg(args[0], XtNfont, clockFontStruct);
2163 XtSetArg(args[1], XtNtop, XtChainTop);
2164 XtSetArg(args[2], XtNbottom, XtChainTop);
2165 XtSetValues(whiteTimerWidget, args, 3);
2167 widgetList[j++] = blackTimerWidget =
2168 XtCreateWidget("blackTime", labelWidgetClass,
2169 formWidget, timerArgs, XtNumber(timerArgs));
2170 XtSetArg(args[0], XtNfont, clockFontStruct);
2171 XtSetArg(args[1], XtNtop, XtChainTop);
2172 XtSetArg(args[2], XtNbottom, XtChainTop);
2173 XtSetValues(blackTimerWidget, args, 3);
2175 if (appData.titleInWindow) {
2176 widgetList[j++] = titleWidget =
2177 XtCreateWidget("title", labelWidgetClass, formWidget,
2178 titleArgs, XtNumber(titleArgs));
2179 XtSetArg(args[0], XtNtop, XtChainTop);
2180 XtSetArg(args[1], XtNbottom, XtChainTop);
2181 XtSetValues(titleWidget, args, 2);
2184 if (appData.showButtonBar) {
2185 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2186 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2187 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2188 XtSetArg(args[2], XtNtop, XtChainTop);
2189 XtSetArg(args[3], XtNbottom, XtChainTop);
2190 XtSetValues(buttonBarWidget, args, 4);
2193 widgetList[j++] = messageWidget =
2194 XtCreateWidget("message", labelWidgetClass, formWidget,
2195 messageArgs, XtNumber(messageArgs));
2196 XtSetArg(args[0], XtNtop, XtChainTop);
2197 XtSetArg(args[1], XtNbottom, XtChainTop);
2198 XtSetValues(messageWidget, args, 2);
2200 widgetList[j++] = boardWidget =
2201 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2202 XtNumber(boardArgs));
2204 XtManageChildren(widgetList, j);
2206 timerWidth = (boardWidth - sep) / 2;
2207 XtSetArg(args[0], XtNwidth, timerWidth);
2208 XtSetValues(whiteTimerWidget, args, 1);
2209 XtSetValues(blackTimerWidget, args, 1);
2211 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2212 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2213 XtGetValues(whiteTimerWidget, args, 2);
2215 if (appData.showButtonBar) {
2216 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2217 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2218 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2222 * formWidget uses these constraints but they are stored
2226 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2227 XtSetValues(menuBarWidget, args, i);
2228 if (appData.titleInWindow) {
2231 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2232 XtSetValues(whiteTimerWidget, args, i);
2234 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2235 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2236 XtSetValues(blackTimerWidget, args, i);
2238 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2239 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2240 XtSetValues(titleWidget, args, i);
2242 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2243 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2244 XtSetValues(messageWidget, args, i);
2245 if (appData.showButtonBar) {
2247 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2248 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2249 XtSetValues(buttonBarWidget, args, i);
2253 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2254 XtSetValues(whiteTimerWidget, args, i);
2256 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2257 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2258 XtSetValues(blackTimerWidget, args, i);
2260 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2261 XtSetValues(titleWidget, args, i);
2263 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2264 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2265 XtSetValues(messageWidget, args, i);
2266 if (appData.showButtonBar) {
2268 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2269 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2270 XtSetValues(buttonBarWidget, args, i);
2275 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2276 XtSetValues(whiteTimerWidget, args, i);
2278 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2279 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2280 XtSetValues(blackTimerWidget, 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);
2293 XtSetArg(args[0], XtNfromVert, messageWidget);
2294 XtSetArg(args[1], XtNtop, XtChainTop);
2295 XtSetArg(args[2], XtNbottom, XtChainBottom);
2296 XtSetArg(args[3], XtNleft, XtChainLeft);
2297 XtSetArg(args[4], XtNright, XtChainRight);
2298 XtSetValues(boardWidget, args, 5);
2300 XtRealizeWidget(shellWidget);
2303 XtSetArg(args[0], XtNx, wpMain.x);
2304 XtSetArg(args[1], XtNy, wpMain.y);
2305 XtSetValues(shellWidget, args, 2);
2309 * Correct the width of the message and title widgets.
2310 * It is not known why some systems need the extra fudge term.
2311 * The value "2" is probably larger than needed.
2313 XawFormDoLayout(formWidget, False);
2315 #define WIDTH_FUDGE 2
2317 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2318 XtSetArg(args[i], XtNheight, &h); i++;
2319 XtGetValues(messageWidget, args, i);
2320 if (appData.showButtonBar) {
2322 XtSetArg(args[i], XtNwidth, &w); i++;
2323 XtGetValues(buttonBarWidget, args, i);
2324 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2326 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2329 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2330 if (gres != XtGeometryYes && appData.debugMode) {
2331 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2332 programName, gres, w, h, wr, hr);
2335 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2336 /* The size used for the child widget in layout lags one resize behind
2337 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2339 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2340 if (gres != XtGeometryYes && appData.debugMode) {
2341 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2342 programName, gres, w, h, wr, hr);
2345 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2346 XtSetArg(args[1], XtNright, XtChainRight);
2347 XtSetValues(messageWidget, args, 2);
2349 if (appData.titleInWindow) {
2351 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2352 XtSetArg(args[i], XtNheight, &h); i++;
2353 XtGetValues(titleWidget, args, i);
2355 w = boardWidth - 2*bor;
2357 XtSetArg(args[0], XtNwidth, &w);
2358 XtGetValues(menuBarWidget, args, 1);
2359 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2362 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2363 if (gres != XtGeometryYes && appData.debugMode) {
2365 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2366 programName, gres, w, h, wr, hr);
2369 XawFormDoLayout(formWidget, True);
2371 xBoardWindow = XtWindow(boardWidget);
2373 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2374 // not need to go into InitDrawingSizes().
2378 * Create X checkmark bitmap and initialize option menu checks.
2380 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2381 checkmark_bits, checkmark_width, checkmark_height);
2382 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2383 if (appData.alwaysPromoteToQueen) {
2384 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2387 if (appData.animateDragging) {
2388 XtSetValues(XtNameToWidget(menuBarWidget,
2389 "menuOptions.Animate Dragging"),
2392 if (appData.animate) {
2393 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2396 if (appData.autoCallFlag) {
2397 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2400 if (appData.autoFlipView) {
2401 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2404 if (appData.blindfold) {
2405 XtSetValues(XtNameToWidget(menuBarWidget,
2406 "menuOptions.Blindfold"), args, 1);
2408 if (appData.flashCount > 0) {
2409 XtSetValues(XtNameToWidget(menuBarWidget,
2410 "menuOptions.Flash Moves"),
2414 if (appData.highlightDragging) {
2415 XtSetValues(XtNameToWidget(menuBarWidget,
2416 "menuOptions.Highlight Dragging"),
2420 if (appData.highlightLastMove) {
2421 XtSetValues(XtNameToWidget(menuBarWidget,
2422 "menuOptions.Highlight Last Move"),
2425 if (appData.highlightMoveWithArrow) {
2426 XtSetValues(XtNameToWidget(menuBarWidget,
2427 "menuOptions.Arrow"),
2430 // if (appData.icsAlarm) {
2431 // XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2434 if (appData.ringBellAfterMoves) {
2435 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2438 if (appData.oneClick) {
2439 XtSetValues(XtNameToWidget(menuBarWidget,
2440 "menuOptions.OneClick"), args, 1);
2442 if (appData.periodicUpdates) {
2443 XtSetValues(XtNameToWidget(menuBarWidget,
2444 "menuOptions.Periodic Updates"), args, 1);
2446 if (appData.ponderNextMove) {
2447 XtSetValues(XtNameToWidget(menuBarWidget,
2448 "menuOptions.Ponder Next Move"), args, 1);
2450 if (appData.popupExitMessage) {
2451 XtSetValues(XtNameToWidget(menuBarWidget,
2452 "menuOptions.Popup Exit Message"), args, 1);
2454 if (appData.popupMoveErrors) {
2455 XtSetValues(XtNameToWidget(menuBarWidget,
2456 "menuOptions.Popup Move Errors"), args, 1);
2458 // if (appData.premove) {
2459 // XtSetValues(XtNameToWidget(menuBarWidget,
2460 // "menuOptions.Premove"), args, 1);
2462 if (appData.showCoords) {
2463 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2466 if (appData.hideThinkingFromHuman) {
2467 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2470 if (appData.testLegality) {
2471 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2474 if (saveSettingsOnExit) {
2475 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2482 ReadBitmap(&wIconPixmap, "icon_white.bm",
2483 icon_white_bits, icon_white_width, icon_white_height);
2484 ReadBitmap(&bIconPixmap, "icon_black.bm",
2485 icon_black_bits, icon_black_width, icon_black_height);
2486 iconPixmap = wIconPixmap;
2488 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2489 XtSetValues(shellWidget, args, i);
2492 * Create a cursor for the board widget.
2494 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2495 XChangeWindowAttributes(xDisplay, xBoardWindow,
2496 CWCursor, &window_attributes);
2499 * Inhibit shell resizing.
2501 shellArgs[0].value = (XtArgVal) &w;
2502 shellArgs[1].value = (XtArgVal) &h;
2503 XtGetValues(shellWidget, shellArgs, 2);
2504 shellArgs[4].value = shellArgs[2].value = w;
2505 shellArgs[5].value = shellArgs[3].value = h;
2506 XtSetValues(shellWidget, &shellArgs[2], 4);
2507 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2508 marginH = h - boardHeight;
2510 CatchDeleteWindow(shellWidget, "QuitProc");
2515 if (appData.bitmapDirectory[0] != NULLCHAR) {
2519 CreateXPMBoard(appData.liteBackTextureFile, 1);
2520 CreateXPMBoard(appData.darkBackTextureFile, 0);
2524 /* Create regular pieces */
2525 if (!useImages) CreatePieces();
2530 if (appData.animate || appData.animateDragging)
2533 XtAugmentTranslations(formWidget,
2534 XtParseTranslationTable(globalTranslations));
2535 XtAugmentTranslations(boardWidget,
2536 XtParseTranslationTable(boardTranslations));
2537 XtAugmentTranslations(whiteTimerWidget,
2538 XtParseTranslationTable(whiteTranslations));
2539 XtAugmentTranslations(blackTimerWidget,
2540 XtParseTranslationTable(blackTranslations));
2542 /* Why is the following needed on some versions of X instead
2543 * of a translation? */
2544 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2545 (XtEventHandler) EventProc, NULL);
2548 /* [AS] Restore layout */
2549 if( wpMoveHistory.visible ) {
2553 if( wpEvalGraph.visible )
2558 if( wpEngineOutput.visible ) {
2559 EngineOutputPopUp();
2564 if (errorExitStatus == -1) {
2565 if (appData.icsActive) {
2566 /* We now wait until we see "login:" from the ICS before
2567 sending the logon script (problems with timestamp otherwise) */
2568 /*ICSInitScript();*/
2569 if (appData.icsInputBox) ICSInputBoxPopUp();
2573 signal(SIGWINCH, TermSizeSigHandler);
2575 signal(SIGINT, IntSigHandler);
2576 signal(SIGTERM, IntSigHandler);
2577 if (*appData.cmailGameName != NULLCHAR) {
2578 signal(SIGUSR1, CmailSigHandler);
2581 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2583 XtSetKeyboardFocus(shellWidget, formWidget);
2585 XtAppMainLoop(appContext);
2586 if (appData.debugMode) fclose(debugFP); // [DM] debug
2593 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2594 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2596 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2597 unlink(gameCopyFilename);
2598 unlink(gamePasteFilename);
2601 RETSIGTYPE TermSizeSigHandler(int sig)
2614 CmailSigHandler(sig)
2620 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2622 /* Activate call-back function CmailSigHandlerCallBack() */
2623 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2625 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2629 CmailSigHandlerCallBack(isr, closure, message, count, error)
2637 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2639 /**** end signal code ****/
2645 /* try to open the icsLogon script, either in the location given
2646 * or in the users HOME directory
2653 f = fopen(appData.icsLogon, "r");
2656 homedir = getenv("HOME");
2657 if (homedir != NULL)
2659 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2660 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2661 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2662 f = fopen(buf, "r");
2667 ProcessICSInitScript(f);
2669 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2678 EditCommentPopDown();
2693 if (!menuBarWidget) return;
2694 w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2696 DisplayError("menuEdit.Revert", 0);
2698 XtSetSensitive(w, !grey);
2700 w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2702 DisplayError("menuEdit.Annotate", 0);
2704 XtSetSensitive(w, !grey);
2709 SetMenuEnables(enab)
2713 if (!menuBarWidget) return;
2714 while (enab->name != NULL) {
2715 w = XtNameToWidget(menuBarWidget, enab->name);
2717 DisplayError(enab->name, 0);
2719 XtSetSensitive(w, enab->value);
2725 Enables icsEnables[] = {
2726 { "menuFile.Mail Move", False },
2727 { "menuFile.Reload CMail Message", False },
2728 { "menuMode.Machine Black", False },
2729 { "menuMode.Machine White", False },
2730 { "menuMode.Analysis Mode", False },
2731 { "menuMode.Analyze File", False },
2732 { "menuMode.Two Machines", False },
2734 { "menuEngine.Hint", False },
2735 { "menuEngine.Book", False },
2736 { "menuEngine.Move Now", False },
2737 { "menuOptions.Periodic Updates", False },
2738 { "menuOptions.Hide Thinking", False },
2739 { "menuOptions.Ponder Next Move", False },
2740 { "menuEngine.Engine #1 Settings", False },
2742 { "menuEngine.Engine #2 Settings", False },
2743 { "menuEdit.Annotate", False },
2747 Enables ncpEnables[] = {
2748 { "menuFile.Mail Move", False },
2749 { "menuFile.Reload CMail Message", False },
2750 { "menuMode.Machine White", False },
2751 { "menuMode.Machine Black", False },
2752 { "menuMode.Analysis Mode", False },
2753 { "menuMode.Analyze File", False },
2754 { "menuMode.Two Machines", False },
2755 { "menuMode.ICS Client", False },
2756 { "menuView.ICS Input Box", False },
2757 { "Action", False },
2758 { "menuEdit.Revert", False },
2759 { "menuEdit.Annotate", False },
2760 { "menuEngine.Engine #1 Settings", False },
2761 { "menuEngine.Engine #2 Settings", False },
2762 { "menuEngine.Move Now", False },
2763 { "menuEngine.Retract Move", False },
2764 { "menuOptions.Auto Flag", False },
2765 { "menuOptions.Auto Flip View", False },
2766 // { "menuOptions.ICS Alarm", False },
2767 { "menuOptions.Move Sound", False },
2768 { "menuOptions.Hide Thinking", False },
2769 { "menuOptions.Periodic Updates", False },
2770 { "menuOptions.Ponder Next Move", False },
2771 { "menuEngine.Hint", False },
2772 { "menuEngine.Book", False },
2776 Enables gnuEnables[] = {
2777 { "menuMode.ICS Client", False },
2778 { "menuView.ICS Input Box", False },
2779 { "menuAction.Accept", False },
2780 { "menuAction.Decline", False },
2781 { "menuAction.Rematch", False },
2782 { "menuAction.Adjourn", False },
2783 { "menuAction.Stop Examining", False },
2784 { "menuAction.Stop Observing", False },
2785 { "menuAction.Upload to Examine", False },
2786 { "menuEdit.Revert", False },
2787 { "menuEdit.Annotate", False },
2789 /* The next two options rely on SetCmailMode being called *after* */
2790 /* SetGNUMode so that when GNU is being used to give hints these */
2791 /* menu options are still available */
2793 { "menuFile.Mail Move", False },
2794 { "menuFile.Reload CMail Message", False },
2798 Enables cmailEnables[] = {
2800 { "menuAction.Call Flag", False },
2801 { "menuAction.Draw", True },
2802 { "menuAction.Adjourn", False },
2803 { "menuAction.Abort", False },
2804 { "menuAction.Stop Observing", False },
2805 { "menuAction.Stop Examining", False },
2806 { "menuFile.Mail Move", True },
2807 { "menuFile.Reload CMail Message", True },
2811 Enables trainingOnEnables[] = {
2812 { "menuMode.Edit Comment", False },
2813 { "menuMode.Pause", False },
2814 { "menuEdit.Forward", False },
2815 { "menuEdit.Backward", False },
2816 { "menuEdit.Forward to End", False },
2817 { "menuEdit.Back to Start", False },
2818 { "menuEngine.Move Now", False },
2819 { "menuEdit.Truncate Game", False },
2823 Enables trainingOffEnables[] = {
2824 { "menuMode.Edit Comment", True },
2825 { "menuMode.Pause", True },
2826 { "menuEdit.Forward", True },
2827 { "menuEdit.Backward", True },
2828 { "menuEdit.Forward to End", True },
2829 { "menuEdit.Back to Start", True },
2830 { "menuEngine.Move Now", True },
2831 { "menuEdit.Truncate Game", True },
2835 Enables machineThinkingEnables[] = {
2836 { "menuFile.Load Game", False },
2837 // { "menuFile.Load Next Game", False },
2838 // { "menuFile.Load Previous Game", False },
2839 // { "menuFile.Reload Same Game", False },
2840 { "menuEdit.Paste Game", False },
2841 { "menuFile.Load Position", False },
2842 // { "menuFile.Load Next Position", False },
2843 // { "menuFile.Load Previous Position", False },
2844 // { "menuFile.Reload Same Position", False },
2845 { "menuEdit.Paste Position", False },
2846 { "menuMode.Machine White", False },
2847 { "menuMode.Machine Black", False },
2848 { "menuMode.Two Machines", False },
2849 { "menuEngine.Retract Move", False },
2853 Enables userThinkingEnables[] = {
2854 { "menuFile.Load Game", True },
2855 // { "menuFile.Load Next Game", True },
2856 // { "menuFile.Load Previous Game", True },
2857 // { "menuFile.Reload Same Game", True },
2858 { "menuEdit.Paste Game", True },
2859 { "menuFile.Load Position", True },
2860 // { "menuFile.Load Next Position", True },
2861 // { "menuFile.Load Previous Position", True },
2862 // { "menuFile.Reload Same Position", True },
2863 { "menuEdit.Paste Position", True },
2864 { "menuMode.Machine White", True },
2865 { "menuMode.Machine Black", True },
2866 { "menuMode.Two Machines", True },
2867 { "menuEngine.Retract Move", True },
2873 SetMenuEnables(icsEnables);
2876 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2877 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2884 SetMenuEnables(ncpEnables);
2890 SetMenuEnables(gnuEnables);
2896 SetMenuEnables(cmailEnables);
2902 SetMenuEnables(trainingOnEnables);
2903 if (appData.showButtonBar) {
2904 XtSetSensitive(buttonBarWidget, False);
2910 SetTrainingModeOff()
2912 SetMenuEnables(trainingOffEnables);
2913 if (appData.showButtonBar) {
2914 XtSetSensitive(buttonBarWidget, True);
2919 SetUserThinkingEnables()
2921 if (appData.noChessProgram) return;
2922 SetMenuEnables(userThinkingEnables);
2926 SetMachineThinkingEnables()
2928 if (appData.noChessProgram) return;
2929 SetMenuEnables(machineThinkingEnables);
2931 case MachinePlaysBlack:
2932 case MachinePlaysWhite:
2933 case TwoMachinesPlay:
2934 XtSetSensitive(XtNameToWidget(menuBarWidget,
2935 ModeToWidgetName(gameMode)), True);
2942 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2943 #define HISTORY_SIZE 64
2944 static char *history[HISTORY_SIZE];
2945 int histIn = 0, histP = 0;
2948 SaveInHistory(char *cmd)
2950 if (history[histIn] != NULL) {
2951 free(history[histIn]);
2952 history[histIn] = NULL;
2954 if (*cmd == NULLCHAR) return;
2955 history[histIn] = StrSave(cmd);
2956 histIn = (histIn + 1) % HISTORY_SIZE;
2957 if (history[histIn] != NULL) {
2958 free(history[histIn]);
2959 history[histIn] = NULL;
2965 PrevInHistory(char *cmd)
2968 if (histP == histIn) {
2969 if (history[histIn] != NULL) free(history[histIn]);
2970 history[histIn] = StrSave(cmd);
2972 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
2973 if (newhp == histIn || history[newhp] == NULL) return NULL;
2975 return history[histP];
2981 if (histP == histIn) return NULL;
2982 histP = (histP + 1) % HISTORY_SIZE;
2983 return history[histP];
2985 // end of borrowed code
2987 #define Abs(n) ((n)<0 ? -(n) : (n))
2990 * Find a font that matches "pattern" that is as close as
2991 * possible to the targetPxlSize. Prefer fonts that are k
2992 * pixels smaller to fonts that are k pixels larger. The
2993 * pattern must be in the X Consortium standard format,
2994 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2995 * The return value should be freed with XtFree when no
2999 FindFont(pattern, targetPxlSize)
3003 char **fonts, *p, *best, *scalable, *scalableTail;
3004 int i, j, nfonts, minerr, err, pxlSize;
3007 char **missing_list;
3009 char *def_string, *base_fnt_lst, strInt[3];
3011 XFontStruct **fnt_list;
3013 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3014 snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize);
3015 p = strstr(pattern, "--");
3016 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3017 strcat(base_fnt_lst, strInt);
3018 strcat(base_fnt_lst, strchr(p + 2, '-'));
3020 if ((fntSet = XCreateFontSet(xDisplay,
3024 &def_string)) == NULL) {
3026 fprintf(stderr, _("Unable to create font set.\n"));
3030 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3032 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3034 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3035 programName, pattern);
3043 for (i=0; i<nfonts; i++) {
3046 if (*p != '-') continue;
3048 if (*p == NULLCHAR) break;
3049 if (*p++ == '-') j++;
3051 if (j < 7) continue;
3054 scalable = fonts[i];
3057 err = pxlSize - targetPxlSize;
3058 if (Abs(err) < Abs(minerr) ||
3059 (minerr > 0 && err < 0 && -err == minerr)) {
3065 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3066 /* If the error is too big and there is a scalable font,
3067 use the scalable font. */
3068 int headlen = scalableTail - scalable;
3069 p = (char *) XtMalloc(strlen(scalable) + 10);
3070 while (isdigit(*scalableTail)) scalableTail++;
3071 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3073 p = (char *) XtMalloc(strlen(best) + 2);
3074 safeStrCpy(p, best, strlen(best)+1 );
3076 if (appData.debugMode) {
3077 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3078 pattern, targetPxlSize, p);
3081 if (missing_count > 0)
3082 XFreeStringList(missing_list);
3083 XFreeFontSet(xDisplay, fntSet);
3085 XFreeFontNames(fonts);
3092 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3093 | GCBackground | GCFunction | GCPlaneMask;
3094 XGCValues gc_values;
3097 gc_values.plane_mask = AllPlanes;
3098 gc_values.line_width = lineGap;
3099 gc_values.line_style = LineSolid;
3100 gc_values.function = GXcopy;
3102 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3103 gc_values.background = XBlackPixel(xDisplay, xScreen);
3104 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3106 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3107 gc_values.background = XWhitePixel(xDisplay, xScreen);
3108 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3109 XSetFont(xDisplay, coordGC, coordFontID);
3111 // [HGM] make font for holdings counts (white on black0
3112 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3113 gc_values.background = XBlackPixel(xDisplay, xScreen);
3114 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3115 XSetFont(xDisplay, countGC, countFontID);
3117 if (appData.monoMode) {
3118 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3119 gc_values.background = XWhitePixel(xDisplay, xScreen);
3120 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3122 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3123 gc_values.background = XBlackPixel(xDisplay, xScreen);
3124 lightSquareGC = wbPieceGC
3125 = XtGetGC(shellWidget, value_mask, &gc_values);
3127 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3128 gc_values.background = XWhitePixel(xDisplay, xScreen);
3129 darkSquareGC = bwPieceGC
3130 = XtGetGC(shellWidget, value_mask, &gc_values);
3132 if (DefaultDepth(xDisplay, xScreen) == 1) {
3133 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3134 gc_values.function = GXcopyInverted;
3135 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3136 gc_values.function = GXcopy;
3137 if (XBlackPixel(xDisplay, xScreen) == 1) {
3138 bwPieceGC = darkSquareGC;
3139 wbPieceGC = copyInvertedGC;
3141 bwPieceGC = copyInvertedGC;
3142 wbPieceGC = lightSquareGC;
3146 gc_values.foreground = highlightSquareColor;
3147 gc_values.background = highlightSquareColor;
3148 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3150 gc_values.foreground = premoveHighlightColor;
3151 gc_values.background = premoveHighlightColor;
3152 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3154 gc_values.foreground = lightSquareColor;
3155 gc_values.background = darkSquareColor;
3156 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3158 gc_values.foreground = darkSquareColor;
3159 gc_values.background = lightSquareColor;
3160 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3162 gc_values.foreground = jailSquareColor;
3163 gc_values.background = jailSquareColor;
3164 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3166 gc_values.foreground = whitePieceColor;
3167 gc_values.background = darkSquareColor;
3168 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3170 gc_values.foreground = whitePieceColor;
3171 gc_values.background = lightSquareColor;
3172 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3174 gc_values.foreground = whitePieceColor;
3175 gc_values.background = jailSquareColor;
3176 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3178 gc_values.foreground = blackPieceColor;
3179 gc_values.background = darkSquareColor;
3180 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3182 gc_values.foreground = blackPieceColor;
3183 gc_values.background = lightSquareColor;
3184 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3186 gc_values.foreground = blackPieceColor;
3187 gc_values.background = jailSquareColor;
3188 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3192 void loadXIM(xim, xmask, filename, dest, mask)
3205 fp = fopen(filename, "rb");
3207 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3214 for (y=0; y<h; ++y) {
3215 for (x=0; x<h; ++x) {
3220 XPutPixel(xim, x, y, blackPieceColor);
3222 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3225 XPutPixel(xim, x, y, darkSquareColor);
3227 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3230 XPutPixel(xim, x, y, whitePieceColor);
3232 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3235 XPutPixel(xim, x, y, lightSquareColor);
3237 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3245 /* create Pixmap of piece */
3246 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3248 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3251 /* create Pixmap of clipmask
3252 Note: We assume the white/black pieces have the same
3253 outline, so we make only 6 masks. This is okay
3254 since the XPM clipmask routines do the same. */
3256 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3258 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3261 /* now create the 1-bit version */
3262 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3265 values.foreground = 1;
3266 values.background = 0;
3268 /* Don't use XtGetGC, not read only */
3269 maskGC = XCreateGC(xDisplay, *mask,
3270 GCForeground | GCBackground, &values);
3271 XCopyPlane(xDisplay, temp, *mask, maskGC,
3272 0, 0, squareSize, squareSize, 0, 0, 1);
3273 XFreePixmap(xDisplay, temp);
3278 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3280 void CreateXIMPieces()
3285 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3290 /* The XSynchronize calls were copied from CreatePieces.
3291 Not sure if needed, but can't hurt */
3292 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3295 /* temp needed by loadXIM() */
3296 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3297 0, 0, ss, ss, AllPlanes, XYPixmap);
3299 if (strlen(appData.pixmapDirectory) == 0) {
3303 if (appData.monoMode) {
3304 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3308 fprintf(stderr, _("\nLoading XIMs...\n"));
3310 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3311 fprintf(stderr, "%d", piece+1);
3312 for (kind=0; kind<4; kind++) {
3313 fprintf(stderr, ".");
3314 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3315 ExpandPathName(appData.pixmapDirectory),
3316 piece <= (int) WhiteKing ? "" : "w",
3317 pieceBitmapNames[piece],
3319 ximPieceBitmap[kind][piece] =
3320 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3321 0, 0, ss, ss, AllPlanes, XYPixmap);
3322 if (appData.debugMode)
3323 fprintf(stderr, _("(File:%s:) "), buf);
3324 loadXIM(ximPieceBitmap[kind][piece],
3326 &(xpmPieceBitmap2[kind][piece]),
3327 &(ximMaskPm2[piece]));
3328 if(piece <= (int)WhiteKing)
3329 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3331 fprintf(stderr," ");
3333 /* Load light and dark squares */
3334 /* If the LSQ and DSQ pieces don't exist, we will
3335 draw them with solid squares. */
3336 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3337 if (access(buf, 0) != 0) {
3341 fprintf(stderr, _("light square "));
3343 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3344 0, 0, ss, ss, AllPlanes, XYPixmap);
3345 if (appData.debugMode)
3346 fprintf(stderr, _("(File:%s:) "), buf);
3348 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3349 fprintf(stderr, _("dark square "));
3350 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3351 ExpandPathName(appData.pixmapDirectory), ss);
3352 if (appData.debugMode)
3353 fprintf(stderr, _("(File:%s:) "), buf);
3355 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3356 0, 0, ss, ss, AllPlanes, XYPixmap);
3357 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3358 xpmJailSquare = xpmLightSquare;
3360 fprintf(stderr, _("Done.\n"));
3362 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3366 void CreateXPMBoard(char *s, int kind)
3370 if(s == NULL || *s == 0 || *s == '*') return;
3371 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3372 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3376 void CreateXPMPieces()
3380 u_int ss = squareSize;
3382 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3383 XpmColorSymbol symbols[4];
3385 /* The XSynchronize calls were copied from CreatePieces.
3386 Not sure if needed, but can't hurt */
3387 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3389 /* Setup translations so piece colors match square colors */
3390 symbols[0].name = "light_piece";
3391 symbols[0].value = appData.whitePieceColor;
3392 symbols[1].name = "dark_piece";
3393 symbols[1].value = appData.blackPieceColor;
3394 symbols[2].name = "light_square";
3395 symbols[2].value = appData.lightSquareColor;
3396 symbols[3].name = "dark_square";
3397 symbols[3].value = appData.darkSquareColor;
3399 attr.valuemask = XpmColorSymbols;
3400 attr.colorsymbols = symbols;
3401 attr.numsymbols = 4;
3403 if (appData.monoMode) {
3404 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3408 if (strlen(appData.pixmapDirectory) == 0) {
3409 XpmPieces* pieces = builtInXpms;
3412 while (pieces->size != squareSize && pieces->size) pieces++;
3413 if (!pieces->size) {
3414 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3417 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3418 for (kind=0; kind<4; kind++) {
3420 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3421 pieces->xpm[piece][kind],
3422 &(xpmPieceBitmap2[kind][piece]),
3423 NULL, &attr)) != 0) {
3424 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3428 if(piece <= (int) WhiteKing)
3429 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3433 xpmJailSquare = xpmLightSquare;
3437 fprintf(stderr, _("\nLoading XPMs...\n"));
3440 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3441 fprintf(stderr, "%d ", piece+1);
3442 for (kind=0; kind<4; kind++) {
3443 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3444 ExpandPathName(appData.pixmapDirectory),
3445 piece > (int) WhiteKing ? "w" : "",
3446 pieceBitmapNames[piece],
3448 if (appData.debugMode) {
3449 fprintf(stderr, _("(File:%s:) "), buf);
3451 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3452 &(xpmPieceBitmap2[kind][piece]),
3453 NULL, &attr)) != 0) {
3454 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3455 // [HGM] missing: read of unorthodox piece failed; substitute King.
3456 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3457 ExpandPathName(appData.pixmapDirectory),
3459 if (appData.debugMode) {
3460 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3462 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3463 &(xpmPieceBitmap2[kind][piece]),
3467 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3472 if(piece <= (int) WhiteKing)
3473 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3476 /* Load light and dark squares */
3477 /* If the LSQ and DSQ pieces don't exist, we will
3478 draw them with solid squares. */
3479 fprintf(stderr, _("light square "));
3480 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3481 if (access(buf, 0) != 0) {
3485 if (appData.debugMode)
3486 fprintf(stderr, _("(File:%s:) "), buf);
3488 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3489 &xpmLightSquare, NULL, &attr)) != 0) {
3490 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3493 fprintf(stderr, _("dark square "));
3494 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3495 ExpandPathName(appData.pixmapDirectory), ss);
3496 if (appData.debugMode) {
3497 fprintf(stderr, _("(File:%s:) "), buf);
3499 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3500 &xpmDarkSquare, NULL, &attr)) != 0) {
3501 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3505 xpmJailSquare = xpmLightSquare;
3506 fprintf(stderr, _("Done.\n"));
3508 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3511 #endif /* HAVE_LIBXPM */
3514 /* No built-in bitmaps */
3519 u_int ss = squareSize;
3521 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3524 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3525 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3526 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3527 pieceBitmapNames[piece],
3528 ss, kind == SOLID ? 's' : 'o');
3529 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3530 if(piece <= (int)WhiteKing)
3531 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3535 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3539 /* With built-in bitmaps */
3542 BuiltInBits* bib = builtInBits;
3545 u_int ss = squareSize;
3547 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3550 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3552 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3553 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3554 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3555 pieceBitmapNames[piece],
3556 ss, kind == SOLID ? 's' : 'o');
3557 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3558 bib->bits[kind][piece], ss, ss);
3559 if(piece <= (int)WhiteKing)
3560 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3564 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3569 void ReadBitmap(pm, name, bits, wreq, hreq)
3572 unsigned char bits[];
3578 char msg[MSG_SIZ], fullname[MSG_SIZ];
3580 if (*appData.bitmapDirectory != NULLCHAR) {
3581 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3582 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3583 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3584 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3585 &w, &h, pm, &x_hot, &y_hot);
3586 fprintf(stderr, "load %s\n", name);
3587 if (errcode != BitmapSuccess) {
3589 case BitmapOpenFailed:
3590 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3592 case BitmapFileInvalid:
3593 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3595 case BitmapNoMemory:
3596 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3600 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3604 fprintf(stderr, _("%s: %s...using built-in\n"),
3606 } else if (w != wreq || h != hreq) {
3608 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3609 programName, fullname, w, h, wreq, hreq);
3615 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3624 if (lineGap == 0) return;
3626 /* [HR] Split this into 2 loops for non-square boards. */
3628 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3629 gridSegments[i].x1 = 0;
3630 gridSegments[i].x2 =
3631 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3632 gridSegments[i].y1 = gridSegments[i].y2
3633 = lineGap / 2 + (i * (squareSize + lineGap));
3636 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3637 gridSegments[j + i].y1 = 0;
3638 gridSegments[j + i].y2 =
3639 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3640 gridSegments[j + i].x1 = gridSegments[j + i].x2
3641 = lineGap / 2 + (j * (squareSize + lineGap));
3645 static void MenuBarSelect(w, addr, index)
3650 XtActionProc proc = (XtActionProc) addr;
3652 (proc)(NULL, NULL, NULL, NULL);
3655 void CreateMenuBarPopup(parent, name, mb)
3665 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3668 XtSetArg(args[j], XtNleftMargin, 20); j++;
3669 XtSetArg(args[j], XtNrightMargin, 20); j++;
3671 while (mi->string != NULL) {
3672 if (strcmp(mi->string, "----") == 0) {
3673 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3676 XtSetArg(args[j], XtNlabel, XtNewString(mi->string));
3677 entry = XtCreateManagedWidget(mi->ref, smeBSBObjectClass,
3679 XtAddCallback(entry, XtNcallback,
3680 (XtCallbackProc) MenuBarSelect,
3681 (caddr_t) mi->proc);
3687 Widget CreateMenuBar(mb)
3691 Widget anchor, menuBar;
3693 char menuName[MSG_SIZ];
3696 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3697 XtSetArg(args[j], XtNvSpace, 0); j++;
3698 XtSetArg(args[j], XtNborderWidth, 0); j++;
3699 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3700 formWidget, args, j);
3702 while (mb->name != NULL) {
3703 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3704 strncat(menuName, mb->ref, MSG_SIZ - strlen(menuName) - 1);
3706 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3709 shortName[0] = mb->name[0];
3710 shortName[1] = NULLCHAR;
3711 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3714 XtSetArg(args[j], XtNlabel, XtNewString(mb->name)); j++;
3717 XtSetArg(args[j], XtNborderWidth, 0); j++;
3718 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3720 CreateMenuBarPopup(menuBar, menuName, mb);
3726 Widget CreateButtonBar(mi)
3730 Widget button, buttonBar;
3734 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3736 XtSetArg(args[j], XtNhSpace, 0); j++;
3738 XtSetArg(args[j], XtNborderWidth, 0); j++;
3739 XtSetArg(args[j], XtNvSpace, 0); j++;
3740 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3741 formWidget, args, j);
3743 while (mi->string != NULL) {
3746 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3747 XtSetArg(args[j], XtNborderWidth, 0); j++;
3749 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3750 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3751 buttonBar, args, j);
3752 XtAddCallback(button, XtNcallback,
3753 (XtCallbackProc) MenuBarSelect,
3754 (caddr_t) mi->proc);
3761 CreatePieceMenu(name, color)
3768 ChessSquare selection;
3770 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3771 boardWidget, args, 0);
3773 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3774 String item = pieceMenuStrings[color][i];
3776 if (strcmp(item, "----") == 0) {
3777 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3780 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3781 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3783 selection = pieceMenuTranslation[color][i];
3784 XtAddCallback(entry, XtNcallback,
3785 (XtCallbackProc) PieceMenuSelect,
3786 (caddr_t) selection);
3787 if (selection == WhitePawn || selection == BlackPawn) {
3788 XtSetArg(args[0], XtNpopupOnEntry, entry);
3789 XtSetValues(menu, args, 1);
3802 ChessSquare selection;
3804 whitePieceMenu = CreatePieceMenu("menuW", 0);
3805 blackPieceMenu = CreatePieceMenu("menuB", 1);
3807 XtRegisterGrabAction(PieceMenuPopup, True,
3808 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3809 GrabModeAsync, GrabModeAsync);
3811 XtSetArg(args[0], XtNlabel, _("Drop"));
3812 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3813 boardWidget, args, 1);
3814 for (i = 0; i < DROP_MENU_SIZE; i++) {
3815 String item = dropMenuStrings[i];
3817 if (strcmp(item, "----") == 0) {
3818 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3821 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3822 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3824 selection = dropMenuTranslation[i];
3825 XtAddCallback(entry, XtNcallback,
3826 (XtCallbackProc) DropMenuSelect,
3827 (caddr_t) selection);
3832 void SetupDropMenu()
3840 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3841 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3842 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3843 dmEnables[i].piece);
3844 XtSetSensitive(entry, p != NULL || !appData.testLegality
3845 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3846 && !appData.icsActive));
3848 while (p && *p++ == dmEnables[i].piece) count++;
3849 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3851 XtSetArg(args[j], XtNlabel, label); j++;
3852 XtSetValues(entry, args, j);
3856 void PieceMenuPopup(w, event, params, num_params)
3860 Cardinal *num_params;
3862 String whichMenu; int menuNr;
3863 if (event->type == ButtonRelease)
3864 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3865 else if (event->type == ButtonPress)
3866 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3868 case 0: whichMenu = params[0]; break;
3869 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3871 case -1: if (errorUp) ErrorPopDown();
3874 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3877 static void PieceMenuSelect(w, piece, junk)
3882 if (pmFromX < 0 || pmFromY < 0) return;
3883 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3886 static void DropMenuSelect(w, piece, junk)
3891 if (pmFromX < 0 || pmFromY < 0) return;
3892 DropMenuEvent(piece, pmFromX, pmFromY);
3895 void WhiteClock(w, event, prms, nprms)
3904 void BlackClock(w, event, prms, nprms)
3915 * If the user selects on a border boundary, return -1; if off the board,
3916 * return -2. Otherwise map the event coordinate to the square.
3918 int EventToSquare(x, limit)
3926 if ((x % (squareSize + lineGap)) >= squareSize)
3928 x /= (squareSize + lineGap);
3934 static void do_flash_delay(msec)
3940 static void drawHighlight(file, rank, gc)
3946 if (lineGap == 0) return;
3949 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3950 (squareSize + lineGap);
3951 y = lineGap/2 + rank * (squareSize + lineGap);
3953 x = lineGap/2 + file * (squareSize + lineGap);
3954 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3955 (squareSize + lineGap);
3958 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3959 squareSize+lineGap, squareSize+lineGap);
3962 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3963 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3966 SetHighlights(fromX, fromY, toX, toY)
3967 int fromX, fromY, toX, toY;
3969 if (hi1X != fromX || hi1Y != fromY) {
3970 if (hi1X >= 0 && hi1Y >= 0) {
3971 drawHighlight(hi1X, hi1Y, lineGC);
3973 } // [HGM] first erase both, then draw new!
3974 if (hi2X != toX || hi2Y != toY) {
3975 if (hi2X >= 0 && hi2Y >= 0) {
3976 drawHighlight(hi2X, hi2Y, lineGC);
3979 if (hi1X != fromX || hi1Y != fromY) {
3980 if (fromX >= 0 && fromY >= 0) {
3981 drawHighlight(fromX, fromY, highlineGC);
3984 if (hi2X != toX || hi2Y != toY) {
3985 if (toX >= 0 && toY >= 0) {
3986 drawHighlight(toX, toY, highlineGC);
3998 SetHighlights(-1, -1, -1, -1);
4003 SetPremoveHighlights(fromX, fromY, toX, toY)
4004 int fromX, fromY, toX, toY;
4006 if (pm1X != fromX || pm1Y != fromY) {
4007 if (pm1X >= 0 && pm1Y >= 0) {
4008 drawHighlight(pm1X, pm1Y, lineGC);
4010 if (fromX >= 0 && fromY >= 0) {
4011 drawHighlight(fromX, fromY, prelineGC);
4014 if (pm2X != toX || pm2Y != toY) {
4015 if (pm2X >= 0 && pm2Y >= 0) {
4016 drawHighlight(pm2X, pm2Y, lineGC);
4018 if (toX >= 0 && toY >= 0) {
4019 drawHighlight(toX, toY, prelineGC);
4029 ClearPremoveHighlights()
4031 SetPremoveHighlights(-1, -1, -1, -1);
4034 static int CutOutSquare(x, y, x0, y0, kind)
4035 int x, y, *x0, *y0, kind;
4037 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
4038 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
4040 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
4041 if(textureW[kind] < W*squareSize)
4042 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
4044 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
4045 if(textureH[kind] < H*squareSize)
4046 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
4048 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
4052 static void BlankSquare(x, y, color, piece, dest, fac)
4053 int x, y, color, fac;
4056 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
4058 if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
4059 XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
4060 squareSize, squareSize, x*fac, y*fac);
4062 if (useImages && useImageSqs) {
4066 pm = xpmLightSquare;
4071 case 2: /* neutral */
4076 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4077 squareSize, squareSize, x*fac, y*fac);
4087 case 2: /* neutral */
4092 XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
4097 I split out the routines to draw a piece so that I could
4098 make a generic flash routine.
4100 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4102 int square_color, x, y;
4105 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4106 switch (square_color) {
4108 case 2: /* neutral */
4110 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4111 ? *pieceToOutline(piece)
4112 : *pieceToSolid(piece),
4113 dest, bwPieceGC, 0, 0,
4114 squareSize, squareSize, x, y);
4117 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4118 ? *pieceToSolid(piece)
4119 : *pieceToOutline(piece),
4120 dest, wbPieceGC, 0, 0,
4121 squareSize, squareSize, x, y);
4126 static void monoDrawPiece(piece, square_color, x, y, dest)
4128 int square_color, x, y;
4131 switch (square_color) {
4133 case 2: /* neutral */
4135 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4136 ? *pieceToOutline(piece)
4137 : *pieceToSolid(piece),
4138 dest, bwPieceGC, 0, 0,
4139 squareSize, squareSize, x, y, 1);
4142 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4143 ? *pieceToSolid(piece)
4144 : *pieceToOutline(piece),
4145 dest, wbPieceGC, 0, 0,
4146 squareSize, squareSize, x, y, 1);
4151 static void colorDrawPiece(piece, square_color, x, y, dest)
4153 int square_color, x, y;
4156 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4157 switch (square_color) {
4159 XCopyPlane(xDisplay, *pieceToSolid(piece),
4160 dest, (int) piece < (int) BlackPawn
4161 ? wlPieceGC : blPieceGC, 0, 0,
4162 squareSize, squareSize, x, y, 1);
4165 XCopyPlane(xDisplay, *pieceToSolid(piece),
4166 dest, (int) piece < (int) BlackPawn
4167 ? wdPieceGC : bdPieceGC, 0, 0,
4168 squareSize, squareSize, x, y, 1);
4170 case 2: /* neutral */
4172 XCopyPlane(xDisplay, *pieceToSolid(piece),
4173 dest, (int) piece < (int) BlackPawn
4174 ? wjPieceGC : bjPieceGC, 0, 0,
4175 squareSize, squareSize, x, y, 1);
4180 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4182 int square_color, x, y;
4185 int kind, p = piece;
4187 switch (square_color) {
4189 case 2: /* neutral */
4191 if ((int)piece < (int) BlackPawn) {
4199 if ((int)piece < (int) BlackPawn) {
4207 if(appData.upsideDown && flipView) { kind ^= 2; p += p < BlackPawn ? BlackPawn : -BlackPawn; }// swap white and black pieces
4208 if(useTexture & square_color+1) {
4209 BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background
4210 XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]);
4211 XSetClipOrigin(xDisplay, wlPieceGC, x, y);
4212 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y);
4213 XSetClipMask(xDisplay, wlPieceGC, None);
4214 XSetClipOrigin(xDisplay, wlPieceGC, 0, 0);
4216 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4217 dest, wlPieceGC, 0, 0,
4218 squareSize, squareSize, x, y);
4221 typedef void (*DrawFunc)();
4223 DrawFunc ChooseDrawFunc()
4225 if (appData.monoMode) {
4226 if (DefaultDepth(xDisplay, xScreen) == 1) {
4227 return monoDrawPiece_1bit;
4229 return monoDrawPiece;
4233 return colorDrawPieceImage;
4235 return colorDrawPiece;
4239 /* [HR] determine square color depending on chess variant. */
4240 static int SquareColor(row, column)
4245 if (gameInfo.variant == VariantXiangqi) {
4246 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4248 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4250 } else if (row <= 4) {
4256 square_color = ((column + row) % 2) == 1;
4259 /* [hgm] holdings: next line makes all holdings squares light */
4260 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4262 return square_color;
4265 void DrawSquare(row, column, piece, do_flash)
4266 int row, column, do_flash;
4269 int square_color, x, y, direction, font_ascent, font_descent;
4272 XCharStruct overall;
4276 /* Calculate delay in milliseconds (2-delays per complete flash) */
4277 flash_delay = 500 / appData.flashRate;
4280 x = lineGap + ((BOARD_WIDTH-1)-column) *
4281 (squareSize + lineGap);
4282 y = lineGap + row * (squareSize + lineGap);
4284 x = lineGap + column * (squareSize + lineGap);
4285 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4286 (squareSize + lineGap);
4289 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4291 square_color = SquareColor(row, column);
4293 if ( // [HGM] holdings: blank out area between board and holdings
4294 column == BOARD_LEFT-1 || column == BOARD_RGHT
4295 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4296 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4297 BlankSquare(x, y, 2, EmptySquare, xBoardWindow, 1);
4299 // [HGM] print piece counts next to holdings
4300 string[1] = NULLCHAR;
4301 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4302 string[0] = '0' + piece;
4303 XTextExtents(countFontStruct, string, 1, &direction,
4304 &font_ascent, &font_descent, &overall);
4305 if (appData.monoMode) {
4306 XDrawImageString(xDisplay, xBoardWindow, countGC,
4307 x + squareSize - overall.width - 2,
4308 y + font_ascent + 1, string, 1);
4310 XDrawString(xDisplay, xBoardWindow, countGC,
4311 x + squareSize - overall.width - 2,
4312 y + font_ascent + 1, string, 1);
4315 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4316 string[0] = '0' + piece;
4317 XTextExtents(countFontStruct, string, 1, &direction,
4318 &font_ascent, &font_descent, &overall);
4319 if (appData.monoMode) {
4320 XDrawImageString(xDisplay, xBoardWindow, countGC,
4321 x + 2, y + font_ascent + 1, string, 1);
4323 XDrawString(xDisplay, xBoardWindow, countGC,
4324 x + 2, y + font_ascent + 1, string, 1);
4328 if (piece == EmptySquare || appData.blindfold) {
4329 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4331 drawfunc = ChooseDrawFunc();
4332 if (do_flash && appData.flashCount > 0) {
4333 for (i=0; i<appData.flashCount; ++i) {
4335 drawfunc(piece, square_color, x, y, xBoardWindow);
4336 XSync(xDisplay, False);
4337 do_flash_delay(flash_delay);
4339 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4340 XSync(xDisplay, False);
4341 do_flash_delay(flash_delay);
4344 drawfunc(piece, square_color, x, y, xBoardWindow);
4348 string[1] = NULLCHAR;
4349 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4350 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4351 string[0] = 'a' + column - BOARD_LEFT;
4352 XTextExtents(coordFontStruct, string, 1, &direction,
4353 &font_ascent, &font_descent, &overall);
4354 if (appData.monoMode) {
4355 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4356 x + squareSize - overall.width - 2,
4357 y + squareSize - font_descent - 1, string, 1);
4359 XDrawString(xDisplay, xBoardWindow, coordGC,
4360 x + squareSize - overall.width - 2,
4361 y + squareSize - font_descent - 1, string, 1);
4364 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4365 string[0] = ONE + row;
4366 XTextExtents(coordFontStruct, string, 1, &direction,
4367 &font_ascent, &font_descent, &overall);
4368 if (appData.monoMode) {
4369 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4370 x + 2, y + font_ascent + 1, string, 1);
4372 XDrawString(xDisplay, xBoardWindow, coordGC,
4373 x + 2, y + font_ascent + 1, string, 1);
4376 if(!partnerUp && marker[row][column]) {
4377 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4378 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4383 /* Why is this needed on some versions of X? */
4384 void EventProc(widget, unused, event)
4389 if (!XtIsRealized(widget))
4392 switch (event->type) {
4394 if (event->xexpose.count > 0) return; /* no clipping is done */
4395 XDrawPosition(widget, True, NULL);
4396 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4397 flipView = !flipView; partnerUp = !partnerUp;
4398 XDrawPosition(widget, True, NULL);
4399 flipView = !flipView; partnerUp = !partnerUp;
4403 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
4410 void DrawPosition(fullRedraw, board)
4411 /*Boolean*/int fullRedraw;
4414 XDrawPosition(boardWidget, fullRedraw, board);
4417 /* Returns 1 if there are "too many" differences between b1 and b2
4418 (i.e. more than 1 move was made) */
4419 static int too_many_diffs(b1, b2)
4425 for (i=0; i<BOARD_HEIGHT; ++i) {
4426 for (j=0; j<BOARD_WIDTH; ++j) {
4427 if (b1[i][j] != b2[i][j]) {
4428 if (++c > 4) /* Castling causes 4 diffs */
4437 /* Matrix describing castling maneuvers */
4438 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4439 static int castling_matrix[4][5] = {
4440 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4441 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4442 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4443 { 7, 7, 4, 5, 6 } /* 0-0, black */
4446 /* Checks whether castling occurred. If it did, *rrow and *rcol
4447 are set to the destination (row,col) of the rook that moved.
4449 Returns 1 if castling occurred, 0 if not.
4451 Note: Only handles a max of 1 castling move, so be sure
4452 to call too_many_diffs() first.
4454 static int check_castle_draw(newb, oldb, rrow, rcol)
4461 /* For each type of castling... */
4462 for (i=0; i<4; ++i) {
4463 r = castling_matrix[i];
4465 /* Check the 4 squares involved in the castling move */
4467 for (j=1; j<=4; ++j) {
4468 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4475 /* All 4 changed, so it must be a castling move */
4484 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4485 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4487 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4490 void DrawSeekBackground( int left, int top, int right, int bottom )
4492 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4495 void DrawSeekText(char *buf, int x, int y)
4497 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4500 void DrawSeekDot(int x, int y, int colorNr)
4502 int square = colorNr & 0x80;
4505 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4507 XFillRectangle(xDisplay, xBoardWindow, color,
4508 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4510 XFillArc(xDisplay, xBoardWindow, color,
4511 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4514 static int damage[2][BOARD_RANKS][BOARD_FILES];
4517 * event handler for redrawing the board
4519 void XDrawPosition(w, repaint, board)
4521 /*Boolean*/int repaint;
4525 static int lastFlipView = 0;
4526 static int lastBoardValid[2] = {0, 0};
4527 static Board lastBoard[2];
4530 int nr = twoBoards*partnerUp;
4532 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4534 if (board == NULL) {
4535 if (!lastBoardValid[nr]) return;
4536 board = lastBoard[nr];
4538 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4539 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4540 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Flip View"),
4545 * It would be simpler to clear the window with XClearWindow()
4546 * but this causes a very distracting flicker.
4549 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4551 if ( lineGap && IsDrawArrowEnabled())
4552 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4553 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4555 /* If too much changes (begin observing new game, etc.), don't
4557 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4559 /* Special check for castling so we don't flash both the king
4560 and the rook (just flash the king). */
4562 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4563 /* Draw rook with NO flashing. King will be drawn flashing later */
4564 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4565 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4569 /* First pass -- Draw (newly) empty squares and repair damage.
4570 This prevents you from having a piece show up twice while it
4571 is flashing on its new square */
4572 for (i = 0; i < BOARD_HEIGHT; i++)
4573 for (j = 0; j < BOARD_WIDTH; j++)
4574 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4575 || damage[nr][i][j]) {
4576 DrawSquare(i, j, board[i][j], 0);
4577 damage[nr][i][j] = False;
4580 /* Second pass -- Draw piece(s) in new position and flash them */
4581 for (i = 0; i < BOARD_HEIGHT; i++)
4582 for (j = 0; j < BOARD_WIDTH; j++)
4583 if (board[i][j] != lastBoard[nr][i][j]) {
4584 DrawSquare(i, j, board[i][j], do_flash);
4588 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4589 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4590 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4592 for (i = 0; i < BOARD_HEIGHT; i++)
4593 for (j = 0; j < BOARD_WIDTH; j++) {
4594 DrawSquare(i, j, board[i][j], 0);
4595 damage[nr][i][j] = False;
4599 CopyBoard(lastBoard[nr], board);
4600 lastBoardValid[nr] = 1;
4601 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4602 lastFlipView = flipView;
4604 /* Draw highlights */
4605 if (pm1X >= 0 && pm1Y >= 0) {
4606 drawHighlight(pm1X, pm1Y, prelineGC);
4608 if (pm2X >= 0 && pm2Y >= 0) {
4609 drawHighlight(pm2X, pm2Y, prelineGC);
4611 if (hi1X >= 0 && hi1Y >= 0) {
4612 drawHighlight(hi1X, hi1Y, highlineGC);
4614 if (hi2X >= 0 && hi2Y >= 0) {
4615 drawHighlight(hi2X, hi2Y, highlineGC);
4617 DrawArrowHighlight(hi1X, hi1Y, hi2X, hi2Y);
4619 /* If piece being dragged around board, must redraw that too */
4622 XSync(xDisplay, False);
4627 * event handler for redrawing the board
4629 void DrawPositionProc(w, event, prms, nprms)
4635 XDrawPosition(w, True, NULL);
4640 * event handler for parsing user moves
4642 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4643 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4644 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4645 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4646 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4647 // and at the end FinishMove() to perform the move after optional promotion popups.
4648 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4649 void HandleUserMove(w, event, prms, nprms)
4655 if (w != boardWidget || errorExitStatus != -1) return;
4656 if(nprms) shiftKey = !strcmp(prms[0], "1");
4659 if (event->type == ButtonPress) {
4660 XtPopdown(promotionShell);
4661 XtDestroyWidget(promotionShell);
4662 promotionUp = False;
4670 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4671 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4672 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4675 void AnimateUserMove (Widget w, XEvent * event,
4676 String * params, Cardinal * nParams)
4678 DragPieceMove(event->xmotion.x, event->xmotion.y);
4681 void HandlePV (Widget w, XEvent * event,
4682 String * params, Cardinal * nParams)
4683 { // [HGM] pv: walk PV
4684 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4687 Widget CommentCreate(name, text, mutable, callback, lines)
4689 int /*Boolean*/ mutable;
4690 XtCallbackProc callback;
4694 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4699 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4700 XtGetValues(boardWidget, args, j);
4703 XtSetArg(args[j], XtNresizable, True); j++;
4706 XtCreatePopupShell(name, topLevelShellWidgetClass,
4707 shellWidget, args, j);
4710 XtCreatePopupShell(name, transientShellWidgetClass,
4711 shellWidget, args, j);
4714 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4715 layoutArgs, XtNumber(layoutArgs));
4717 XtCreateManagedWidget("form", formWidgetClass, layout,
4718 formArgs, XtNumber(formArgs));
4722 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4723 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4725 XtSetArg(args[j], XtNstring, text); j++;
4726 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4727 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4728 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4729 XtSetArg(args[j], XtNright, XtChainRight); j++;
4730 XtSetArg(args[j], XtNresizable, True); j++;
4731 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4732 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4733 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4734 XtSetArg(args[j], XtNautoFill, True); j++;
4735 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4737 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4738 XtOverrideTranslations(edit, XtParseTranslationTable(commentTranslations));
4742 XtSetArg(args[j], XtNfromVert, edit); j++;
4743 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4744 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4745 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4746 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4748 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4749 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4752 XtSetArg(args[j], XtNfromVert, edit); j++;
4753 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4754 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4755 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4756 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4757 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4759 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4760 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4763 XtSetArg(args[j], XtNfromVert, edit); j++;
4764 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4765 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4766 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4767 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4768 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4770 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4771 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4774 XtSetArg(args[j], XtNfromVert, edit); j++;
4775 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4776 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4777 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4778 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4780 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4781 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4784 XtSetArg(args[j], XtNfromVert, edit); j++;
4785 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4786 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4787 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4788 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4789 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4791 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4792 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4795 XtRealizeWidget(shell);
4797 if (commentX == -1) {
4800 Dimension pw_height;
4801 Dimension ew_height;
4804 XtSetArg(args[j], XtNheight, &ew_height); j++;
4805 XtGetValues(edit, args, j);
4808 XtSetArg(args[j], XtNheight, &pw_height); j++;
4809 XtGetValues(shell, args, j);
4810 commentH = pw_height + (lines - 1) * ew_height;
4811 commentW = bw_width - 16;
4813 XSync(xDisplay, False);
4815 /* This code seems to tickle an X bug if it is executed too soon
4816 after xboard starts up. The coordinates get transformed as if
4817 the main window was positioned at (0, 0).
4819 XtTranslateCoords(shellWidget,
4820 (bw_width - commentW) / 2, 0 - commentH / 2,
4821 &commentX, &commentY);
4823 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4824 RootWindowOfScreen(XtScreen(shellWidget)),
4825 (bw_width - commentW) / 2, 0 - commentH / 2,
4830 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4833 if(wpComment.width > 0) {
4834 commentX = wpComment.x;
4835 commentY = wpComment.y;
4836 commentW = wpComment.width;
4837 commentH = wpComment.height;
4841 XtSetArg(args[j], XtNheight, commentH); j++;
4842 XtSetArg(args[j], XtNwidth, commentW); j++;
4843 XtSetArg(args[j], XtNx, commentX); j++;
4844 XtSetArg(args[j], XtNy, commentY); j++;
4845 XtSetValues(shell, args, j);
4846 XtSetKeyboardFocus(shell, edit);
4851 /* Used for analysis window and ICS input window */
4852 Widget MiscCreate(name, text, mutable, callback, lines)
4854 int /*Boolean*/ mutable;
4855 XtCallbackProc callback;
4859 Widget shell, layout, form, edit;
4861 Dimension bw_width, pw_height, ew_height, w, h;
4867 XtSetArg(args[j], XtNresizable, True); j++;
4870 XtCreatePopupShell(name, topLevelShellWidgetClass,
4871 shellWidget, args, j);
4874 XtCreatePopupShell(name, transientShellWidgetClass,
4875 shellWidget, args, j);
4878 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4879 layoutArgs, XtNumber(layoutArgs));
4881 XtCreateManagedWidget("form", formWidgetClass, layout,
4882 formArgs, XtNumber(formArgs));
4886 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4887 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4889 XtSetArg(args[j], XtNstring, text); j++;
4890 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4891 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4892 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4893 XtSetArg(args[j], XtNright, XtChainRight); j++;
4894 XtSetArg(args[j], XtNresizable, True); j++;
4895 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4896 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4897 XtSetArg(args[j], XtNautoFill, True); j++;
4898 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4900 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4902 XtRealizeWidget(shell);
4905 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4906 XtGetValues(boardWidget, args, j);
4909 XtSetArg(args[j], XtNheight, &ew_height); j++;
4910 XtGetValues(edit, args, j);
4913 XtSetArg(args[j], XtNheight, &pw_height); j++;
4914 XtGetValues(shell, args, j);
4915 h = pw_height + (lines - 1) * ew_height;
4918 XSync(xDisplay, False);
4920 /* This code seems to tickle an X bug if it is executed too soon
4921 after xboard starts up. The coordinates get transformed as if
4922 the main window was positioned at (0, 0).
4924 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4926 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4927 RootWindowOfScreen(XtScreen(shellWidget)),
4928 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4932 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4935 XtSetArg(args[j], XtNheight, h); j++;
4936 XtSetArg(args[j], XtNwidth, w); j++;
4937 XtSetArg(args[j], XtNx, x); j++;
4938 XtSetArg(args[j], XtNy, y); j++;
4939 XtSetValues(shell, args, j);
4945 static int savedIndex; /* gross that this is global */
4947 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
4950 XawTextPosition index, dummy;
4953 XawTextGetSelectionPos(w, &index, &dummy);
4954 XtSetArg(arg, XtNstring, &val);
4955 XtGetValues(w, &arg, 1);
4956 ReplaceComment(savedIndex, val);
4957 if(savedIndex != currentMove) ToNrEvent(savedIndex);
4958 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
4961 void EditCommentPopUp(index, title, text)
4970 if (text == NULL) text = "";
4972 if (editShell == NULL) {
4974 CommentCreate(title, text, True, EditCommentCallback, 4);
4975 XtRealizeWidget(editShell);
4976 CatchDeleteWindow(editShell, "EditCommentPopDown");
4978 edit = XtNameToWidget(editShell, "*form.text");
4980 XtSetArg(args[j], XtNstring, text); j++;
4981 XtSetValues(edit, args, j);
4983 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4984 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4985 XtSetValues(editShell, args, j);
4988 XtPopup(editShell, XtGrabNone);
4992 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4993 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"),
4995 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"),
4999 void EditCommentCallback(w, client_data, call_data)
5001 XtPointer client_data, call_data;
5009 XtSetArg(args[j], XtNlabel, &name); j++;
5010 XtGetValues(w, args, j);
5012 if (strcmp(name, _("ok")) == 0) {
5013 edit = XtNameToWidget(editShell, "*form.text");
5015 XtSetArg(args[j], XtNstring, &val); j++;
5016 XtGetValues(edit, args, j);
5017 ReplaceComment(savedIndex, val);
5018 EditCommentPopDown();
5019 } else if (strcmp(name, _("cancel")) == 0) {
5020 EditCommentPopDown();
5021 } else if (strcmp(name, _("clear")) == 0) {
5022 edit = XtNameToWidget(editShell, "*form.text");
5023 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5024 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5028 void EditCommentPopDown()
5033 if (!editUp) return;
5035 XtSetArg(args[j], XtNx, &commentX); j++;
5036 XtSetArg(args[j], XtNy, &commentY); j++;
5037 XtSetArg(args[j], XtNheight, &commentH); j++;
5038 XtSetArg(args[j], XtNwidth, &commentW); j++;
5039 XtGetValues(editShell, args, j);
5040 XtPopdown(editShell);
5043 XtSetArg(args[j], XtNleftBitmap, None); j++;
5044 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"),
5046 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"),
5050 void ICSInputBoxPopUp()
5055 char *title = _("ICS Input");
5058 if (ICSInputShell == NULL) {
5059 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
5060 tr = XtParseTranslationTable(ICSInputTranslations);
5061 edit = XtNameToWidget(ICSInputShell, "*form.text");
5062 XtOverrideTranslations(edit, tr);
5063 XtRealizeWidget(ICSInputShell);
5064 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
5067 edit = XtNameToWidget(ICSInputShell, "*form.text");
5069 XtSetArg(args[j], XtNstring, ""); j++;
5070 XtSetValues(edit, args, j);
5072 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5073 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5074 XtSetValues(ICSInputShell, args, j);
5077 XtPopup(ICSInputShell, XtGrabNone);
5078 XtSetKeyboardFocus(ICSInputShell, edit);
5080 ICSInputBoxUp = True;
5082 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5083 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.ICS Input Box"),
5087 void ICSInputSendText()
5094 edit = XtNameToWidget(ICSInputShell, "*form.text");
5096 XtSetArg(args[j], XtNstring, &val); j++;
5097 XtGetValues(edit, args, j);
5099 SendMultiLineToICS(val);
5100 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5101 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5104 void ICSInputBoxPopDown()
5109 if (!ICSInputBoxUp) return;
5111 XtPopdown(ICSInputShell);
5112 ICSInputBoxUp = False;
5114 XtSetArg(args[j], XtNleftBitmap, None); j++;
5115 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.ICS Input Box"),
5119 void CommentPopUp(title, text)
5126 savedIndex = currentMove; // [HGM] vari
5127 if (commentShell == NULL) {
5129 CommentCreate(title, text, False, CommentCallback, 4);
5130 XtRealizeWidget(commentShell);
5131 CatchDeleteWindow(commentShell, "CommentPopDown");
5133 edit = XtNameToWidget(commentShell, "*form.text");
5135 XtSetArg(args[j], XtNstring, text); j++;
5136 XtSetValues(edit, args, j);
5138 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5139 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5140 XtSetValues(commentShell, args, j);
5143 XtPopup(commentShell, XtGrabNone);
5144 XSync(xDisplay, False);
5149 void CommentCallback(w, client_data, call_data)
5151 XtPointer client_data, call_data;
5158 XtSetArg(args[j], XtNlabel, &name); j++;
5159 XtGetValues(w, args, j);
5161 if (strcmp(name, _("close")) == 0) {
5163 } else if (strcmp(name, _("edit")) == 0) {
5170 void CommentPopDown()
5175 if (!commentUp) return;
5177 XtSetArg(args[j], XtNx, &commentX); j++;
5178 XtSetArg(args[j], XtNy, &commentY); j++;
5179 XtSetArg(args[j], XtNwidth, &commentW); j++;
5180 XtSetArg(args[j], XtNheight, &commentH); j++;
5181 XtGetValues(commentShell, args, j);
5182 XtPopdown(commentShell);
5183 XSync(xDisplay, False);
5187 void FileNamePopUp(label, def, proc, openMode)
5193 fileProc = proc; /* I can't see a way not */
5194 fileOpenMode = openMode; /* to use globals here */
5195 { // [HGM] use file-selector dialog stolen from Ghostview
5197 int index; // this is not supported yet
5199 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5200 def, openMode, NULL, &name))
5201 (void) (*fileProc)(f, index=0, name);
5205 void FileNamePopDown()
5207 if (!filenameUp) return;
5208 XtPopdown(fileNameShell);
5209 XtDestroyWidget(fileNameShell);
5214 void FileNameCallback(w, client_data, call_data)
5216 XtPointer client_data, call_data;
5221 XtSetArg(args[0], XtNlabel, &name);
5222 XtGetValues(w, args, 1);
5224 if (strcmp(name, _("cancel")) == 0) {
5229 FileNameAction(w, NULL, NULL, NULL);
5232 void FileNameAction(w, event, prms, nprms)
5244 name = XawDialogGetValueString(w = XtParent(w));
5246 if ((name != NULL) && (*name != NULLCHAR)) {
5247 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
5248 XtPopdown(w = XtParent(XtParent(w)));
5252 p = strrchr(buf, ' ');
5259 fullname = ExpandPathName(buf);
5261 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5264 f = fopen(fullname, fileOpenMode);
5266 DisplayError(_("Failed to open file"), errno);
5268 (void) (*fileProc)(f, index, buf);
5275 XtPopdown(w = XtParent(XtParent(w)));
5281 void PromotionPopUp()
5284 Widget dialog, layout;
5286 Dimension bw_width, pw_width;
5290 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5291 XtGetValues(boardWidget, args, j);
5294 XtSetArg(args[j], XtNresizable, True); j++;
5295 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5297 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5298 shellWidget, args, j);
5300 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5301 layoutArgs, XtNumber(layoutArgs));
5304 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5305 XtSetArg(args[j], XtNborderWidth, 0); j++;
5306 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5309 if(gameInfo.variant != VariantShogi) {
5310 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) {
5311 XawDialogAddButton(dialog, _("Warlord"), PromotionCallback,
5312 (XtPointer) dialog);
5313 XawDialogAddButton(dialog, _("General"), PromotionCallback,
5314 (XtPointer) dialog);
5315 XawDialogAddButton(dialog, _("Lieutenant"), PromotionCallback,
5316 (XtPointer) dialog);
5317 XawDialogAddButton(dialog, _("Captain"), PromotionCallback,
5318 (XtPointer) dialog);
5320 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5321 (XtPointer) dialog);
5322 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5323 (XtPointer) dialog);
5324 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5325 (XtPointer) dialog);
5326 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5327 (XtPointer) dialog);
5329 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5330 gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
\r
5331 gameInfo.variant == VariantGiveaway) {
5332 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5333 (XtPointer) dialog);
5335 if(gameInfo.variant == VariantCapablanca ||
5336 gameInfo.variant == VariantGothic ||
5337 gameInfo.variant == VariantCapaRandom) {
5338 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5339 (XtPointer) dialog);
5340 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5341 (XtPointer) dialog);
5343 } else // [HGM] shogi
5345 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5346 (XtPointer) dialog);
5347 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5348 (XtPointer) dialog);
5350 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5351 (XtPointer) dialog);
5353 XtRealizeWidget(promotionShell);
5354 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5357 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5358 XtGetValues(promotionShell, args, j);
5360 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5361 lineGap + squareSize/3 +
5362 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5363 0 : 6*(squareSize + lineGap)), &x, &y);
5366 XtSetArg(args[j], XtNx, x); j++;
5367 XtSetArg(args[j], XtNy, y); j++;
5368 XtSetValues(promotionShell, args, j);
5370 XtPopup(promotionShell, XtGrabNone);
5375 void PromotionPopDown()
5377 if (!promotionUp) return;
5378 XtPopdown(promotionShell);
5379 XtDestroyWidget(promotionShell);
5380 promotionUp = False;
5383 void PromotionCallback(w, client_data, call_data)
5385 XtPointer client_data, call_data;
5391 XtSetArg(args[0], XtNlabel, &name);
5392 XtGetValues(w, args, 1);
5396 if (fromX == -1) return;
5398 if (strcmp(name, _("cancel")) == 0) {
5402 } else if (strcmp(name, _("Knight")) == 0) {
5404 } else if (strcmp(name, _("Promote")) == 0) {
5406 } else if (strcmp(name, _("Defer")) == 0) {
5409 promoChar = ToLower(name[0]);
5412 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5414 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5415 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5420 void ErrorCallback(w, client_data, call_data)
5422 XtPointer client_data, call_data;
5425 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5427 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5433 if (!errorUp) return;
5435 XtPopdown(errorShell);
5436 XtDestroyWidget(errorShell);
5437 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5440 void ErrorPopUp(title, label, modal)
5441 char *title, *label;
5445 Widget dialog, layout;
5449 Dimension bw_width, pw_width;
5450 Dimension pw_height;
5454 XtSetArg(args[i], XtNresizable, True); i++;
5455 XtSetArg(args[i], XtNtitle, title); i++;
5457 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5458 shellWidget, args, i);
5460 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5461 layoutArgs, XtNumber(layoutArgs));
5464 XtSetArg(args[i], XtNlabel, label); i++;
5465 XtSetArg(args[i], XtNborderWidth, 0); i++;
5466 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5469 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5471 XtRealizeWidget(errorShell);
5472 CatchDeleteWindow(errorShell, "ErrorPopDown");
5475 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5476 XtGetValues(boardWidget, args, i);
5478 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5479 XtSetArg(args[i], XtNheight, &pw_height); i++;
5480 XtGetValues(errorShell, args, i);
5483 /* This code seems to tickle an X bug if it is executed too soon
5484 after xboard starts up. The coordinates get transformed as if
5485 the main window was positioned at (0, 0).
5487 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5488 0 - pw_height + squareSize / 3, &x, &y);
5490 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5491 RootWindowOfScreen(XtScreen(boardWidget)),
5492 (bw_width - pw_width) / 2,
5493 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5497 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5500 XtSetArg(args[i], XtNx, x); i++;
5501 XtSetArg(args[i], XtNy, y); i++;
5502 XtSetValues(errorShell, args, i);
5505 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5508 /* Disable all user input other than deleting the window */
5509 static int frozen = 0;
5513 /* Grab by a widget that doesn't accept input */
5514 XtAddGrab(messageWidget, TRUE, FALSE);
5518 /* Undo a FreezeUI */
5521 if (!frozen) return;
5522 XtRemoveGrab(messageWidget);
5526 char *ModeToWidgetName(mode)
5530 case BeginningOfGame:
5531 if (appData.icsActive)
5532 return "menuMode.ICS Client";
5533 else if (appData.noChessProgram ||
5534 *appData.cmailGameName != NULLCHAR)
5535 return "menuMode.Edit Game";
5537 return "menuMode.Machine Black";
5538 case MachinePlaysBlack:
5539 return "menuMode.Machine Black";
5540 case MachinePlaysWhite:
5541 return "menuMode.Machine White";
5543 return "menuMode.Analysis Mode";
5545 return "menuMode.Analyze File";
5546 case TwoMachinesPlay:
5547 return "menuMode.Two Machines";
5549 return "menuMode.Edit Game";
5550 case PlayFromGameFile:
5551 return "menuFile.Load Game";
5553 return "menuMode.Edit Position";
5555 return "menuMode.Training";
5556 case IcsPlayingWhite:
5557 case IcsPlayingBlack:
5561 return "menuMode.ICS Client";
5568 void ModeHighlight()
5571 static int oldPausing = FALSE;
5572 static GameMode oldmode = (GameMode) -1;
5575 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5577 if (pausing != oldPausing) {
5578 oldPausing = pausing;
5580 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5582 XtSetArg(args[0], XtNleftBitmap, None);
5584 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5587 if (appData.showButtonBar) {
5588 /* Always toggle, don't set. Previous code messes up when
5589 invoked while the button is pressed, as releasing it
5590 toggles the state again. */
5593 XtSetArg(args[0], XtNbackground, &oldbg);
5594 XtSetArg(args[1], XtNforeground, &oldfg);
5595 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5597 XtSetArg(args[0], XtNbackground, oldfg);
5598 XtSetArg(args[1], XtNforeground, oldbg);
5600 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5604 wname = ModeToWidgetName(oldmode);
5605 if (wname != NULL) {
5606 XtSetArg(args[0], XtNleftBitmap, None);
5607 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5609 wname = ModeToWidgetName(gameMode);
5610 if (wname != NULL) {
5611 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5612 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5616 /* Maybe all the enables should be handled here, not just this one */
5617 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5618 gameMode == Training || gameMode == PlayFromGameFile);
5623 * Button/menu procedures
5625 void ResetProc(w, event, prms, nprms)
5634 int LoadGamePopUp(f, gameNumber, title)
5639 cmailMsgLoaded = FALSE;
5640 if (gameNumber == 0) {
5641 int error = GameListBuild(f);
5643 DisplayError(_("Cannot build game list"), error);
5644 } else if (!ListEmpty(&gameList) &&
5645 ((ListGame *) gameList.tailPred)->number > 1) {
5646 GameListPopUp(f, title);
5652 return LoadGame(f, gameNumber, title, FALSE);
5655 void LoadGameProc(w, event, prms, nprms)
5661 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5664 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5667 void LoadNextGameProc(w, event, prms, nprms)
5676 void LoadPrevGameProc(w, event, prms, nprms)
5685 void ReloadGameProc(w, event, prms, nprms)
5694 void LoadNextPositionProc(w, event, prms, nprms)
5703 void LoadPrevPositionProc(w, event, prms, nprms)
5712 void ReloadPositionProc(w, event, prms, nprms)
5721 void LoadPositionProc(w, event, prms, nprms)
5727 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5730 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5733 void SaveGameProc(w, event, prms, nprms)
5739 FileNamePopUp(_("Save game file name?"),
5740 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5744 void SavePositionProc(w, event, prms, nprms)
5750 FileNamePopUp(_("Save position file name?"),
5751 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5755 void ReloadCmailMsgProc(w, event, prms, nprms)
5761 ReloadCmailMsgEvent(FALSE);
5764 void MailMoveProc(w, event, prms, nprms)
5773 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5774 char *selected_fen_position=NULL;
5777 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5778 Atom *type_return, XtPointer *value_return,
5779 unsigned long *length_return, int *format_return)
5781 char *selection_tmp;
5783 if (!selected_fen_position) return False; /* should never happen */
5784 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5785 /* note: since no XtSelectionDoneProc was registered, Xt will
5786 * automatically call XtFree on the value returned. So have to
5787 * make a copy of it allocated with XtMalloc */
5788 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5789 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
5791 *value_return=selection_tmp;
5792 *length_return=strlen(selection_tmp);
5793 *type_return=*target;
5794 *format_return = 8; /* bits per byte */
5796 } else if (*target == XA_TARGETS(xDisplay)) {
5797 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5798 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5799 targets_tmp[1] = XA_STRING;
5800 *value_return = targets_tmp;
5801 *type_return = XA_ATOM;
5803 *format_return = 8 * sizeof(Atom);
5804 if (*format_return > 32) {
5805 *length_return *= *format_return / 32;
5806 *format_return = 32;
5814 /* note: when called from menu all parameters are NULL, so no clue what the
5815 * Widget which was clicked on was, or what the click event was
5817 void CopyPositionProc(w, event, prms, nprms)
5824 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5825 * have a notion of a position that is selected but not copied.
5826 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5828 if(gameMode == EditPosition) EditPositionDone(TRUE);
5829 if (selected_fen_position) free(selected_fen_position);
5830 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5831 if (!selected_fen_position) return;
5832 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5834 SendPositionSelection,
5835 NULL/* lose_ownership_proc */ ,
5836 NULL/* transfer_done_proc */);
5837 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5839 SendPositionSelection,
5840 NULL/* lose_ownership_proc */ ,
5841 NULL/* transfer_done_proc */);
5844 /* function called when the data to Paste is ready */
5846 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5847 Atom *type, XtPointer value, unsigned long *len, int *format)
5850 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5851 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5852 EditPositionPasteFEN(fenstr);
5856 /* called when Paste Position button is pressed,
5857 * all parameters will be NULL */
5858 void PastePositionProc(w, event, prms, nprms)
5864 XtGetSelectionValue(menuBarWidget,
5865 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5866 /* (XtSelectionCallbackProc) */ PastePositionCB,
5867 NULL, /* client_data passed to PastePositionCB */
5869 /* better to use the time field from the event that triggered the
5870 * call to this function, but that isn't trivial to get
5878 SendGameSelection(Widget w, Atom *selection, Atom *target,
5879 Atom *type_return, XtPointer *value_return,
5880 unsigned long *length_return, int *format_return)
5882 char *selection_tmp;
5884 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5885 FILE* f = fopen(gameCopyFilename, "r");
5888 if (f == NULL) return False;
5892 selection_tmp = XtMalloc(len + 1);
5893 count = fread(selection_tmp, 1, len, f);
5896 XtFree(selection_tmp);
5899 selection_tmp[len] = NULLCHAR;
5900 *value_return = selection_tmp;
5901 *length_return = len;
5902 *type_return = *target;
5903 *format_return = 8; /* bits per byte */
5905 } else if (*target == XA_TARGETS(xDisplay)) {
5906 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5907 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5908 targets_tmp[1] = XA_STRING;
5909 *value_return = targets_tmp;
5910 *type_return = XA_ATOM;
5912 *format_return = 8 * sizeof(Atom);
5913 if (*format_return > 32) {
5914 *length_return *= *format_return / 32;
5915 *format_return = 32;
5923 /* note: when called from menu all parameters are NULL, so no clue what the
5924 * Widget which was clicked on was, or what the click event was
5926 void CopyGameProc(w, event, prms, nprms)
5934 ret = SaveGameToFile(gameCopyFilename, FALSE);
5938 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5939 * have a notion of a game that is selected but not copied.
5940 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5942 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5945 NULL/* lose_ownership_proc */ ,
5946 NULL/* transfer_done_proc */);
5947 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5950 NULL/* lose_ownership_proc */ ,
5951 NULL/* transfer_done_proc */);
5954 /* function called when the data to Paste is ready */
5956 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5957 Atom *type, XtPointer value, unsigned long *len, int *format)
5960 if (value == NULL || *len == 0) {
5961 return; /* nothing had been selected to copy */
5963 f = fopen(gamePasteFilename, "w");
5965 DisplayError(_("Can't open temp file"), errno);
5968 fwrite(value, 1, *len, f);
5971 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5974 /* called when Paste Game button is pressed,
5975 * all parameters will be NULL */
5976 void PasteGameProc(w, event, prms, nprms)
5982 XtGetSelectionValue(menuBarWidget,
5983 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5984 /* (XtSelectionCallbackProc) */ PasteGameCB,
5985 NULL, /* client_data passed to PasteGameCB */
5987 /* better to use the time field from the event that triggered the
5988 * call to this function, but that isn't trivial to get
5998 SaveGameProc(NULL, NULL, NULL, NULL);
6002 void QuitProc(w, event, prms, nprms)
6011 void PauseProc(w, event, prms, nprms)
6021 void MachineBlackProc(w, event, prms, nprms)
6027 MachineBlackEvent();
6030 void MachineWhiteProc(w, event, prms, nprms)
6036 MachineWhiteEvent();
6039 void AnalyzeModeProc(w, event, prms, nprms)
6047 if (!first.analysisSupport) {
6048 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6049 DisplayError(buf, 0);
6052 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
6053 if (appData.icsActive) {
6054 if (gameMode != IcsObserving) {
6055 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
6056 DisplayError(buf, 0);
6058 if (appData.icsEngineAnalyze) {
6059 if (appData.debugMode)
6060 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
6066 /* if enable, use want disable icsEngineAnalyze */
6067 if (appData.icsEngineAnalyze) {
6072 appData.icsEngineAnalyze = TRUE;
6073 if (appData.debugMode)
6074 fprintf(debugFP, _("ICS engine analyze starting... \n"));
6076 if (!appData.showThinking)
6077 ShowThinkingProc(w,event,prms,nprms);
6082 void AnalyzeFileProc(w, event, prms, nprms)
6088 if (!first.analysisSupport) {
6090 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6091 DisplayError(buf, 0);
6096 if (!appData.showThinking)
6097 ShowThinkingProc(w,event,prms,nprms);
6100 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
6101 AnalysisPeriodicEvent(1);
6104 void TwoMachinesProc(w, event, prms, nprms)
6113 void IcsClientProc(w, event, prms, nprms)
6122 void EditGameProc(w, event, prms, nprms)
6131 void EditPositionProc(w, event, prms, nprms)
6137 EditPositionEvent();
6140 void TrainingProc(w, event, prms, nprms)
6149 void EditCommentProc(w, event, prms, nprms)
6156 EditCommentPopDown();
6162 void IcsInputBoxProc(w, event, prms, nprms)
6168 if (ICSInputBoxUp) {
6169 ICSInputBoxPopDown();
6175 void AcceptProc(w, event, prms, nprms)
6184 void DeclineProc(w, event, prms, nprms)
6193 void RematchProc(w, event, prms, nprms)
6202 void CallFlagProc(w, event, prms, nprms)
6211 void DrawProc(w, event, prms, nprms)
6220 void AbortProc(w, event, prms, nprms)
6229 void AdjournProc(w, event, prms, nprms)
6238 void ResignProc(w, event, prms, nprms)
6247 void AdjuWhiteProc(w, event, prms, nprms)
6253 UserAdjudicationEvent(+1);
6256 void AdjuBlackProc(w, event, prms, nprms)
6262 UserAdjudicationEvent(-1);
6265 void AdjuDrawProc(w, event, prms, nprms)
6271 UserAdjudicationEvent(0);
6274 void EnterKeyProc(w, event, prms, nprms)
6280 if (ICSInputBoxUp == True)
6284 void UpKeyProc(w, event, prms, nprms)
6289 { // [HGM] input: let up-arrow recall previous line from history
6296 if (!ICSInputBoxUp) return;
6297 edit = XtNameToWidget(ICSInputShell, "*form.text");
6299 XtSetArg(args[j], XtNstring, &val); j++;
6300 XtGetValues(edit, args, j);
6301 val = PrevInHistory(val);
6302 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6303 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6305 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6306 XawTextReplace(edit, 0, 0, &t);
6307 XawTextSetInsertionPoint(edit, 9999);
6311 void DownKeyProc(w, event, prms, nprms)
6316 { // [HGM] input: let down-arrow recall next line from history
6321 if (!ICSInputBoxUp) return;
6322 edit = XtNameToWidget(ICSInputShell, "*form.text");
6323 val = NextInHistory();
6324 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6325 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6327 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6328 XawTextReplace(edit, 0, 0, &t);
6329 XawTextSetInsertionPoint(edit, 9999);
6333 void StopObservingProc(w, event, prms, nprms)
6339 StopObservingEvent();
6342 void StopExaminingProc(w, event, prms, nprms)
6348 StopExaminingEvent();
6351 void UploadProc(w, event, prms, nprms)
6361 void ForwardProc(w, event, prms, nprms)
6371 void BackwardProc(w, event, prms, nprms)
6380 void ToStartProc(w, event, prms, nprms)
6389 void ToEndProc(w, event, prms, nprms)
6398 void RevertProc(w, event, prms, nprms)
6407 void AnnotateProc(w, event, prms, nprms)
6416 void TruncateGameProc(w, event, prms, nprms)
6422 TruncateGameEvent();
6424 void RetractMoveProc(w, event, prms, nprms)
6433 void MoveNowProc(w, event, prms, nprms)
6443 void AlwaysQueenProc(w, event, prms, nprms)
6451 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6453 if (appData.alwaysPromoteToQueen) {
6454 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6456 XtSetArg(args[0], XtNleftBitmap, None);
6458 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6462 void AnimateDraggingProc(w, event, prms, nprms)
6470 appData.animateDragging = !appData.animateDragging;
6472 if (appData.animateDragging) {
6473 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6476 XtSetArg(args[0], XtNleftBitmap, None);
6478 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6482 void AnimateMovingProc(w, event, prms, nprms)
6490 appData.animate = !appData.animate;
6492 if (appData.animate) {
6493 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6496 XtSetArg(args[0], XtNleftBitmap, None);
6498 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6502 void AutoflagProc(w, event, prms, nprms)
6510 appData.autoCallFlag = !appData.autoCallFlag;
6512 if (appData.autoCallFlag) {
6513 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6515 XtSetArg(args[0], XtNleftBitmap, None);
6517 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6521 void AutoflipProc(w, event, prms, nprms)
6529 appData.autoFlipView = !appData.autoFlipView;
6531 if (appData.autoFlipView) {
6532 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6534 XtSetArg(args[0], XtNleftBitmap, None);
6536 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6540 void BlindfoldProc(w, event, prms, nprms)
6548 appData.blindfold = !appData.blindfold;
6550 if (appData.blindfold) {
6551 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6553 XtSetArg(args[0], XtNleftBitmap, None);
6555 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6558 DrawPosition(True, NULL);
6561 void TestLegalityProc(w, event, prms, nprms)
6569 appData.testLegality = !appData.testLegality;
6571 if (appData.testLegality) {
6572 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6574 XtSetArg(args[0], XtNleftBitmap, None);
6576 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6581 void FlashMovesProc(w, event, prms, nprms)
6589 if (appData.flashCount == 0) {
6590 appData.flashCount = 3;
6592 appData.flashCount = -appData.flashCount;
6595 if (appData.flashCount > 0) {
6596 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6598 XtSetArg(args[0], XtNleftBitmap, None);
6600 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6604 void FlipViewProc(w, event, prms, nprms)
6610 flipView = !flipView;
6611 DrawPosition(True, NULL);
6615 void HighlightDraggingProc(w, event, prms, nprms)
6623 appData.highlightDragging = !appData.highlightDragging;
6625 if (appData.highlightDragging) {
6626 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6628 XtSetArg(args[0], XtNleftBitmap, None);
6630 XtSetValues(XtNameToWidget(menuBarWidget,
6631 "menuOptions.Highlight Dragging"), args, 1);
6635 void HighlightLastMoveProc(w, event, prms, nprms)
6643 appData.highlightLastMove = !appData.highlightLastMove;
6645 if (appData.highlightLastMove) {
6646 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6648 XtSetArg(args[0], XtNleftBitmap, None);
6650 XtSetValues(XtNameToWidget(menuBarWidget,
6651 "menuOptions.Highlight Last Move"), args, 1);
6654 void HighlightArrowProc(w, event, prms, nprms)
6662 appData.highlightMoveWithArrow = !appData.highlightMoveWithArrow;
6664 if (appData.highlightMoveWithArrow) {
6665 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6667 XtSetArg(args[0], XtNleftBitmap, None);
6669 XtSetValues(XtNameToWidget(menuBarWidget,
6670 "menuOptions.Arrow"), args, 1);
6674 void IcsAlarmProc(w, event, prms, nprms)
6682 appData.icsAlarm = !appData.icsAlarm;
6684 if (appData.icsAlarm) {
6685 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6687 XtSetArg(args[0], XtNleftBitmap, None);
6689 XtSetValues(XtNameToWidget(menuBarWidget,
6690 "menuOptions.ICS Alarm"), args, 1);
6694 void MoveSoundProc(w, event, prms, nprms)
6702 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6704 if (appData.ringBellAfterMoves) {
6705 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6707 XtSetArg(args[0], XtNleftBitmap, None);
6709 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6713 void OneClickProc(w, event, prms, nprms)
6721 appData.oneClick = !appData.oneClick;
6723 if (appData.oneClick) {
6724 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6726 XtSetArg(args[0], XtNleftBitmap, None);
6728 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.OneClick"),
6732 void PeriodicUpdatesProc(w, event, prms, nprms)
6740 PeriodicUpdatesEvent(!appData.periodicUpdates);
6742 if (appData.periodicUpdates) {
6743 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6745 XtSetArg(args[0], XtNleftBitmap, None);
6747 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6751 void PonderNextMoveProc(w, event, prms, nprms)
6759 PonderNextMoveEvent(!appData.ponderNextMove);
6761 if (appData.ponderNextMove) {
6762 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6764 XtSetArg(args[0], XtNleftBitmap, None);
6766 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6770 void PopupExitMessageProc(w, event, prms, nprms)
6778 appData.popupExitMessage = !appData.popupExitMessage;
6780 if (appData.popupExitMessage) {
6781 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6783 XtSetArg(args[0], XtNleftBitmap, None);
6785 XtSetValues(XtNameToWidget(menuBarWidget,
6786 "menuOptions.Popup Exit Message"), args, 1);
6789 void PopupMoveErrorsProc(w, event, prms, nprms)
6797 appData.popupMoveErrors = !appData.popupMoveErrors;
6799 if (appData.popupMoveErrors) {
6800 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6802 XtSetArg(args[0], XtNleftBitmap, None);
6804 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6809 void PremoveProc(w, event, prms, nprms)
6817 appData.premove = !appData.premove;
6819 if (appData.premove) {
6820 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6822 XtSetArg(args[0], XtNleftBitmap, None);
6824 XtSetValues(XtNameToWidget(menuBarWidget,
6825 "menuOptions.Premove"), args, 1);
6829 void ShowCoordsProc(w, event, prms, nprms)
6837 appData.showCoords = !appData.showCoords;
6839 if (appData.showCoords) {
6840 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6842 XtSetArg(args[0], XtNleftBitmap, None);
6844 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6847 DrawPosition(True, NULL);
6850 void ShowThinkingProc(w, event, prms, nprms)
6856 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6857 ShowThinkingEvent();
6860 void HideThinkingProc(w, event, prms, nprms)
6868 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6869 ShowThinkingEvent();
6871 if (appData.hideThinkingFromHuman) {
6872 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6874 XtSetArg(args[0], XtNleftBitmap, None);
6876 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6880 void SaveOnExitProc(w, event, prms, nprms)
6888 saveSettingsOnExit = !saveSettingsOnExit;
6890 if (saveSettingsOnExit) {
6891 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6893 XtSetArg(args[0], XtNleftBitmap, None);
6895 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6899 void SaveSettingsProc(w, event, prms, nprms)
6905 SaveSettings(settingsFileName);
6908 void InfoProc(w, event, prms, nprms)
6915 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6920 void ManProc(w, event, prms, nprms)
6928 if (nprms && *nprms > 0)
6932 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6936 void HintProc(w, event, prms, nprms)
6945 void BookProc(w, event, prms, nprms)
6954 void AboutProc(w, event, prms, nprms)
6962 char *zippy = " (with Zippy code)";
6966 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6967 programVersion, zippy,
6968 "Copyright 1991 Digital Equipment Corporation",
6969 "Enhancements Copyright 1992-2009 Free Software Foundation",
6970 "Enhancements Copyright 2005 Alessandro Scotti",
6971 PACKAGE, " is free software and carries NO WARRANTY;",
6972 "see the file COPYING for more information.");
6973 ErrorPopUp(_("About XBoard"), buf, FALSE);
6976 void DebugProc(w, event, prms, nprms)
6982 appData.debugMode = !appData.debugMode;
6985 void AboutGameProc(w, event, prms, nprms)
6994 void NothingProc(w, event, prms, nprms)
7003 void Iconify(w, event, prms, nprms)
7012 XtSetArg(args[0], XtNiconic, True);
7013 XtSetValues(shellWidget, args, 1);
7016 void DisplayMessage(message, extMessage)
7017 char *message, *extMessage;
7019 /* display a message in the message widget */
7028 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
7033 message = extMessage;
7037 /* need to test if messageWidget already exists, since this function
7038 can also be called during the startup, if for example a Xresource
7039 is not set up correctly */
7042 XtSetArg(arg, XtNlabel, message);
7043 XtSetValues(messageWidget, &arg, 1);
7049 void DisplayTitle(text)
7054 char title[MSG_SIZ];
7057 if (text == NULL) text = "";
7059 if (appData.titleInWindow) {
7061 XtSetArg(args[i], XtNlabel, text); i++;
7062 XtSetValues(titleWidget, args, i);
7065 if (*text != NULLCHAR) {
7066 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
7067 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
7068 } else if (appData.icsActive) {
7069 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7070 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7071 } else if (appData.cmailGameName[0] != NULLCHAR) {
7072 snprintf(icon, sizeof(icon), "%s", "CMail");
7073 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7075 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7076 } else if (gameInfo.variant == VariantGothic) {
7077 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7078 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
7081 } else if (gameInfo.variant == VariantFalcon) {
7082 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7083 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
7085 } else if (appData.noChessProgram) {
7086 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7087 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
7089 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
7090 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7093 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7094 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7095 XtSetValues(shellWidget, args, i);
7100 DisplayError(message, error)
7107 if (appData.debugMode || appData.matchMode) {
7108 fprintf(stderr, "%s: %s\n", programName, message);
7111 if (appData.debugMode || appData.matchMode) {
7112 fprintf(stderr, "%s: %s: %s\n",
7113 programName, message, strerror(error));
7115 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7118 ErrorPopUp(_("Error"), message, FALSE);
7122 void DisplayMoveError(message)
7127 DrawPosition(FALSE, NULL);
7128 if (appData.debugMode || appData.matchMode) {
7129 fprintf(stderr, "%s: %s\n", programName, message);
7131 if (appData.popupMoveErrors) {
7132 ErrorPopUp(_("Error"), message, FALSE);
7134 DisplayMessage(message, "");
7139 void DisplayFatalError(message, error, status)
7145 errorExitStatus = status;
7147 fprintf(stderr, "%s: %s\n", programName, message);
7149 fprintf(stderr, "%s: %s: %s\n",
7150 programName, message, strerror(error));
7151 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7154 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7155 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7161 void DisplayInformation(message)
7165 ErrorPopUp(_("Information"), message, TRUE);
7168 void DisplayNote(message)
7172 ErrorPopUp(_("Note"), message, FALSE);
7176 NullXErrorCheck(dpy, error_event)
7178 XErrorEvent *error_event;
7183 void DisplayIcsInteractionTitle(message)
7186 if (oldICSInteractionTitle == NULL) {
7187 /* Magic to find the old window title, adapted from vim */
7188 char *wina = getenv("WINDOWID");
7190 Window win = (Window) atoi(wina);
7191 Window root, parent, *children;
7192 unsigned int nchildren;
7193 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7195 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7196 if (!XQueryTree(xDisplay, win, &root, &parent,
7197 &children, &nchildren)) break;
7198 if (children) XFree((void *)children);
7199 if (parent == root || parent == 0) break;
7202 XSetErrorHandler(oldHandler);
7204 if (oldICSInteractionTitle == NULL) {
7205 oldICSInteractionTitle = "xterm";
7208 printf("\033]0;%s\007", message);
7212 char pendingReplyPrefix[MSG_SIZ];
7213 ProcRef pendingReplyPR;
7215 void AskQuestionProc(w, event, prms, nprms)
7222 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7226 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7229 void AskQuestionPopDown()
7231 if (!askQuestionUp) return;
7232 XtPopdown(askQuestionShell);
7233 XtDestroyWidget(askQuestionShell);
7234 askQuestionUp = False;
7237 void AskQuestionReplyAction(w, event, prms, nprms)
7247 reply = XawDialogGetValueString(w = XtParent(w));
7248 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
7249 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
7250 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
7251 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
7252 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7253 AskQuestionPopDown();
7255 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7258 void AskQuestionCallback(w, client_data, call_data)
7260 XtPointer client_data, call_data;
7265 XtSetArg(args[0], XtNlabel, &name);
7266 XtGetValues(w, args, 1);
7268 if (strcmp(name, _("cancel")) == 0) {
7269 AskQuestionPopDown();
7271 AskQuestionReplyAction(w, NULL, NULL, NULL);
7275 void AskQuestion(title, question, replyPrefix, pr)
7276 char *title, *question, *replyPrefix;
7280 Widget popup, layout, dialog, edit;
7286 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
7287 pendingReplyPR = pr;
7290 XtSetArg(args[i], XtNresizable, True); i++;
7291 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7292 askQuestionShell = popup =
7293 XtCreatePopupShell(title, transientShellWidgetClass,
7294 shellWidget, args, i);
7297 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7298 layoutArgs, XtNumber(layoutArgs));
7301 XtSetArg(args[i], XtNlabel, question); i++;
7302 XtSetArg(args[i], XtNvalue, ""); i++;
7303 XtSetArg(args[i], XtNborderWidth, 0); i++;
7304 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7307 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7308 (XtPointer) dialog);
7309 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7310 (XtPointer) dialog);
7312 XtRealizeWidget(popup);
7313 CatchDeleteWindow(popup, "AskQuestionPopDown");
7315 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7316 &x, &y, &win_x, &win_y, &mask);
7318 XtSetArg(args[0], XtNx, x - 10);
7319 XtSetArg(args[1], XtNy, y - 30);
7320 XtSetValues(popup, args, 2);
7322 XtPopup(popup, XtGrabExclusive);
7323 askQuestionUp = True;
7325 edit = XtNameToWidget(dialog, "*value");
7326 XtSetKeyboardFocus(popup, edit);
7334 if (*name == NULLCHAR) {
7336 } else if (strcmp(name, "$") == 0) {
7337 putc(BELLCHAR, stderr);
7340 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7348 PlaySound(appData.soundMove);
7354 PlaySound(appData.soundIcsWin);
7360 PlaySound(appData.soundIcsLoss);
7366 PlaySound(appData.soundIcsDraw);
7370 PlayIcsUnfinishedSound()
7372 PlaySound(appData.soundIcsUnfinished);
7378 PlaySound(appData.soundIcsAlarm);
7384 system("stty echo");
7390 system("stty -echo");
7394 Colorize(cc, continuation)
7399 int count, outCount, error;
7401 if (textColors[(int)cc].bg > 0) {
7402 if (textColors[(int)cc].fg > 0) {
7403 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7404 textColors[(int)cc].fg, textColors[(int)cc].bg);
7406 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7407 textColors[(int)cc].bg);
7410 if (textColors[(int)cc].fg > 0) {
7411 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7412 textColors[(int)cc].fg);
7414 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7417 count = strlen(buf);
7418 outCount = OutputToProcess(NoProc, buf, count, &error);
7419 if (outCount < count) {
7420 DisplayFatalError(_("Error writing to display"), error, 1);
7423 if (continuation) return;
7426 PlaySound(appData.soundShout);
7429 PlaySound(appData.soundSShout);
7432 PlaySound(appData.soundChannel1);
7435 PlaySound(appData.soundChannel);
7438 PlaySound(appData.soundKibitz);
7441 PlaySound(appData.soundTell);
7443 case ColorChallenge:
7444 PlaySound(appData.soundChallenge);
7447 PlaySound(appData.soundRequest);
7450 PlaySound(appData.soundSeek);
7461 return getpwuid(getuid())->pw_name;
7465 ExpandPathName(path)
7468 static char static_buf[4*MSG_SIZ];
7469 char *d, *s, buf[4*MSG_SIZ];
7475 while (*s && isspace(*s))
7484 if (*(s+1) == '/') {
7485 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7489 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7490 { char *p; if(p = strchr(buf, '/')) *p = 0; }
7491 pwd = getpwnam(buf);
7494 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7498 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7499 strcat(d, strchr(s+1, '/'));
7503 safeStrCpy(d, s, 4*MSG_SIZ );
7510 static char host_name[MSG_SIZ];
7512 #if HAVE_GETHOSTNAME
7513 gethostname(host_name, MSG_SIZ);
7515 #else /* not HAVE_GETHOSTNAME */
7516 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7517 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7519 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7521 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7522 #endif /* not HAVE_GETHOSTNAME */
7525 XtIntervalId delayedEventTimerXID = 0;
7526 DelayedEventCallback delayedEventCallback = 0;
7531 delayedEventTimerXID = 0;
7532 delayedEventCallback();
7536 ScheduleDelayedEvent(cb, millisec)
7537 DelayedEventCallback cb; long millisec;
7539 if(delayedEventTimerXID && delayedEventCallback == cb)
7540 // [HGM] alive: replace, rather than add or flush identical event
7541 XtRemoveTimeOut(delayedEventTimerXID);
7542 delayedEventCallback = cb;
7543 delayedEventTimerXID =
7544 XtAppAddTimeOut(appContext, millisec,
7545 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7548 DelayedEventCallback
7551 if (delayedEventTimerXID) {
7552 return delayedEventCallback;
7559 CancelDelayedEvent()
7561 if (delayedEventTimerXID) {
7562 XtRemoveTimeOut(delayedEventTimerXID);
7563 delayedEventTimerXID = 0;
7567 XtIntervalId loadGameTimerXID = 0;
7569 int LoadGameTimerRunning()
7571 return loadGameTimerXID != 0;
7574 int StopLoadGameTimer()
7576 if (loadGameTimerXID != 0) {
7577 XtRemoveTimeOut(loadGameTimerXID);
7578 loadGameTimerXID = 0;
7586 LoadGameTimerCallback(arg, id)
7590 loadGameTimerXID = 0;
7595 StartLoadGameTimer(millisec)
7599 XtAppAddTimeOut(appContext, millisec,
7600 (XtTimerCallbackProc) LoadGameTimerCallback,
7604 XtIntervalId analysisClockXID = 0;
7607 AnalysisClockCallback(arg, id)
7611 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7612 || appData.icsEngineAnalyze) { // [DM]
7613 AnalysisPeriodicEvent(0);
7614 StartAnalysisClock();
7619 StartAnalysisClock()
7622 XtAppAddTimeOut(appContext, 2000,
7623 (XtTimerCallbackProc) AnalysisClockCallback,
7627 XtIntervalId clockTimerXID = 0;
7629 int ClockTimerRunning()
7631 return clockTimerXID != 0;
7634 int StopClockTimer()
7636 if (clockTimerXID != 0) {
7637 XtRemoveTimeOut(clockTimerXID);
7646 ClockTimerCallback(arg, id)
7655 StartClockTimer(millisec)
7659 XtAppAddTimeOut(appContext, millisec,
7660 (XtTimerCallbackProc) ClockTimerCallback,
7665 DisplayTimerLabel(w, color, timer, highlight)
7674 /* check for low time warning */
7675 Pixel foregroundOrWarningColor = timerForegroundPixel;
7678 appData.lowTimeWarning &&
7679 (timer / 1000) < appData.icsAlarmTime)
7680 foregroundOrWarningColor = lowTimeWarningColor;
7682 if (appData.clockMode) {
7683 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7684 XtSetArg(args[0], XtNlabel, buf);
7686 snprintf(buf, MSG_SIZ, "%s ", color);
7687 XtSetArg(args[0], XtNlabel, buf);
7692 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7693 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7695 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7696 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7699 XtSetValues(w, args, 3);
7703 DisplayWhiteClock(timeRemaining, highlight)
7709 if(appData.noGUI) return;
7710 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7711 if (highlight && iconPixmap == bIconPixmap) {
7712 iconPixmap = wIconPixmap;
7713 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7714 XtSetValues(shellWidget, args, 1);
7719 DisplayBlackClock(timeRemaining, highlight)
7725 if(appData.noGUI) return;
7726 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7727 if (highlight && iconPixmap == wIconPixmap) {
7728 iconPixmap = bIconPixmap;
7729 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7730 XtSetValues(shellWidget, args, 1);
7748 int StartChildProcess(cmdLine, dir, pr)
7755 int to_prog[2], from_prog[2];
7759 if (appData.debugMode) {
7760 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7763 /* We do NOT feed the cmdLine to the shell; we just
7764 parse it into blank-separated arguments in the
7765 most simple-minded way possible.
7768 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7771 while(*p == ' ') p++;
7773 if(*p == '"' || *p == '\'')
7774 p = strchr(++argv[i-1], *p);
7775 else p = strchr(p, ' ');
7776 if (p == NULL) break;
7781 SetUpChildIO(to_prog, from_prog);
7783 if ((pid = fork()) == 0) {
7785 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7786 close(to_prog[1]); // first close the unused pipe ends
7787 close(from_prog[0]);
7788 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7789 dup2(from_prog[1], 1);
7790 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7791 close(from_prog[1]); // and closing again loses one of the pipes!
7792 if(fileno(stderr) >= 2) // better safe than sorry...
7793 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7795 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7800 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7802 execvp(argv[0], argv);
7804 /* If we get here, exec failed */
7809 /* Parent process */
7811 close(from_prog[1]);
7813 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7816 cp->fdFrom = from_prog[0];
7817 cp->fdTo = to_prog[1];
7822 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7823 static RETSIGTYPE AlarmCallBack(int n)
7829 DestroyChildProcess(pr, signalType)
7833 ChildProc *cp = (ChildProc *) pr;
7835 if (cp->kind != CPReal) return;
7837 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7838 signal(SIGALRM, AlarmCallBack);
7840 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7841 kill(cp->pid, SIGKILL); // kill it forcefully
7842 wait((int *) 0); // and wait again
7846 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7848 /* Process is exiting either because of the kill or because of
7849 a quit command sent by the backend; either way, wait for it to die.
7858 InterruptChildProcess(pr)
7861 ChildProc *cp = (ChildProc *) pr;
7863 if (cp->kind != CPReal) return;
7864 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7867 int OpenTelnet(host, port, pr)
7872 char cmdLine[MSG_SIZ];
7874 if (port[0] == NULLCHAR) {
7875 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7877 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7879 return StartChildProcess(cmdLine, "", pr);
7882 int OpenTCP(host, port, pr)
7888 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7889 #else /* !OMIT_SOCKETS */
7891 struct sockaddr_in sa;
7893 unsigned short uport;
7896 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7900 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7901 sa.sin_family = AF_INET;
7902 sa.sin_addr.s_addr = INADDR_ANY;
7903 uport = (unsigned short) 0;
7904 sa.sin_port = htons(uport);
7905 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7909 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7910 if (!(hp = gethostbyname(host))) {
7912 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7913 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7914 hp->h_addrtype = AF_INET;
7916 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7917 hp->h_addr_list[0] = (char *) malloc(4);
7918 hp->h_addr_list[0][0] = b0;
7919 hp->h_addr_list[0][1] = b1;
7920 hp->h_addr_list[0][2] = b2;
7921 hp->h_addr_list[0][3] = b3;
7926 sa.sin_family = hp->h_addrtype;
7927 uport = (unsigned short) atoi(port);
7928 sa.sin_port = htons(uport);
7929 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7931 if (connect(s, (struct sockaddr *) &sa,
7932 sizeof(struct sockaddr_in)) < 0) {
7936 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7943 #endif /* !OMIT_SOCKETS */
7948 int OpenCommPort(name, pr)
7955 fd = open(name, 2, 0);
7956 if (fd < 0) return errno;
7958 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7968 int OpenLoopback(pr)
7974 SetUpChildIO(to, from);
7976 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7979 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7986 int OpenRcmd(host, user, cmd, pr)
7987 char *host, *user, *cmd;
7990 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7994 #define INPUT_SOURCE_BUF_SIZE 8192
8003 char buf[INPUT_SOURCE_BUF_SIZE];
8008 DoInputCallback(closure, source, xid)
8013 InputSource *is = (InputSource *) closure;
8018 if (is->lineByLine) {
8019 count = read(is->fd, is->unused,
8020 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
8022 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
8025 is->unused += count;
8027 while (p < is->unused) {
8028 q = memchr(p, '\n', is->unused - p);
8029 if (q == NULL) break;
8031 (is->func)(is, is->closure, p, q - p, 0);
8035 while (p < is->unused) {
8040 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8045 (is->func)(is, is->closure, is->buf, count, error);
8049 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8056 ChildProc *cp = (ChildProc *) pr;
8058 is = (InputSource *) calloc(1, sizeof(InputSource));
8059 is->lineByLine = lineByLine;
8063 is->fd = fileno(stdin);
8065 is->kind = cp->kind;
8066 is->fd = cp->fdFrom;
8069 is->unused = is->buf;
8072 is->xid = XtAppAddInput(appContext, is->fd,
8073 (XtPointer) (XtInputReadMask),
8074 (XtInputCallbackProc) DoInputCallback,
8076 is->closure = closure;
8077 return (InputSourceRef) is;
8081 RemoveInputSource(isr)
8084 InputSource *is = (InputSource *) isr;
8086 if (is->xid == 0) return;
8087 XtRemoveInput(is->xid);
8091 int OutputToProcess(pr, message, count, outError)
8097 static int line = 0;
8098 ChildProc *cp = (ChildProc *) pr;
8103 if (appData.noJoin || !appData.useInternalWrap)
8104 outCount = fwrite(message, 1, count, stdout);
8107 int width = get_term_width();
8108 int len = wrap(NULL, message, count, width, &line);
8109 char *msg = malloc(len);
8113 outCount = fwrite(message, 1, count, stdout);
8116 dbgchk = wrap(msg, message, count, width, &line);
8117 if (dbgchk != len && appData.debugMode)
8118 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8119 outCount = fwrite(msg, 1, dbgchk, stdout);
8125 outCount = write(cp->fdTo, message, count);
8135 /* Output message to process, with "ms" milliseconds of delay
8136 between each character. This is needed when sending the logon
8137 script to ICC, which for some reason doesn't like the
8138 instantaneous send. */
8139 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8146 ChildProc *cp = (ChildProc *) pr;
8151 r = write(cp->fdTo, message++, 1);
8164 /**** Animation code by Hugh Fisher, DCS, ANU.
8166 Known problem: if a window overlapping the board is
8167 moved away while a piece is being animated underneath,
8168 the newly exposed area won't be updated properly.
8169 I can live with this.
8171 Known problem: if you look carefully at the animation
8172 of pieces in mono mode, they are being drawn as solid
8173 shapes without interior detail while moving. Fixing
8174 this would be a major complication for minimal return.
8177 /* Masks for XPM pieces. Black and white pieces can have
8178 different shapes, but in the interest of retaining my
8179 sanity pieces must have the same outline on both light
8180 and dark squares, and all pieces must use the same
8181 background square colors/images. */
8183 static int xpmDone = 0;
8186 CreateAnimMasks (pieceDepth)
8193 unsigned long plane;
8196 /* Need a bitmap just to get a GC with right depth */
8197 buf = XCreatePixmap(xDisplay, xBoardWindow,
8199 values.foreground = 1;
8200 values.background = 0;
8201 /* Don't use XtGetGC, not read only */
8202 maskGC = XCreateGC(xDisplay, buf,
8203 GCForeground | GCBackground, &values);
8204 XFreePixmap(xDisplay, buf);
8206 buf = XCreatePixmap(xDisplay, xBoardWindow,
8207 squareSize, squareSize, pieceDepth);
8208 values.foreground = XBlackPixel(xDisplay, xScreen);
8209 values.background = XWhitePixel(xDisplay, xScreen);
8210 bufGC = XCreateGC(xDisplay, buf,
8211 GCForeground | GCBackground, &values);
8213 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8214 /* Begin with empty mask */
8215 if(!xpmDone) // [HGM] pieces: keep using existing
8216 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8217 squareSize, squareSize, 1);
8218 XSetFunction(xDisplay, maskGC, GXclear);
8219 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8220 0, 0, squareSize, squareSize);
8222 /* Take a copy of the piece */
8227 XSetFunction(xDisplay, bufGC, GXcopy);
8228 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8230 0, 0, squareSize, squareSize, 0, 0);
8232 /* XOR the background (light) over the piece */
8233 XSetFunction(xDisplay, bufGC, GXxor);
8235 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8236 0, 0, squareSize, squareSize, 0, 0);
8238 XSetForeground(xDisplay, bufGC, lightSquareColor);
8239 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8242 /* We now have an inverted piece image with the background
8243 erased. Construct mask by just selecting all the non-zero
8244 pixels - no need to reconstruct the original image. */
8245 XSetFunction(xDisplay, maskGC, GXor);
8247 /* Might be quicker to download an XImage and create bitmap
8248 data from it rather than this N copies per piece, but it
8249 only takes a fraction of a second and there is a much
8250 longer delay for loading the pieces. */
8251 for (n = 0; n < pieceDepth; n ++) {
8252 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8253 0, 0, squareSize, squareSize,
8259 XFreePixmap(xDisplay, buf);
8260 XFreeGC(xDisplay, bufGC);
8261 XFreeGC(xDisplay, maskGC);
8265 InitAnimState (anim, info)
8267 XWindowAttributes * info;
8272 /* Each buffer is square size, same depth as window */
8273 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8274 squareSize, squareSize, info->depth);
8275 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8276 squareSize, squareSize, info->depth);
8278 /* Create a plain GC for blitting */
8279 mask = GCForeground | GCBackground | GCFunction |
8280 GCPlaneMask | GCGraphicsExposures;
8281 values.foreground = XBlackPixel(xDisplay, xScreen);
8282 values.background = XWhitePixel(xDisplay, xScreen);
8283 values.function = GXcopy;
8284 values.plane_mask = AllPlanes;
8285 values.graphics_exposures = False;
8286 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8288 /* Piece will be copied from an existing context at
8289 the start of each new animation/drag. */
8290 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8292 /* Outline will be a read-only copy of an existing */
8293 anim->outlineGC = None;
8299 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8300 XWindowAttributes info;
8302 if (xpmDone && gameInfo.variant == old) return;
8303 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8304 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8306 InitAnimState(&game, &info);
8307 InitAnimState(&player, &info);
8309 /* For XPM pieces, we need bitmaps to use as masks. */
8311 CreateAnimMasks(info.depth);
8317 static Boolean frameWaiting;
8319 static RETSIGTYPE FrameAlarm (sig)
8322 frameWaiting = False;
8323 /* In case System-V style signals. Needed?? */
8324 signal(SIGALRM, FrameAlarm);
8331 struct itimerval delay;
8333 XSync(xDisplay, False);
8336 frameWaiting = True;
8337 signal(SIGALRM, FrameAlarm);
8338 delay.it_interval.tv_sec =
8339 delay.it_value.tv_sec = time / 1000;
8340 delay.it_interval.tv_usec =
8341 delay.it_value.tv_usec = (time % 1000) * 1000;
8342 setitimer(ITIMER_REAL, &delay, NULL);
8343 while (frameWaiting) pause();
8344 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8345 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8346 setitimer(ITIMER_REAL, &delay, NULL);
8356 XSync(xDisplay, False);
8358 usleep(time * 1000);
8363 /* Convert board position to corner of screen rect and color */
8366 ScreenSquare(column, row, pt, color)
8367 int column; int row; XPoint * pt; int * color;
8370 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8371 pt->y = lineGap + row * (squareSize + lineGap);
8373 pt->x = lineGap + column * (squareSize + lineGap);
8374 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8376 *color = SquareColor(row, column);
8379 /* Convert window coords to square */
8382 BoardSquare(x, y, column, row)
8383 int x; int y; int * column; int * row;
8385 *column = EventToSquare(x, BOARD_WIDTH);
8386 if (flipView && *column >= 0)
8387 *column = BOARD_WIDTH - 1 - *column;
8388 *row = EventToSquare(y, BOARD_HEIGHT);
8389 if (!flipView && *row >= 0)
8390 *row = BOARD_HEIGHT - 1 - *row;
8395 #undef Max /* just in case */
8397 #define Max(a, b) ((a) > (b) ? (a) : (b))
8398 #define Min(a, b) ((a) < (b) ? (a) : (b))
8401 SetRect(rect, x, y, width, height)
8402 XRectangle * rect; int x; int y; int width; int height;
8406 rect->width = width;
8407 rect->height = height;
8410 /* Test if two frames overlap. If they do, return
8411 intersection rect within old and location of
8412 that rect within new. */
8415 Intersect(old, new, size, area, pt)
8416 XPoint * old; XPoint * new;
8417 int size; XRectangle * area; XPoint * pt;
8419 if (old->x > new->x + size || new->x > old->x + size ||
8420 old->y > new->y + size || new->y > old->y + size) {
8423 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8424 size - abs(old->x - new->x), size - abs(old->y - new->y));
8425 pt->x = Max(old->x - new->x, 0);
8426 pt->y = Max(old->y - new->y, 0);
8431 /* For two overlapping frames, return the rect(s)
8432 in the old that do not intersect with the new. */
8435 CalcUpdateRects(old, new, size, update, nUpdates)
8436 XPoint * old; XPoint * new; int size;
8437 XRectangle update[]; int * nUpdates;
8441 /* If old = new (shouldn't happen) then nothing to draw */
8442 if (old->x == new->x && old->y == new->y) {
8446 /* Work out what bits overlap. Since we know the rects
8447 are the same size we don't need a full intersect calc. */
8449 /* Top or bottom edge? */
8450 if (new->y > old->y) {
8451 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8453 } else if (old->y > new->y) {
8454 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8455 size, old->y - new->y);
8458 /* Left or right edge - don't overlap any update calculated above. */
8459 if (new->x > old->x) {
8460 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8461 new->x - old->x, size - abs(new->y - old->y));
8463 } else if (old->x > new->x) {
8464 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8465 old->x - new->x, size - abs(new->y - old->y));
8472 /* Generate a series of frame coords from start->mid->finish.
8473 The movement rate doubles until the half way point is
8474 reached, then halves back down to the final destination,
8475 which gives a nice slow in/out effect. The algorithmn
8476 may seem to generate too many intermediates for short
8477 moves, but remember that the purpose is to attract the
8478 viewers attention to the piece about to be moved and
8479 then to where it ends up. Too few frames would be less
8483 Tween(start, mid, finish, factor, frames, nFrames)
8484 XPoint * start; XPoint * mid;
8485 XPoint * finish; int factor;
8486 XPoint frames[]; int * nFrames;
8488 int fraction, n, count;
8492 /* Slow in, stepping 1/16th, then 1/8th, ... */
8494 for (n = 0; n < factor; n++)
8496 for (n = 0; n < factor; n++) {
8497 frames[count].x = start->x + (mid->x - start->x) / fraction;
8498 frames[count].y = start->y + (mid->y - start->y) / fraction;
8500 fraction = fraction / 2;
8504 frames[count] = *mid;
8507 /* Slow out, stepping 1/2, then 1/4, ... */
8509 for (n = 0; n < factor; n++) {
8510 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8511 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8513 fraction = fraction * 2;
8518 /* Draw a piece on the screen without disturbing what's there */
8521 SelectGCMask(piece, clip, outline, mask)
8522 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8526 /* Bitmap for piece being moved. */
8527 if (appData.monoMode) {
8528 *mask = *pieceToSolid(piece);
8529 } else if (useImages) {
8531 *mask = xpmMask[piece];
8533 *mask = ximMaskPm[piece];
8536 *mask = *pieceToSolid(piece);
8539 /* GC for piece being moved. Square color doesn't matter, but
8540 since it gets modified we make a copy of the original. */
8542 if (appData.monoMode)
8547 if (appData.monoMode)
8552 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8554 /* Outline only used in mono mode and is not modified */
8556 *outline = bwPieceGC;
8558 *outline = wbPieceGC;
8562 OverlayPiece(piece, clip, outline, dest)
8563 ChessSquare piece; GC clip; GC outline; Drawable dest;
8568 /* Draw solid rectangle which will be clipped to shape of piece */
8569 XFillRectangle(xDisplay, dest, clip,
8570 0, 0, squareSize, squareSize);
8571 if (appData.monoMode)
8572 /* Also draw outline in contrasting color for black
8573 on black / white on white cases */
8574 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8575 0, 0, squareSize, squareSize, 0, 0, 1);
8577 /* Copy the piece */
8582 if(appData.upsideDown && flipView) kind ^= 2;
8583 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8585 0, 0, squareSize, squareSize,
8590 /* Animate the movement of a single piece */
8593 BeginAnimation(anim, piece, startColor, start)
8601 if(appData.upsideDown && flipView) piece += piece < BlackPawn ? BlackPawn : -BlackPawn;
8602 /* The old buffer is initialised with the start square (empty) */
8603 BlankSquare(start->x, start->y, startColor, EmptySquare, anim->saveBuf, 0);
8604 anim->prevFrame = *start;
8606 /* The piece will be drawn using its own bitmap as a matte */
8607 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8608 XSetClipMask(xDisplay, anim->pieceGC, mask);
8612 AnimationFrame(anim, frame, piece)
8617 XRectangle updates[4];
8622 /* Save what we are about to draw into the new buffer */
8623 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8624 frame->x, frame->y, squareSize, squareSize,
8627 /* Erase bits of the previous frame */
8628 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8629 /* Where the new frame overlapped the previous,
8630 the contents in newBuf are wrong. */
8631 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8632 overlap.x, overlap.y,
8633 overlap.width, overlap.height,
8635 /* Repaint the areas in the old that don't overlap new */
8636 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8637 for (i = 0; i < count; i++)
8638 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8639 updates[i].x - anim->prevFrame.x,
8640 updates[i].y - anim->prevFrame.y,
8641 updates[i].width, updates[i].height,
8642 updates[i].x, updates[i].y);
8644 /* Easy when no overlap */
8645 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8646 0, 0, squareSize, squareSize,
8647 anim->prevFrame.x, anim->prevFrame.y);
8650 /* Save this frame for next time round */
8651 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8652 0, 0, squareSize, squareSize,
8654 anim->prevFrame = *frame;
8656 /* Draw piece over original screen contents, not current,
8657 and copy entire rect. Wipes out overlapping piece images. */
8658 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8659 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8660 0, 0, squareSize, squareSize,
8661 frame->x, frame->y);
8665 EndAnimation (anim, finish)
8669 XRectangle updates[4];
8674 /* The main code will redraw the final square, so we
8675 only need to erase the bits that don't overlap. */
8676 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8677 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8678 for (i = 0; i < count; i++)
8679 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8680 updates[i].x - anim->prevFrame.x,
8681 updates[i].y - anim->prevFrame.y,
8682 updates[i].width, updates[i].height,
8683 updates[i].x, updates[i].y);
8685 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8686 0, 0, squareSize, squareSize,
8687 anim->prevFrame.x, anim->prevFrame.y);
8692 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8694 ChessSquare piece; int startColor;
8695 XPoint * start; XPoint * finish;
8696 XPoint frames[]; int nFrames;
8700 BeginAnimation(anim, piece, startColor, start);
8701 for (n = 0; n < nFrames; n++) {
8702 AnimationFrame(anim, &(frames[n]), piece);
8703 FrameDelay(appData.animSpeed);
8705 EndAnimation(anim, finish);
8709 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
8712 ChessSquare piece = board[fromY][toY];
8713 board[fromY][toY] = EmptySquare;
8714 DrawPosition(FALSE, board);
8716 x = lineGap + ((BOARD_WIDTH-1)-toX) * (squareSize + lineGap);
8717 y = lineGap + toY * (squareSize + lineGap);
8719 x = lineGap + toX * (squareSize + lineGap);
8720 y = lineGap + ((BOARD_HEIGHT-1)-toY) * (squareSize + lineGap);
8722 for(i=1; i<4*kFactor; i++) {
8723 int r = squareSize * 9 * i/(20*kFactor - 5);
8724 XFillArc(xDisplay, xBoardWindow, highlineGC,
8725 x + squareSize/2 - r, y+squareSize/2 - r, 2*r, 2*r, 0, 64*360);
8726 FrameDelay(appData.animSpeed);
8728 board[fromY][toY] = piece;
8731 /* Main control logic for deciding what to animate and how */
8734 AnimateMove(board, fromX, fromY, toX, toY)
8743 XPoint start, finish, mid;
8744 XPoint frames[kFactor * 2 + 1];
8745 int nFrames, startColor, endColor;
8747 /* Are we animating? */
8748 if (!appData.animate || appData.blindfold)
8751 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8752 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8753 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8755 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8756 piece = board[fromY][fromX];
8757 if (piece >= EmptySquare) return;
8762 hop = abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1;
8765 if (appData.debugMode) {
8766 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8767 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8768 piece, fromX, fromY, toX, toY); }
8770 ScreenSquare(fromX, fromY, &start, &startColor);
8771 ScreenSquare(toX, toY, &finish, &endColor);
8774 /* Knight: make straight movement then diagonal */
8775 if (abs(toY - fromY) < abs(toX - fromX)) {
8776 mid.x = start.x + (finish.x - start.x) / 2;
8780 mid.y = start.y + (finish.y - start.y) / 2;
8783 mid.x = start.x + (finish.x - start.x) / 2;
8784 mid.y = start.y + (finish.y - start.y) / 2;
8787 /* Don't use as many frames for very short moves */
8788 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8789 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8791 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8792 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8793 if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged
8795 for(i=0; i<BOARD_WIDTH; i++) for(j=0; j<BOARD_HEIGHT; j++)
8796 if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] = True;
8799 /* Be sure end square is redrawn */
8800 damage[0][toY][toX] = True;
8804 DragPieceBegin(x, y)
8807 int boardX, boardY, color;
8810 /* Are we animating? */
8811 if (!appData.animateDragging || appData.blindfold)
8814 /* Figure out which square we start in and the
8815 mouse position relative to top left corner. */
8816 BoardSquare(x, y, &boardX, &boardY);
8817 player.startBoardX = boardX;
8818 player.startBoardY = boardY;
8819 ScreenSquare(boardX, boardY, &corner, &color);
8820 player.startSquare = corner;
8821 player.startColor = color;
8822 /* As soon as we start dragging, the piece will jump slightly to
8823 be centered over the mouse pointer. */
8824 player.mouseDelta.x = squareSize/2;
8825 player.mouseDelta.y = squareSize/2;
8826 /* Initialise animation */
8827 player.dragPiece = PieceForSquare(boardX, boardY);
8829 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8830 player.dragActive = True;
8831 BeginAnimation(&player, player.dragPiece, color, &corner);
8832 /* Mark this square as needing to be redrawn. Note that
8833 we don't remove the piece though, since logically (ie
8834 as seen by opponent) the move hasn't been made yet. */
8835 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8836 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8837 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8838 corner.x, corner.y, squareSize, squareSize,
8839 0, 0); // [HGM] zh: unstack in stead of grab
8840 if(gatingPiece != EmptySquare) {
8841 /* Kludge alert: When gating we want the introduced
8842 piece to appear on the from square. To generate an
8843 image of it, we draw it on the board, copy the image,
8844 and draw the original piece again. */
8845 ChessSquare piece = boards[currentMove][boardY][boardX];
8846 DrawSquare(boardY, boardX, gatingPiece, 0);
8847 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8848 corner.x, corner.y, squareSize, squareSize, 0, 0);
8849 DrawSquare(boardY, boardX, piece, 0);
8851 damage[0][boardY][boardX] = True;
8853 player.dragActive = False;
8863 /* Are we animating? */
8864 if (!appData.animateDragging || appData.blindfold)
8868 if (! player.dragActive)
8870 /* Move piece, maintaining same relative position
8871 of mouse within square */
8872 corner.x = x - player.mouseDelta.x;
8873 corner.y = y - player.mouseDelta.y;
8874 AnimationFrame(&player, &corner, player.dragPiece);
8876 if (appData.highlightDragging) {
8878 BoardSquare(x, y, &boardX, &boardY);
8879 SetHighlights(fromX, fromY, boardX, boardY);
8888 int boardX, boardY, color;
8891 /* Are we animating? */
8892 if (!appData.animateDragging || appData.blindfold)
8896 if (! player.dragActive)
8898 /* Last frame in sequence is square piece is
8899 placed on, which may not match mouse exactly. */
8900 BoardSquare(x, y, &boardX, &boardY);
8901 ScreenSquare(boardX, boardY, &corner, &color);
8902 EndAnimation(&player, &corner);
8904 /* Be sure end square is redrawn */
8905 damage[0][boardY][boardX] = True;
8907 /* This prevents weird things happening with fast successive
8908 clicks which on my Sun at least can cause motion events
8909 without corresponding press/release. */
8910 player.dragActive = False;
8913 /* Handle expose event while piece being dragged */
8918 if (!player.dragActive || appData.blindfold)
8921 /* What we're doing: logically, the move hasn't been made yet,
8922 so the piece is still in it's original square. But visually
8923 it's being dragged around the board. So we erase the square
8924 that the piece is on and draw it at the last known drag point. */
8925 BlankSquare(player.startSquare.x, player.startSquare.y,
8926 player.startColor, EmptySquare, xBoardWindow, 1);
8927 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8928 damage[0][player.startBoardY][player.startBoardX] = TRUE;
8931 #include <sys/ioctl.h>
8932 int get_term_width()
8934 int fd, default_width;
8937 default_width = 79; // this is FICS default anyway...
8939 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8941 if (!ioctl(fd, TIOCGSIZE, &win))
8942 default_width = win.ts_cols;
8943 #elif defined(TIOCGWINSZ)
8945 if (!ioctl(fd, TIOCGWINSZ, &win))
8946 default_width = win.ws_col;
8948 return default_width;
8954 static int old_width = 0;
8955 int new_width = get_term_width();
8957 if (old_width != new_width)
8958 ics_printf("set width %d\n", new_width);
8959 old_width = new_width;
8962 void NotifyFrontendLogin()
8967 /* [AS] Arrow highlighting support */
8969 static double A_WIDTH = 5; /* Width of arrow body */
8971 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
8972 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
8974 static double Sqr( double x )
8979 static int Round( double x )
8981 return (int) (x + 0.5);
8984 void SquareToPos(int rank, int file, int *x, int *y)
8987 *x = lineGap + ((BOARD_WIDTH-1)-file) * (squareSize + lineGap);
8988 *y = lineGap + rank * (squareSize + lineGap);
8990 *x = lineGap + file * (squareSize + lineGap);
8991 *y = lineGap + ((BOARD_HEIGHT-1)-rank) * (squareSize + lineGap);
8995 /* Draw an arrow between two points using current settings */
8996 void DrawArrowBetweenPoints( int s_x, int s_y, int d_x, int d_y )
8999 double dx, dy, j, k, x, y;
9002 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
9004 arrow[0].x = s_x + A_WIDTH + 0.5;
9007 arrow[1].x = s_x + A_WIDTH + 0.5;
9008 arrow[1].y = d_y - h;
9010 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9011 arrow[2].y = d_y - h;
9016 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
9017 arrow[5].y = d_y - h;
9019 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9020 arrow[4].y = d_y - h;
9022 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
9025 else if( d_y == s_y ) {
9026 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
9029 arrow[0].y = s_y + A_WIDTH + 0.5;
9031 arrow[1].x = d_x - w;
9032 arrow[1].y = s_y + A_WIDTH + 0.5;
9034 arrow[2].x = d_x - w;
9035 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9040 arrow[5].x = d_x - w;
9041 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
9043 arrow[4].x = d_x - w;
9044 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9047 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
9050 /* [AS] Needed a lot of paper for this! :-) */
9051 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
9052 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
9054 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
9056 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
9061 arrow[0].x = Round(x - j);
9062 arrow[0].y = Round(y + j*dx);
9064 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
9065 arrow[1].y = Round(arrow[0].y - 2*j*dx);
9068 x = (double) d_x - k;
9069 y = (double) d_y - k*dy;
9072 x = (double) d_x + k;
9073 y = (double) d_y + k*dy;
9076 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
9078 arrow[6].x = Round(x - j);
9079 arrow[6].y = Round(y + j*dx);
9081 arrow[2].x = Round(arrow[6].x + 2*j);
9082 arrow[2].y = Round(arrow[6].y - 2*j*dx);
9084 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
9085 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
9090 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
9091 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
9094 XFillPolygon(xDisplay, xBoardWindow, highlineGC, arrow, 7, Nonconvex, CoordModeOrigin);
9095 // Polygon( hdc, arrow, 7 );
9098 /* [AS] Draw an arrow between two squares */
9099 void DrawArrowBetweenSquares( int s_col, int s_row, int d_col, int d_row )
9101 int s_x, s_y, d_x, d_y, hor, vert, i;
9103 if( s_col == d_col && s_row == d_row ) {
9107 /* Get source and destination points */
9108 SquareToPos( s_row, s_col, &s_x, &s_y);
9109 SquareToPos( d_row, d_col, &d_x, &d_y);
9112 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
9114 else if( d_y < s_y ) {
9115 d_y += squareSize / 2 + squareSize / 4;
9118 d_y += squareSize / 2;
9122 d_x += squareSize / 2 - squareSize / 4;
9124 else if( d_x < s_x ) {
9125 d_x += squareSize / 2 + squareSize / 4;
9128 d_x += squareSize / 2;
9131 s_x += squareSize / 2;
9132 s_y += squareSize / 2;
9135 A_WIDTH = squareSize / 14.; //[HGM] make float
9137 DrawArrowBetweenPoints( s_x, s_y, d_x, d_y );
9139 hor = 64*s_col + 32; vert = 64*s_row + 32;
9140 for(i=0; i<= 64; i++) {
9141 damage[0][vert+6>>6][hor+6>>6] = True;
9142 damage[0][vert-6>>6][hor+6>>6] = True;
9143 damage[0][vert+6>>6][hor-6>>6] = True;
9144 damage[0][vert-6>>6][hor-6>>6] = True;
9145 hor += d_col - s_col; vert += d_row - s_row;
9149 Boolean IsDrawArrowEnabled()
9151 return appData.highlightMoveWithArrow && squareSize >= 32;
9154 void DrawArrowHighlight(int fromX, int fromY, int toX,int toY)
9156 if( IsDrawArrowEnabled() && fromX >= 0 && fromY >= 0 && toX >= 0 && toY >= 0)
9157 DrawArrowBetweenSquares(fromX, fromY, toX, toY);