2 * xboard.c -- X front end for XBoard
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
8 * 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
10 * The following terms apply to Digital Equipment Corporation's copyright
12 * ------------------------------------------------------------------------
15 * Permission to use, copy, modify, and distribute this software and its
16 * documentation for any purpose and without fee is hereby granted,
17 * provided that the above copyright notice appear in all copies and that
18 * both that copyright notice and this permission notice appear in
19 * supporting documentation, and that the name of Digital not be
20 * used in advertising or publicity pertaining to distribution of the
21 * software without specific, written prior permission.
23 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
30 * ------------------------------------------------------------------------
32 * The following terms apply to the enhanced version of XBoard
33 * distributed by the Free Software Foundation:
34 * ------------------------------------------------------------------------
36 * GNU XBoard is free software: you can redistribute it and/or modify
37 * it under the terms of the GNU General Public License as published by
38 * the Free Software Foundation, either version 3 of the License, or (at
39 * your option) any later version.
41 * GNU XBoard is distributed in the hope that it will be useful, but
42 * WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44 * General Public License for more details.
46 * You should have received a copy of the GNU General Public License
47 * along with this program. If not, see http://www.gnu.org/licenses/. *
49 *------------------------------------------------------------------------
50 ** See the file ChangeLog for a revision history. */
60 #include <sys/types.h>
66 # if HAVE_SYS_SOCKET_H
67 # include <sys/socket.h>
68 # include <netinet/in.h>
70 # else /* not HAVE_SYS_SOCKET_H */
71 # if HAVE_LAN_SOCKET_H
72 # include <lan/socket.h>
74 # include <lan/netdb.h>
75 # else /* not HAVE_LAN_SOCKET_H */
76 # define OMIT_SOCKETS 1
77 # endif /* not HAVE_LAN_SOCKET_H */
78 # endif /* not HAVE_SYS_SOCKET_H */
79 #endif /* !OMIT_SOCKETS */
84 #else /* not STDC_HEADERS */
85 extern char *getenv();
88 # else /* not HAVE_STRING_H */
90 # endif /* not HAVE_STRING_H */
91 #endif /* not STDC_HEADERS */
94 # include <sys/fcntl.h>
95 #else /* not HAVE_SYS_FCNTL_H */
98 # endif /* HAVE_FCNTL_H */
99 #endif /* not HAVE_SYS_FCNTL_H */
101 #if HAVE_SYS_SYSTEMINFO_H
102 # include <sys/systeminfo.h>
103 #endif /* HAVE_SYS_SYSTEMINFO_H */
105 #if TIME_WITH_SYS_TIME
106 # include <sys/time.h>
110 # include <sys/time.h>
121 # include <sys/wait.h>
126 # define NAMLEN(dirent) strlen((dirent)->d_name)
127 # define HAVE_DIR_STRUCT
129 # define dirent direct
130 # define NAMLEN(dirent) (dirent)->d_namlen
132 # include <sys/ndir.h>
133 # define HAVE_DIR_STRUCT
136 # include <sys/dir.h>
137 # define HAVE_DIR_STRUCT
141 # define HAVE_DIR_STRUCT
145 #include <X11/Intrinsic.h>
146 #include <X11/StringDefs.h>
147 #include <X11/Shell.h>
148 #include <X11/cursorfont.h>
149 #include <X11/Xatom.h>
150 #include <X11/Xmu/Atoms.h>
152 #include <X11/Xaw3d/Dialog.h>
153 #include <X11/Xaw3d/Form.h>
154 #include <X11/Xaw3d/List.h>
155 #include <X11/Xaw3d/Label.h>
156 #include <X11/Xaw3d/SimpleMenu.h>
157 #include <X11/Xaw3d/SmeBSB.h>
158 #include <X11/Xaw3d/SmeLine.h>
159 #include <X11/Xaw3d/Box.h>
160 #include <X11/Xaw3d/MenuButton.h>
161 #include <X11/Xaw3d/Text.h>
162 #include <X11/Xaw3d/AsciiText.h>
164 #include <X11/Xaw/Dialog.h>
165 #include <X11/Xaw/Form.h>
166 #include <X11/Xaw/List.h>
167 #include <X11/Xaw/Label.h>
168 #include <X11/Xaw/SimpleMenu.h>
169 #include <X11/Xaw/SmeBSB.h>
170 #include <X11/Xaw/SmeLine.h>
171 #include <X11/Xaw/Box.h>
172 #include <X11/Xaw/MenuButton.h>
173 #include <X11/Xaw/Text.h>
174 #include <X11/Xaw/AsciiText.h>
177 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
182 #include "pixmaps/pixmaps.h"
183 #define IMAGE_EXT "xpm"
185 #define IMAGE_EXT "xim"
186 #include "bitmaps/bitmaps.h"
189 #include "bitmaps/icon_white.bm"
190 #include "bitmaps/icon_black.bm"
191 #include "bitmaps/checkmark.bm"
193 #include "frontend.h"
195 #include "backendz.h"
199 #include "xgamelist.h"
200 #include "xhistory.h"
201 #include "xedittags.h"
204 // must be moved to xengineoutput.h
206 void EngineOutputProc P((Widget w, XEvent *event,
207 String *prms, Cardinal *nprms));
208 void EvalGraphProc P((Widget w, XEvent *event,
209 String *prms, Cardinal *nprms));
216 #define usleep(t) _sleep2(((t)+500)/1000)
220 # define _(s) gettext (s)
221 # define N_(s) gettext_noop (s)
239 int main P((int argc, char **argv));
240 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
241 char *init_path, char *mode, int (*show_entry)(), char **name_return));
242 RETSIGTYPE CmailSigHandler P((int sig));
243 RETSIGTYPE IntSigHandler P((int sig));
244 RETSIGTYPE TermSizeSigHandler P((int sig));
245 void CreateGCs P((int redo));
246 void CreateXIMPieces P((void));
247 void CreateXPMPieces P((void));
248 void CreateXPMBoard P((char *s, int n));
249 void CreatePieces P((void));
250 void CreatePieceMenus P((void));
251 Widget CreateMenuBar P((Menu *mb));
252 Widget CreateButtonBar P ((MenuItem *mi));
253 char *FindFont P((char *pattern, int targetPxlSize));
254 void PieceMenuPopup P((Widget w, XEvent *event,
255 String *params, Cardinal *num_params));
256 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
257 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
258 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
259 u_int wreq, u_int hreq));
260 void CreateGrid P((void));
261 int EventToSquare P((int x, int limit));
262 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
263 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
264 void HandleUserMove P((Widget w, XEvent *event,
265 String *prms, Cardinal *nprms));
266 void AnimateUserMove P((Widget w, XEvent * event,
267 String * params, Cardinal * nParams));
268 void HandlePV P((Widget w, XEvent * event,
269 String * params, Cardinal * nParams));
270 void SelectPV P((Widget w, XEvent * event,
271 String * params, Cardinal * nParams));
272 void StopPV P((Widget w, XEvent * event,
273 String * params, Cardinal * nParams));
274 void WhiteClock P((Widget w, XEvent *event,
275 String *prms, Cardinal *nprms));
276 void BlackClock P((Widget w, XEvent *event,
277 String *prms, Cardinal *nprms));
278 void DrawPositionProc P((Widget w, XEvent *event,
279 String *prms, Cardinal *nprms));
280 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
282 void CommentClick P((Widget w, XEvent * event,
283 String * params, Cardinal * nParams));
284 void CommentPopUp P((char *title, char *label));
285 void CommentPopDown P((void));
286 void CommentCallback P((Widget w, XtPointer client_data,
287 XtPointer call_data));
288 void ICSInputBoxPopUp P((void));
289 void ICSInputBoxPopDown P((void));
290 void FileNamePopUp P((char *label, char *def,
291 FileProc proc, char *openMode));
292 void FileNamePopDown P((void));
293 void FileNameCallback P((Widget w, XtPointer client_data,
294 XtPointer call_data));
295 void FileNameAction P((Widget w, XEvent *event,
296 String *prms, Cardinal *nprms));
297 void AskQuestionReplyAction P((Widget w, XEvent *event,
298 String *prms, Cardinal *nprms));
299 void AskQuestionProc P((Widget w, XEvent *event,
300 String *prms, Cardinal *nprms));
301 void AskQuestionPopDown P((void));
302 void PromotionPopDown P((void));
303 void PromotionCallback P((Widget w, XtPointer client_data,
304 XtPointer call_data));
305 void EditCommentPopDown P((void));
306 void EditCommentCallback P((Widget w, XtPointer client_data,
307 XtPointer call_data));
308 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
309 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
310 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
311 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
313 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
315 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
317 void LoadPositionProc P((Widget w, XEvent *event,
318 String *prms, Cardinal *nprms));
319 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
321 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
323 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
325 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
327 void PastePositionProc P((Widget w, XEvent *event, String *prms,
329 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
330 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
331 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
332 void SavePositionProc P((Widget w, XEvent *event,
333 String *prms, Cardinal *nprms));
334 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
335 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
337 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
338 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
339 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
341 void MachineWhiteProc P((Widget w, XEvent *event,
342 String *prms, Cardinal *nprms));
343 void AnalyzeModeProc P((Widget w, XEvent *event,
344 String *prms, Cardinal *nprms));
345 void AnalyzeFileProc P((Widget w, XEvent *event,
346 String *prms, Cardinal *nprms));
347 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
349 void IcsClientProc P((Widget w, XEvent *event, String *prms,
351 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
352 void EditPositionProc P((Widget w, XEvent *event,
353 String *prms, Cardinal *nprms));
354 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
355 void EditCommentProc P((Widget w, XEvent *event,
356 String *prms, Cardinal *nprms));
357 void IcsInputBoxProc P((Widget w, XEvent *event,
358 String *prms, Cardinal *nprms));
359 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
365 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
369 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
370 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
371 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
372 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
373 void StopObservingProc P((Widget w, XEvent *event, String *prms,
375 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
377 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
379 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
380 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
384 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
386 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
388 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
389 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
391 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
393 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
395 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
396 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
397 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
398 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
400 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
401 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
403 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
405 void HighlightArrowProc P((Widget w, XEvent *event, String *prms,
407 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
408 //void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
409 void OneClickProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
410 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
412 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
414 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
416 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
418 //void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
419 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
421 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
423 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
425 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
427 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
428 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
429 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
430 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
431 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
432 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
433 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
434 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
435 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
436 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
437 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void DisplayMove P((int moveNumber));
439 void DisplayTitle P((char *title));
440 void ICSInitScript P((void));
441 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
442 void ErrorPopUp P((char *title, char *text, int modal));
443 void ErrorPopDown P((void));
444 static char *ExpandPathName P((char *path));
445 static void CreateAnimVars P((void));
446 static void DragPieceMove P((int x, int y));
447 static void DrawDragPiece P((void));
448 char *ModeToWidgetName P((GameMode mode));
449 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
450 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
451 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
452 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
453 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
454 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
455 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
456 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
457 void IcsOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
458 void SoundOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
459 void BoardOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
460 void LoadOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
461 void SaveOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
462 void GameListOptionsPopDown P(());
463 void ShufflePopDown P(());
464 void EnginePopDown P(());
465 void UciPopDown P(());
466 void TimeControlPopDown P(());
467 void NewVariantPopDown P(());
468 void SettingsPopDown P(());
469 void update_ics_width P(());
470 int get_term_width P(());
471 int CopyMemoProc P(());
472 void DrawArrowHighlight P((int fromX, int fromY, int toX,int toY));
473 Boolean IsDrawArrowEnabled P(());
476 * XBoard depends on Xt R4 or higher
478 int xtVersion = XtSpecificationRelease;
483 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
484 jailSquareColor, highlightSquareColor, premoveHighlightColor;
485 Pixel lowTimeWarningColor;
486 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
487 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
488 wjPieceGC, bjPieceGC, prelineGC, countGC;
489 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
490 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
491 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
492 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
493 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
494 ICSInputShell, fileNameShell, askQuestionShell;
495 Widget historyShell, evalGraphShell, gameListShell;
496 int hOffset; // [HGM] dual
497 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
498 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
499 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
500 Font clockFontID, coordFontID, countFontID;
501 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
502 XtAppContext appContext;
504 char *oldICSInteractionTitle;
508 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
510 Position commentX = -1, commentY = -1;
511 Dimension commentW, commentH;
512 typedef unsigned int BoardSize;
514 Boolean chessProgram;
516 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
517 int squareSize, smallLayout = 0, tinyLayout = 0,
518 marginW, marginH, // [HGM] for run-time resizing
519 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
520 ICSInputBoxUp = False, askQuestionUp = False,
521 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
522 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
523 Pixel timerForegroundPixel, timerBackgroundPixel;
524 Pixel buttonForegroundPixel, buttonBackgroundPixel;
525 char *chessDir, *programName, *programVersion,
526 *gameCopyFilename, *gamePasteFilename;
527 Boolean alwaysOnTop = False;
528 Boolean saveSettingsOnExit;
529 char *settingsFileName;
530 char *icsTextMenuString;
532 char *firstChessProgramNames;
533 char *secondChessProgramNames;
535 WindowPlacement wpMain;
536 WindowPlacement wpConsole;
537 WindowPlacement wpComment;
538 WindowPlacement wpMoveHistory;
539 WindowPlacement wpEvalGraph;
540 WindowPlacement wpEngineOutput;
541 WindowPlacement wpGameList;
542 WindowPlacement wpTags;
546 Pixmap pieceBitmap[2][(int)BlackPawn];
547 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
548 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
549 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
550 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
551 Pixmap xpmBoardBitmap[2];
552 int useImages, useImageSqs, useTexture, textureW[2], textureH[2];
553 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
554 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
555 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
556 XImage *ximLightSquare, *ximDarkSquare;
559 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
560 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
562 #define White(piece) ((int)(piece) < (int)BlackPawn)
564 /* Variables for doing smooth animation. This whole thing
565 would be much easier if the board was double-buffered,
566 but that would require a fairly major rewrite. */
571 GC blitGC, pieceGC, outlineGC;
572 XPoint startSquare, prevFrame, mouseDelta;
576 int startBoardX, startBoardY;
579 /* There can be two pieces being animated at once: a player
580 can begin dragging a piece before the remote opponent has moved. */
582 static AnimState game, player;
584 /* Bitmaps for use as masks when drawing XPM pieces.
585 Need one for each black and white piece. */
586 static Pixmap xpmMask[BlackKing + 1];
588 /* This magic number is the number of intermediate frames used
589 in each half of the animation. For short moves it's reduced
590 by 1. The total number of frames will be factor * 2 + 1. */
593 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
595 MenuItem fileMenu[] = {
596 {N_("New Game Ctrl+N"), "New Game", ResetProc},
597 {N_("New Shuffle Game ..."), "New Shuffle Game", ShuffleMenuProc},
598 {N_("New Variant ... Alt+Shift+V"), "New Variant", NewVariantProc}, // [HGM] variant: not functional yet
599 {"----", NULL, NothingProc},
600 {N_("Load Game Ctrl+O"), "Load Game", LoadGameProc},
601 {N_("Load Position Ctrl+Shift+O"), "Load Position", LoadPositionProc},
602 // {N_("Load Next Game"), "Load Next Game", LoadNextGameProc},
603 // {N_("Load Previous Game"), "Load Previous Game", LoadPrevGameProc},
604 // {N_("Reload Same Game"), "Reload Same Game", ReloadGameProc},
605 {N_("Next Position Shift+PgDn"), "Load Next Position", LoadNextPositionProc},
606 {N_("Prev Position Shift+PgUp"), "Load Previous Position", LoadPrevPositionProc},
607 {"----", NULL, NothingProc},
608 // {N_("Reload Same Position"), "Reload Same Position", ReloadPositionProc},
609 {N_("Save Game Ctrl+S"), "Save Game", SaveGameProc},
610 {N_("Save Position Ctrl+Shift+S"), "Save Position", SavePositionProc},
611 {"----", NULL, NothingProc},
612 {N_("Mail Move"), "Mail Move", MailMoveProc},
613 {N_("Reload CMail Message"), "Reload CMail Message", ReloadCmailMsgProc},
614 {"----", NULL, NothingProc},
615 {N_("Quit Ctr+Q"), "Exit", QuitProc},
619 MenuItem editMenu[] = {
620 {N_("Copy Game Ctrl+C"), "Copy Game", CopyGameProc},
621 {N_("Copy Position Ctrl+Shift+C"), "Copy Position", CopyPositionProc},
622 {"----", NULL, NothingProc},
623 {N_("Paste Game Ctrl+V"), "Paste Game", PasteGameProc},
624 {N_("Paste Position Ctrl+Shift+V"), "Paste Position", PastePositionProc},
625 {"----", NULL, NothingProc},
626 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
627 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
628 {N_("Edit Tags"), "Edit Tags", EditTagsProc},
629 {N_("Edit Comment"), "Edit Comment", EditCommentProc},
630 {"----", NULL, NothingProc},
631 {N_("Revert Home"), "Revert", RevertProc},
632 {N_("Annotate"), "Annotate", AnnotateProc},
633 {N_("Truncate Game End"), "Truncate Game", TruncateGameProc},
634 {"----", NULL, NothingProc},
635 {N_("Backward Alt+Left"), "Backward", BackwardProc},
636 {N_("Forward Alt+Right"), "Forward", ForwardProc},
637 {N_("Back to Start Alt+Home"), "Back to Start", ToStartProc},
638 {N_("Forward to End Alt+End"), "Forward to End", ToEndProc},
642 MenuItem viewMenu[] = {
643 {N_("Flip View F2"), "Flip View", FlipViewProc},
644 {"----", NULL, NothingProc},
645 {N_("Engine Output Alt+Shift+O"), "Show Engine Output", EngineOutputProc},
646 {N_("Move History Alt+Shift+H"), "Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
647 {N_("Evaluation Graph Alt+Shift+E"), "Show Evaluation Graph", EvalGraphProc},
648 {N_("Game List Alt+Shift+G"), "Show Game List", ShowGameListProc},
649 {"----", NULL, NothingProc},
650 {N_("Tags"), "Show Tags", EditTagsProc},
651 {N_("Comments"), "Show Comments", EditCommentProc},
652 {N_("ICS Input Box"), "ICS Input Box", IcsInputBoxProc},
653 {"----", NULL, NothingProc},
654 {N_("Board..."), "Board Options", BoardOptionsProc},
655 {N_("Game List Tags..."), "Game List", GameListOptionsPopUp},
659 MenuItem modeMenu[] = {
660 {N_("Machine White Ctrl+W"), "Machine White", MachineWhiteProc},
661 {N_("Machine Black Ctrl+B"), "Machine Black", MachineBlackProc},
662 {N_("Two Machines Ctrl+T"), "Two Machines", TwoMachinesProc},
663 {N_("Analysis Mode Ctrl+A"), "Analysis Mode", AnalyzeModeProc},
664 {N_("Analyze File Ctrl+F"), "Analyze File", AnalyzeFileProc },
665 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
666 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
667 {N_("Training"), "Training", TrainingProc},
668 {N_("ICS Client"), "ICS Client", IcsClientProc},
669 {"----", NULL, NothingProc},
670 {N_("Pause Pause"), "Pause", PauseProc},
674 MenuItem actionMenu[] = {
675 {N_("Accept F3"), "Accept", AcceptProc},
676 {N_("Decline F4"), "Decline", DeclineProc},
677 {N_("Rematch F12"), "Rematch", RematchProc},
678 {"----", NULL, NothingProc},
679 {N_("Call Flag F5"), "Call Flag", CallFlagProc},
680 {N_("Draw F6"), "Draw", DrawProc},
681 {N_("Adjourn F7"), "Adjourn", AdjournProc},
682 {N_("Abort F8"),"Abort", AbortProc},
683 {N_("Resign F9"), "Resign", ResignProc},
684 {"----", NULL, NothingProc},
685 {N_("Stop Observing F10"), "Stop Observing", StopObservingProc},
686 {N_("Stop Examining F11"), "Stop Examining", StopExaminingProc},
687 {N_("Upload to Examine"), "Upload to Examine", UploadProc},
688 {"----", NULL, NothingProc},
689 {N_("Adjudicate to White"), "Adjudicate to White", AdjuWhiteProc},
690 {N_("Adjudicate to Black"), "Adjudicate to Black", AdjuBlackProc},
691 {N_("Adjudicate Draw"), "Adjudicate Draw", AdjuDrawProc},
695 MenuItem engineMenu[] = {
696 {N_("Engine #1 Settings ..."), "Engine #1 Settings", FirstSettingsProc},
697 {N_("Engine #2 Settings ..."), "Engine #2 Settings", SecondSettingsProc},
698 {"----", NULL, NothingProc},
699 {N_("Hint"), "Hint", HintProc},
700 {N_("Book"), "Book", BookProc},
701 {"----", NULL, NothingProc},
702 {N_("Move Now Ctrl+M"), "Move Now", MoveNowProc},
703 {N_("Retract Move Ctrl+X"), "Retract Move", RetractMoveProc},
707 MenuItem optionsMenu[] = {
708 {N_("Time Control ... Alt+Shift+T"), "Time Control", TimeControlProc},
709 {N_("Common Engine ... Alt+Shift+U"), "Common Engine", UciMenuProc},
710 {N_("Adjudications ... Alt+Shift+J"), "Adjudications", EngineMenuProc},
711 {N_("ICS ..."), "ICS", IcsOptionsProc},
712 {N_("Load Game ..."), "Load Game", LoadOptionsProc},
713 {N_("Save Game ..."), "Save Game", SaveOptionsProc},
714 // {N_(" ..."), "", OptionsProc},
715 {N_("Game List ..."), "Game List", GameListOptionsPopUp},
716 {N_("Sounds ..."), "Sounds", SoundOptionsProc},
717 {"----", NULL, NothingProc},
718 {N_("Always Queen Ctrl+Shift+Q"), "Always Queen", AlwaysQueenProc},
719 {N_("Animate Dragging"), "Animate Dragging", AnimateDraggingProc},
720 {N_("Animate Moving Ctrl+Shift+A"), "Animate Moving", AnimateMovingProc},
721 {N_("Auto Flag Ctrl+Shift+F"), "Auto Flag", AutoflagProc},
722 {N_("Auto Flip View"), "Auto Flip View", AutoflipProc},
723 {N_("Blindfold"), "Blindfold", BlindfoldProc},
724 {N_("Flash Moves"), "Flash Moves", FlashMovesProc},
726 {N_("Highlight Dragging"), "Highlight Dragging", HighlightDraggingProc},
728 {N_("Highlight Last Move"), "Highlight Last Move", HighlightLastMoveProc},
729 {N_("Highlight With Arrow"), "Arrow", HighlightArrowProc},
730 {N_("Move Sound"), "Move Sound", MoveSoundProc},
731 // {N_("ICS Alarm"), "ICS Alarm", IcsAlarmProc},
732 {N_("One-Click Moving"), "OneClick", OneClickProc},
733 {N_("Periodic Updates"), "Periodic Updates", PeriodicUpdatesProc},
734 {N_("Ponder Next Move Ctrl+Shift+P"), "Ponder Next Move", PonderNextMoveProc},
735 {N_("Popup Exit Message"), "Popup Exit Message", PopupExitMessageProc},
736 {N_("Popup Move Errors"), "Popup Move Errors", PopupMoveErrorsProc},
737 // {N_("Premove"), "Premove", PremoveProc},
738 {N_("Show Coords"), "Show Coords", ShowCoordsProc},
739 {N_("Hide Thinking Ctrl+Shift+H"), "Hide Thinking", HideThinkingProc},
740 {N_("Test Legality Ctrl+Shift+L"), "Test Legality", TestLegalityProc},
741 {"----", NULL, NothingProc},
742 {N_("Save Settings Now"), "Save Settings Now", SaveSettingsProc},
743 {N_("Save Settings on Exit"), "Save Settings on Exit", SaveOnExitProc},
747 MenuItem helpMenu[] = {
748 {N_("Info XBoard"), "Info XBoard", InfoProc},
749 {N_("Man XBoard F1"), "Man XBoard", ManProc},
750 {"----", NULL, NothingProc},
751 {N_("About XBoard"), "About XBoard", AboutProc},
756 {N_("File"), "File", fileMenu},
757 {N_("Edit"), "Edit", editMenu},
758 {N_("View"), "View", viewMenu},
759 {N_("Mode"), "Mode", modeMenu},
760 {N_("Action"), "Action", actionMenu},
761 {N_("Engine"), "Engine", engineMenu},
762 {N_("Options"), "Options", optionsMenu},
763 {N_("Help"), "Help", helpMenu},
767 #define PAUSE_BUTTON "P"
768 MenuItem buttonBar[] = {
769 {"<<", "<<", ToStartProc},
770 {"<", "<", BackwardProc},
771 {PAUSE_BUTTON, PAUSE_BUTTON, PauseProc},
772 {">", ">", ForwardProc},
773 {">>", ">>", ToEndProc},
777 #define PIECE_MENU_SIZE 18
778 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
779 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
780 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
781 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
782 N_("Empty square"), N_("Clear board") },
783 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
784 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
785 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
786 N_("Empty square"), N_("Clear board") }
788 /* must be in same order as PieceMenuStrings! */
789 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
790 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
791 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
792 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
793 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
794 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
795 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
796 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
797 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
800 #define DROP_MENU_SIZE 6
801 String dropMenuStrings[DROP_MENU_SIZE] = {
802 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
804 /* must be in same order as PieceMenuStrings! */
805 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
806 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
807 WhiteRook, WhiteQueen
815 DropMenuEnables dmEnables[] = {
833 { XtNborderWidth, 0 },
834 { XtNdefaultDistance, 0 },
838 { XtNborderWidth, 0 },
839 { XtNresizable, (XtArgVal) True },
843 { XtNborderWidth, 0 },
849 { XtNjustify, (XtArgVal) XtJustifyRight },
850 { XtNlabel, (XtArgVal) "..." },
851 { XtNresizable, (XtArgVal) True },
852 { XtNresize, (XtArgVal) False }
855 Arg messageArgs[] = {
856 { XtNjustify, (XtArgVal) XtJustifyLeft },
857 { XtNlabel, (XtArgVal) "..." },
858 { XtNresizable, (XtArgVal) True },
859 { XtNresize, (XtArgVal) False }
863 { XtNborderWidth, 0 },
864 { XtNjustify, (XtArgVal) XtJustifyLeft }
867 XtResource clientResources[] = {
868 { "flashCount", "flashCount", XtRInt, sizeof(int),
869 XtOffset(AppDataPtr, flashCount), XtRImmediate,
870 (XtPointer) FLASH_COUNT },
873 XrmOptionDescRec shellOptions[] = {
874 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
875 { "-flash", "flashCount", XrmoptionNoArg, "3" },
876 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
879 XtActionsRec boardActions[] = {
880 { "DrawPosition", DrawPositionProc },
881 { "HandleUserMove", HandleUserMove },
882 { "AnimateUserMove", AnimateUserMove },
883 { "HandlePV", HandlePV },
884 { "SelectPV", SelectPV },
885 { "StopPV", StopPV },
886 { "FileNameAction", FileNameAction },
887 { "AskQuestionProc", AskQuestionProc },
888 { "AskQuestionReplyAction", AskQuestionReplyAction },
889 { "PieceMenuPopup", PieceMenuPopup },
890 { "WhiteClock", WhiteClock },
891 { "BlackClock", BlackClock },
892 { "Iconify", Iconify },
893 { "ResetProc", ResetProc },
894 { "NewVariantProc", NewVariantProc },
895 { "LoadGameProc", LoadGameProc },
896 { "LoadNextGameProc", LoadNextGameProc },
897 { "LoadPrevGameProc", LoadPrevGameProc },
898 { "LoadSelectedProc", LoadSelectedProc },
899 { "SetFilterProc", SetFilterProc },
900 { "ReloadGameProc", ReloadGameProc },
901 { "LoadPositionProc", LoadPositionProc },
902 { "LoadNextPositionProc", LoadNextPositionProc },
903 { "LoadPrevPositionProc", LoadPrevPositionProc },
904 { "ReloadPositionProc", ReloadPositionProc },
905 { "CopyPositionProc", CopyPositionProc },
906 { "PastePositionProc", PastePositionProc },
907 { "CopyGameProc", CopyGameProc },
908 { "PasteGameProc", PasteGameProc },
909 { "SaveGameProc", SaveGameProc },
910 { "SavePositionProc", SavePositionProc },
911 { "MailMoveProc", MailMoveProc },
912 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
913 { "QuitProc", QuitProc },
914 { "MachineWhiteProc", MachineWhiteProc },
915 { "MachineBlackProc", MachineBlackProc },
916 { "AnalysisModeProc", AnalyzeModeProc },
917 { "AnalyzeFileProc", AnalyzeFileProc },
918 { "TwoMachinesProc", TwoMachinesProc },
919 { "IcsClientProc", IcsClientProc },
920 { "EditGameProc", EditGameProc },
921 { "EditPositionProc", EditPositionProc },
922 { "TrainingProc", EditPositionProc },
923 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
924 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
925 { "ShowGameListProc", ShowGameListProc },
926 { "ShowMoveListProc", HistoryShowProc},
927 { "EditTagsProc", EditCommentProc },
928 { "EditCommentProc", EditCommentProc },
929 { "IcsInputBoxProc", IcsInputBoxProc },
930 { "PauseProc", PauseProc },
931 { "AcceptProc", AcceptProc },
932 { "DeclineProc", DeclineProc },
933 { "RematchProc", RematchProc },
934 { "CallFlagProc", CallFlagProc },
935 { "DrawProc", DrawProc },
936 { "AdjournProc", AdjournProc },
937 { "AbortProc", AbortProc },
938 { "ResignProc", ResignProc },
939 { "AdjuWhiteProc", AdjuWhiteProc },
940 { "AdjuBlackProc", AdjuBlackProc },
941 { "AdjuDrawProc", AdjuDrawProc },
942 { "EnterKeyProc", EnterKeyProc },
943 { "UpKeyProc", UpKeyProc },
944 { "DownKeyProc", DownKeyProc },
945 { "StopObservingProc", StopObservingProc },
946 { "StopExaminingProc", StopExaminingProc },
947 { "UploadProc", UploadProc },
948 { "BackwardProc", BackwardProc },
949 { "ForwardProc", ForwardProc },
950 { "ToStartProc", ToStartProc },
951 { "ToEndProc", ToEndProc },
952 { "RevertProc", RevertProc },
953 { "AnnotateProc", AnnotateProc },
954 { "TruncateGameProc", TruncateGameProc },
955 { "MoveNowProc", MoveNowProc },
956 { "RetractMoveProc", RetractMoveProc },
957 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
958 { "UciMenuProc", (XtActionProc) UciMenuProc },
959 { "TimeControlProc", (XtActionProc) TimeControlProc },
960 { "AlwaysQueenProc", AlwaysQueenProc },
961 { "AnimateDraggingProc", AnimateDraggingProc },
962 { "AnimateMovingProc", AnimateMovingProc },
963 { "AutoflagProc", AutoflagProc },
964 { "AutoflipProc", AutoflipProc },
965 { "BlindfoldProc", BlindfoldProc },
966 { "FlashMovesProc", FlashMovesProc },
967 { "FlipViewProc", FlipViewProc },
969 { "HighlightDraggingProc", HighlightDraggingProc },
971 { "HighlightLastMoveProc", HighlightLastMoveProc },
972 // { "IcsAlarmProc", IcsAlarmProc },
973 { "MoveSoundProc", MoveSoundProc },
974 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
975 { "PonderNextMoveProc", PonderNextMoveProc },
976 { "PopupExitMessageProc", PopupExitMessageProc },
977 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
978 // { "PremoveProc", PremoveProc },
979 { "ShowCoordsProc", ShowCoordsProc },
980 { "ShowThinkingProc", ShowThinkingProc },
981 { "HideThinkingProc", HideThinkingProc },
982 { "TestLegalityProc", TestLegalityProc },
983 { "SaveSettingsProc", SaveSettingsProc },
984 { "SaveOnExitProc", SaveOnExitProc },
985 { "InfoProc", InfoProc },
986 { "ManProc", ManProc },
987 { "HintProc", HintProc },
988 { "BookProc", BookProc },
989 { "AboutGameProc", AboutGameProc },
990 { "AboutProc", AboutProc },
991 { "DebugProc", DebugProc },
992 { "NothingProc", NothingProc },
993 { "CommentClick", (XtActionProc) CommentClick },
994 { "CommentPopDown", (XtActionProc) CommentPopDown },
995 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
996 { "TagsPopDown", (XtActionProc) TagsPopDown },
997 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
998 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
999 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
1000 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
1001 { "GameListPopDown", (XtActionProc) GameListPopDown },
1002 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
1003 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1004 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
1005 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1006 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1007 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
1008 { "EnginePopDown", (XtActionProc) EnginePopDown },
1009 { "UciPopDown", (XtActionProc) UciPopDown },
1010 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
1011 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
1012 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
1013 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1016 char globalTranslations[] =
1017 ":<Key>F9: ResignProc() \n \
1018 :Ctrl<Key>n: ResetProc() \n \
1019 :Meta<Key>V: NewVariantProc() \n \
1020 :Ctrl<Key>o: LoadGameProc() \n \
1021 :Meta<Key>Next: LoadNextGameProc() \n \
1022 :Meta<Key>Prior: LoadPrevGameProc() \n \
1023 :Ctrl<Key>s: SaveGameProc() \n \
1024 :Ctrl<Key>c: CopyGameProc() \n \
1025 :Ctrl<Key>v: PasteGameProc() \n \
1026 :Ctrl<Key>O: LoadPositionProc() \n \
1027 :Shift<Key>Next: LoadNextPositionProc() \n \
1028 :Shift<Key>Prior: LoadPrevPositionProc() \n \
1029 :Ctrl<Key>S: SavePositionProc() \n \
1030 :Ctrl<Key>C: CopyPositionProc() \n \
1031 :Ctrl<Key>V: PastePositionProc() \n \
1032 :Ctrl<Key>q: QuitProc() \n \
1033 :Ctrl<Key>w: MachineWhiteProc() \n \
1034 :Ctrl<Key>b: MachineBlackProc() \n \
1035 :Ctrl<Key>t: TwoMachinesProc() \n \
1036 :Ctrl<Key>a: AnalysisModeProc() \n \
1037 :Ctrl<Key>f: AnalyzeFileProc() \n \
1038 :Ctrl<Key>e: EditGameProc() \n \
1039 :Ctrl<Key>E: EditPositionProc() \n \
1040 :Meta<Key>O: EngineOutputProc() \n \
1041 :Meta<Key>E: EvalGraphProc() \n \
1042 :Meta<Key>G: ShowGameListProc() \n \
1043 :Meta<Key>H: ShowMoveListProc() \n \
1044 :<Key>Pause: PauseProc() \n \
1045 :<Key>F3: AcceptProc() \n \
1046 :<Key>F4: DeclineProc() \n \
1047 :<Key>F12: RematchProc() \n \
1048 :<Key>F5: CallFlagProc() \n \
1049 :<Key>F6: DrawProc() \n \
1050 :<Key>F7: AdjournProc() \n \
1051 :<Key>F8: AbortProc() \n \
1052 :<Key>F10: StopObservingProc() \n \
1053 :<Key>F11: StopExaminingProc() \n \
1054 :Meta Ctrl<Key>F12: DebugProc() \n \
1055 :Meta<Key>End: ToEndProc() \n \
1056 :Meta<Key>Right: ForwardProc() \n \
1057 :Meta<Key>Home: ToStartProc() \n \
1058 :Meta<Key>Left: BackwardProc() \n \
1059 :<Key>Home: RevertProc() \n \
1060 :<Key>End: TruncateGameProc() \n \
1061 :Ctrl<Key>m: MoveNowProc() \n \
1062 :Ctrl<Key>x: RetractMoveProc() \n \
1063 :Meta<Key>J: EngineMenuProc() \n \
1064 :Meta<Key>U: UciMenuProc() \n \
1065 :Meta<Key>T: TimeControlProc() \n \
1066 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1067 :Ctrl<Key>F: AutoflagProc() \n \
1068 :Ctrl<Key>A: AnimateMovingProc() \n \
1069 :Ctrl<Key>P: PonderNextMoveProc() \n \
1070 :Ctrl<Key>L: TestLegalityProc() \n \
1071 :Ctrl<Key>H: HideThinkingProc() \n \
1072 :<Key>-: Iconify() \n \
1073 :<Key>F1: ManProc() \n \
1074 :<Key>F2: FlipViewProc() \n \
1075 <KeyDown>.: BackwardProc() \n \
1076 <KeyUp>.: ForwardProc() \n \
1077 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1078 \"Send to chess program:\",,1) \n \
1079 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1080 \"Send to second chess program:\",,2) \n";
1082 char boardTranslations[] =
1083 "<Btn1Down>: HandleUserMove(0) \n \
1084 Shift<Btn1Up>: HandleUserMove(1) \n \
1085 <Btn1Up>: HandleUserMove(0) \n \
1086 <Btn1Motion>: AnimateUserMove() \n \
1087 <Btn3Motion>: HandlePV() \n \
1088 <Btn3Up>: PieceMenuPopup(menuB) \n \
1089 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1090 PieceMenuPopup(menuB) \n \
1091 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1092 PieceMenuPopup(menuW) \n \
1093 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1094 PieceMenuPopup(menuW) \n \
1095 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1096 PieceMenuPopup(menuB) \n";
1098 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1099 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1101 char ICSInputTranslations[] =
1102 "<Key>Up: UpKeyProc() \n "
1103 "<Key>Down: DownKeyProc() \n "
1104 "<Key>Return: EnterKeyProc() \n";
1106 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1107 // as the widget is destroyed before the up-click can call extend-end
1108 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1110 String xboardResources[] = {
1111 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1112 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1113 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1118 /* Max possible square size */
1119 #define MAXSQSIZE 256
1121 static int xpm_avail[MAXSQSIZE];
1123 #ifdef HAVE_DIR_STRUCT
1125 /* Extract piece size from filename */
1127 xpm_getsize(name, len, ext)
1138 if ((p=strchr(name, '.')) == NULL ||
1139 StrCaseCmp(p+1, ext) != 0)
1145 while (*p && isdigit(*p))
1152 /* Setup xpm_avail */
1154 xpm_getavail(dirname, ext)
1162 for (i=0; i<MAXSQSIZE; ++i)
1165 if (appData.debugMode)
1166 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1168 dir = opendir(dirname);
1171 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1172 programName, dirname);
1176 while ((ent=readdir(dir)) != NULL) {
1177 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1178 if (i > 0 && i < MAXSQSIZE)
1188 xpm_print_avail(fp, ext)
1194 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1195 for (i=1; i<MAXSQSIZE; ++i) {
1201 /* Return XPM piecesize closest to size */
1203 xpm_closest_to(dirname, size, ext)
1209 int sm_diff = MAXSQSIZE;
1213 xpm_getavail(dirname, ext);
1215 if (appData.debugMode)
1216 xpm_print_avail(stderr, ext);
1218 for (i=1; i<MAXSQSIZE; ++i) {
1221 diff = (diff<0) ? -diff : diff;
1222 if (diff < sm_diff) {
1230 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1236 #else /* !HAVE_DIR_STRUCT */
1237 /* If we are on a system without a DIR struct, we can't
1238 read the directory, so we can't collect a list of
1239 filenames, etc., so we can't do any size-fitting. */
1241 xpm_closest_to(dirname, size, ext)
1246 fprintf(stderr, _("\
1247 Warning: No DIR structure found on this system --\n\
1248 Unable to autosize for XPM/XIM pieces.\n\
1249 Please report this error to frankm@hiwaay.net.\n\
1250 Include system type & operating system in message.\n"));
1253 #endif /* HAVE_DIR_STRUCT */
1255 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1256 "magenta", "cyan", "white" };
1260 TextColors textColors[(int)NColorClasses];
1262 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1264 parse_color(str, which)
1268 char *p, buf[100], *d;
1271 if (strlen(str) > 99) /* watch bounds on buf */
1276 for (i=0; i<which; ++i) {
1283 /* Could be looking at something like:
1285 .. in which case we want to stop on a comma also */
1286 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1290 return -1; /* Use default for empty field */
1293 if (which == 2 || isdigit(*p))
1296 while (*p && isalpha(*p))
1301 for (i=0; i<8; ++i) {
1302 if (!StrCaseCmp(buf, cnames[i]))
1303 return which? (i+40) : (i+30);
1305 if (!StrCaseCmp(buf, "default")) return -1;
1307 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1312 parse_cpair(cc, str)
1316 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1317 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1322 /* bg and attr are optional */
1323 textColors[(int)cc].bg = parse_color(str, 1);
1324 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1325 textColors[(int)cc].attr = 0;
1331 /* Arrange to catch delete-window events */
1332 Atom wm_delete_window;
1334 CatchDeleteWindow(Widget w, String procname)
1337 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1338 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1339 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1346 XtSetArg(args[0], XtNiconic, False);
1347 XtSetValues(shellWidget, args, 1);
1349 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1352 //---------------------------------------------------------------------------------------------------------
1353 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1356 #define CW_USEDEFAULT (1<<31)
1357 #define ICS_TEXT_MENU_SIZE 90
1358 #define DEBUG_FILE "xboard.debug"
1359 #define SetCurrentDirectory chdir
1360 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1364 // these two must some day move to frontend.h, when they are implemented
1365 Boolean GameListIsUp();
1367 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1370 // front-end part of option handling
1372 // [HGM] This platform-dependent table provides the location for storing the color info
1373 extern char *crWhite, * crBlack;
1377 &appData.whitePieceColor,
1378 &appData.blackPieceColor,
1379 &appData.lightSquareColor,
1380 &appData.darkSquareColor,
1381 &appData.highlightSquareColor,
1382 &appData.premoveHighlightColor,
1383 &appData.lowTimeWarningColor,
1394 // [HGM] font: keep a font for each square size, even non-stndard ones
1395 #define NUM_SIZES 18
1396 #define MAX_SIZE 130
1397 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1398 char *fontTable[NUM_FONTS][MAX_SIZE];
1401 ParseFont(char *name, int number)
1402 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1404 if(sscanf(name, "size%d:", &size)) {
1405 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1406 // defer processing it until we know if it matches our board size
1407 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1408 fontTable[number][size] = strdup(strchr(name, ':')+1);
1409 fontValid[number][size] = True;
1414 case 0: // CLOCK_FONT
1415 appData.clockFont = strdup(name);
1417 case 1: // MESSAGE_FONT
1418 appData.font = strdup(name);
1420 case 2: // COORD_FONT
1421 appData.coordFont = strdup(name);
1426 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1431 { // only 2 fonts currently
1432 appData.clockFont = CLOCK_FONT_NAME;
1433 appData.coordFont = COORD_FONT_NAME;
1434 appData.font = DEFAULT_FONT_NAME;
1439 { // no-op, until we identify the code for this already in XBoard and move it here
1443 ParseColor(int n, char *name)
1444 { // in XBoard, just copy the color-name string
1445 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1449 ParseTextAttribs(ColorClass cc, char *s)
1451 (&appData.colorShout)[cc] = strdup(s);
1455 ParseBoardSize(void *addr, char *name)
1457 appData.boardSize = strdup(name);
1462 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1466 SetCommPortDefaults()
1467 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1470 // [HGM] args: these three cases taken out to stay in front-end
1472 SaveFontArg(FILE *f, ArgDescriptor *ad)
1475 int i, n = (int)(intptr_t)ad->argLoc;
1477 case 0: // CLOCK_FONT
1478 name = appData.clockFont;
1480 case 1: // MESSAGE_FONT
1481 name = appData.font;
1483 case 2: // COORD_FONT
1484 name = appData.coordFont;
1489 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1490 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1491 fontTable[n][squareSize] = strdup(name);
1492 fontValid[n][squareSize] = True;
1495 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1496 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1501 { // nothing to do, as the sounds are at all times represented by their text-string names already
1505 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1506 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1507 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
1511 SaveColor(FILE *f, ArgDescriptor *ad)
1512 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1513 if(colorVariable[(int)(intptr_t)ad->argLoc])
1514 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
1518 SaveBoardSize(FILE *f, char *name, void *addr)
1519 { // wrapper to shield back-end from BoardSize & sizeInfo
1520 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1524 ParseCommPortSettings(char *s)
1525 { // no such option in XBoard (yet)
1528 extern Widget engineOutputShell;
1529 extern Widget tagsShell, editTagsShell;
1531 GetActualPlacement(Widget wg, WindowPlacement *wp)
1541 XtSetArg(args[i], XtNx, &x); i++;
1542 XtSetArg(args[i], XtNy, &y); i++;
1543 XtSetArg(args[i], XtNwidth, &w); i++;
1544 XtSetArg(args[i], XtNheight, &h); i++;
1545 XtGetValues(wg, args, i);
1554 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1555 // In XBoard this will have to wait until awareness of window parameters is implemented
1556 GetActualPlacement(shellWidget, &wpMain);
1557 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1558 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1559 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1560 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1561 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1562 else GetActualPlacement(editShell, &wpComment);
1563 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1564 else GetActualPlacement(editTagsShell, &wpTags);
1568 PrintCommPortSettings(FILE *f, char *name)
1569 { // This option does not exist in XBoard
1573 MySearchPath(char *installDir, char *name, char *fullname)
1574 { // just append installDir and name. Perhaps ExpandPath should be used here?
1575 name = ExpandPathName(name);
1576 if(name && name[0] == '/')
1577 safeStrCpy(fullname, name, MSG_SIZ );
1579 sprintf(fullname, "%s%c%s", installDir, '/', name);
1585 MyGetFullPathName(char *name, char *fullname)
1586 { // should use ExpandPath?
1587 name = ExpandPathName(name);
1588 safeStrCpy(fullname, name, MSG_SIZ );
1593 EnsureOnScreen(int *x, int *y, int minX, int minY)
1600 { // [HGM] args: allows testing if main window is realized from back-end
1601 return xBoardWindow != 0;
1605 PopUpStartupDialog()
1606 { // start menu not implemented in XBoard
1610 ConvertToLine(int argc, char **argv)
1612 static char line[128*1024], buf[1024];
1616 for(i=1; i<argc; i++)
1618 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1619 && argv[i][0] != '{' )
1620 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1622 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1623 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1626 line[strlen(line)-1] = NULLCHAR;
1630 //--------------------------------------------------------------------------------------------
1632 extern Boolean twoBoards, partnerUp;
1635 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1637 #define BoardSize int
1638 void InitDrawingSizes(BoardSize boardSize, int flags)
1639 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1640 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1642 XtGeometryResult gres;
1645 if(!formWidget) return;
1648 * Enable shell resizing.
1650 shellArgs[0].value = (XtArgVal) &w;
1651 shellArgs[1].value = (XtArgVal) &h;
1652 XtGetValues(shellWidget, shellArgs, 2);
1654 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1655 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1656 XtSetValues(shellWidget, &shellArgs[2], 4);
1658 XtSetArg(args[0], XtNdefaultDistance, &sep);
1659 XtGetValues(formWidget, args, 1);
1661 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1662 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1663 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1665 hOffset = boardWidth + 10;
1666 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1667 secondSegments[i] = gridSegments[i];
1668 secondSegments[i].x1 += hOffset;
1669 secondSegments[i].x2 += hOffset;
1672 XtSetArg(args[0], XtNwidth, boardWidth);
1673 XtSetArg(args[1], XtNheight, boardHeight);
1674 XtSetValues(boardWidget, args, 2);
1676 timerWidth = (boardWidth - sep) / 2;
1677 XtSetArg(args[0], XtNwidth, timerWidth);
1678 XtSetValues(whiteTimerWidget, args, 1);
1679 XtSetValues(blackTimerWidget, args, 1);
1681 XawFormDoLayout(formWidget, False);
1683 if (appData.titleInWindow) {
1685 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1686 XtSetArg(args[i], XtNheight, &h); i++;
1687 XtGetValues(titleWidget, args, i);
1689 w = boardWidth - 2*bor;
1691 XtSetArg(args[0], XtNwidth, &w);
1692 XtGetValues(menuBarWidget, args, 1);
1693 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1696 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1697 if (gres != XtGeometryYes && appData.debugMode) {
1699 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1700 programName, gres, w, h, wr, hr);
1704 XawFormDoLayout(formWidget, True);
1707 * Inhibit shell resizing.
1709 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1710 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1711 shellArgs[4].value = shellArgs[2].value = w;
1712 shellArgs[5].value = shellArgs[3].value = h;
1713 XtSetValues(shellWidget, &shellArgs[0], 6);
1715 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1718 for(i=0; i<4; i++) {
1720 for(p=0; p<=(int)WhiteKing; p++)
1721 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1722 if(gameInfo.variant == VariantShogi) {
1723 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1724 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1725 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1726 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1727 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1730 if(gameInfo.variant == VariantGothic) {
1731 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1734 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1735 xpmPieceBitmap[i][(int)WhiteAngel] = xpmPieceBitmap2[i][(int)WhiteFalcon];
1736 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1739 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1740 for(p=0; p<=(int)WhiteKing; p++)
1741 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1742 if(gameInfo.variant == VariantShogi) {
1743 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1744 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1745 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1746 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1747 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1750 if(gameInfo.variant == VariantGothic) {
1751 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1754 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1755 ximMaskPm[(int)WhiteAngel] = ximMaskPm2[(int)WhiteFalcon];
1756 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1761 for(i=0; i<2; i++) {
1763 for(p=0; p<=(int)WhiteKing; p++)
1764 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1765 if(gameInfo.variant == VariantShogi) {
1766 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1767 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1768 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1769 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1770 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1773 if(gameInfo.variant == VariantGothic) {
1774 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1777 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1778 pieceBitmap[i][(int)WhiteAngel] = pieceBitmap2[i][(int)WhiteFalcon];
1779 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1789 void ParseIcsTextColors()
1790 { // [HGM] tken out of main(), so it can be called from ICS-Options dialog
1791 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1792 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1793 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1794 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1795 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1796 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1797 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1798 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1799 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1800 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1802 if (appData.colorize) {
1804 _("%s: can't parse color names; disabling colorization\n"),
1807 appData.colorize = FALSE;
1812 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
1813 XrmValue vFrom, vTo;
1814 int forceMono = False;
1816 if (!appData.monoMode) {
1817 vFrom.addr = (caddr_t) appData.lightSquareColor;
1818 vFrom.size = strlen(appData.lightSquareColor);
1819 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1820 if (vTo.addr == NULL) {
1821 appData.monoMode = True;
1824 lightSquareColor = *(Pixel *) vTo.addr;
1827 if (!appData.monoMode) {
1828 vFrom.addr = (caddr_t) appData.darkSquareColor;
1829 vFrom.size = strlen(appData.darkSquareColor);
1830 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1831 if (vTo.addr == NULL) {
1832 appData.monoMode = True;
1835 darkSquareColor = *(Pixel *) vTo.addr;
1838 if (!appData.monoMode) {
1839 vFrom.addr = (caddr_t) appData.whitePieceColor;
1840 vFrom.size = strlen(appData.whitePieceColor);
1841 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1842 if (vTo.addr == NULL) {
1843 appData.monoMode = True;
1846 whitePieceColor = *(Pixel *) vTo.addr;
1849 if (!appData.monoMode) {
1850 vFrom.addr = (caddr_t) appData.blackPieceColor;
1851 vFrom.size = strlen(appData.blackPieceColor);
1852 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1853 if (vTo.addr == NULL) {
1854 appData.monoMode = True;
1857 blackPieceColor = *(Pixel *) vTo.addr;
1861 if (!appData.monoMode) {
1862 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1863 vFrom.size = strlen(appData.highlightSquareColor);
1864 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1865 if (vTo.addr == NULL) {
1866 appData.monoMode = True;
1869 highlightSquareColor = *(Pixel *) vTo.addr;
1873 if (!appData.monoMode) {
1874 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1875 vFrom.size = strlen(appData.premoveHighlightColor);
1876 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1877 if (vTo.addr == NULL) {
1878 appData.monoMode = True;
1881 premoveHighlightColor = *(Pixel *) vTo.addr;
1892 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1893 XSetWindowAttributes window_attributes;
1895 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1896 XrmValue vFrom, vTo;
1897 XtGeometryResult gres;
1900 int forceMono = False;
1902 srandom(time(0)); // [HGM] book: make random truly random
1904 setbuf(stdout, NULL);
1905 setbuf(stderr, NULL);
1908 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1909 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1913 programName = strrchr(argv[0], '/');
1914 if (programName == NULL)
1915 programName = argv[0];
1920 XtSetLanguageProc(NULL, NULL, NULL);
1921 bindtextdomain(PACKAGE, LOCALEDIR);
1922 textdomain(PACKAGE);
1926 XtAppInitialize(&appContext, "XBoard", shellOptions,
1927 XtNumber(shellOptions),
1928 &argc, argv, xboardResources, NULL, 0);
1929 appData.boardSize = "";
1930 InitAppData(ConvertToLine(argc, argv));
1932 if (p == NULL) p = "/tmp";
1933 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1934 gameCopyFilename = (char*) malloc(i);
1935 gamePasteFilename = (char*) malloc(i);
1936 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1937 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1939 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1940 clientResources, XtNumber(clientResources),
1943 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1944 static char buf[MSG_SIZ];
1945 EscapeExpand(buf, appData.initString);
1946 appData.initString = strdup(buf);
1947 EscapeExpand(buf, appData.secondInitString);
1948 appData.secondInitString = strdup(buf);
1949 EscapeExpand(buf, appData.firstComputerString);
1950 appData.firstComputerString = strdup(buf);
1951 EscapeExpand(buf, appData.secondComputerString);
1952 appData.secondComputerString = strdup(buf);
1955 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1958 if (chdir(chessDir) != 0) {
1959 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1965 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1966 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1967 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1968 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1971 setbuf(debugFP, NULL);
1974 /* [HGM,HR] make sure board size is acceptable */
1975 if(appData.NrFiles > BOARD_FILES ||
1976 appData.NrRanks > BOARD_RANKS )
1977 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1980 /* This feature does not work; animation needs a rewrite */
1981 appData.highlightDragging = FALSE;
1985 xDisplay = XtDisplay(shellWidget);
1986 xScreen = DefaultScreen(xDisplay);
1987 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1989 gameInfo.variant = StringToVariant(appData.variant);
1990 InitPosition(FALSE);
1993 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1995 if (isdigit(appData.boardSize[0])) {
1996 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1997 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1998 &fontPxlSize, &smallLayout, &tinyLayout);
2000 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
2001 programName, appData.boardSize);
2005 /* Find some defaults; use the nearest known size */
2006 SizeDefaults *szd, *nearest;
2007 int distance = 99999;
2008 nearest = szd = sizeDefaults;
2009 while (szd->name != NULL) {
2010 if (abs(szd->squareSize - squareSize) < distance) {
2012 distance = abs(szd->squareSize - squareSize);
2013 if (distance == 0) break;
2017 if (i < 2) lineGap = nearest->lineGap;
2018 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
2019 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
2020 if (i < 5) fontPxlSize = nearest->fontPxlSize;
2021 if (i < 6) smallLayout = nearest->smallLayout;
2022 if (i < 7) tinyLayout = nearest->tinyLayout;
2025 SizeDefaults *szd = sizeDefaults;
2026 if (*appData.boardSize == NULLCHAR) {
2027 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
2028 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
2031 if (szd->name == NULL) szd--;
2032 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
2034 while (szd->name != NULL &&
2035 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
2036 if (szd->name == NULL) {
2037 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
2038 programName, appData.boardSize);
2042 squareSize = szd->squareSize;
2043 lineGap = szd->lineGap;
2044 clockFontPxlSize = szd->clockFontPxlSize;
2045 coordFontPxlSize = szd->coordFontPxlSize;
2046 fontPxlSize = szd->fontPxlSize;
2047 smallLayout = szd->smallLayout;
2048 tinyLayout = szd->tinyLayout;
2049 // [HGM] font: use defaults from settings file if available and not overruled
2051 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
2052 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
2053 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
2054 appData.font = fontTable[MESSAGE_FONT][squareSize];
2055 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
2056 appData.coordFont = fontTable[COORD_FONT][squareSize];
2058 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
2059 if (strlen(appData.pixmapDirectory) > 0) {
2060 p = ExpandPathName(appData.pixmapDirectory);
2062 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
2063 appData.pixmapDirectory);
2066 if (appData.debugMode) {
2067 fprintf(stderr, _("\
2068 XBoard square size (hint): %d\n\
2069 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
2071 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
2072 if (appData.debugMode) {
2073 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
2076 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
2078 /* [HR] height treated separately (hacked) */
2079 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
2080 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
2081 if (appData.showJail == 1) {
2082 /* Jail on top and bottom */
2083 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2084 XtSetArg(boardArgs[2], XtNheight,
2085 boardHeight + 2*(lineGap + squareSize));
2086 } else if (appData.showJail == 2) {
2088 XtSetArg(boardArgs[1], XtNwidth,
2089 boardWidth + 2*(lineGap + squareSize));
2090 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2093 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2094 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2098 * Determine what fonts to use.
2100 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2101 clockFontID = XLoadFont(xDisplay, appData.clockFont);
2102 clockFontStruct = XQueryFont(xDisplay, clockFontID);
2103 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2104 coordFontID = XLoadFont(xDisplay, appData.coordFont);
2105 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2106 appData.font = FindFont(appData.font, fontPxlSize);
2107 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
2108 countFontStruct = XQueryFont(xDisplay, countFontID);
2109 // appData.font = FindFont(appData.font, fontPxlSize);
2111 xdb = XtDatabase(xDisplay);
2112 XrmPutStringResource(&xdb, "*font", appData.font);
2115 * Detect if there are not enough colors available and adapt.
2117 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2118 appData.monoMode = True;
2121 forceMono = MakeColors();
2124 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2127 if (appData.bitmapDirectory == NULL ||
2128 appData.bitmapDirectory[0] == NULLCHAR)
2129 appData.bitmapDirectory = DEF_BITMAP_DIR;
2132 if (appData.lowTimeWarning && !appData.monoMode) {
2133 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2134 vFrom.size = strlen(appData.lowTimeWarningColor);
2135 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2136 if (vTo.addr == NULL)
2137 appData.monoMode = True;
2139 lowTimeWarningColor = *(Pixel *) vTo.addr;
2142 if (appData.monoMode && appData.debugMode) {
2143 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2144 (unsigned long) XWhitePixel(xDisplay, xScreen),
2145 (unsigned long) XBlackPixel(xDisplay, xScreen));
2148 ParseIcsTextColors();
2149 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2150 textColors[ColorNone].attr = 0;
2152 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2158 layoutName = "tinyLayout";
2159 } else if (smallLayout) {
2160 layoutName = "smallLayout";
2162 layoutName = "normalLayout";
2164 /* Outer layoutWidget is there only to provide a name for use in
2165 resources that depend on the layout style */
2167 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2168 layoutArgs, XtNumber(layoutArgs));
2170 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2171 formArgs, XtNumber(formArgs));
2172 XtSetArg(args[0], XtNdefaultDistance, &sep);
2173 XtGetValues(formWidget, args, 1);
2176 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2177 XtSetArg(args[0], XtNtop, XtChainTop);
2178 XtSetArg(args[1], XtNbottom, XtChainTop);
2179 XtSetArg(args[2], XtNright, XtChainLeft);
2180 XtSetValues(menuBarWidget, args, 3);
2182 widgetList[j++] = whiteTimerWidget =
2183 XtCreateWidget("whiteTime", labelWidgetClass,
2184 formWidget, timerArgs, XtNumber(timerArgs));
2185 XtSetArg(args[0], XtNfont, clockFontStruct);
2186 XtSetArg(args[1], XtNtop, XtChainTop);
2187 XtSetArg(args[2], XtNbottom, XtChainTop);
2188 XtSetValues(whiteTimerWidget, args, 3);
2190 widgetList[j++] = blackTimerWidget =
2191 XtCreateWidget("blackTime", labelWidgetClass,
2192 formWidget, timerArgs, XtNumber(timerArgs));
2193 XtSetArg(args[0], XtNfont, clockFontStruct);
2194 XtSetArg(args[1], XtNtop, XtChainTop);
2195 XtSetArg(args[2], XtNbottom, XtChainTop);
2196 XtSetValues(blackTimerWidget, args, 3);
2198 if (appData.titleInWindow) {
2199 widgetList[j++] = titleWidget =
2200 XtCreateWidget("title", labelWidgetClass, formWidget,
2201 titleArgs, XtNumber(titleArgs));
2202 XtSetArg(args[0], XtNtop, XtChainTop);
2203 XtSetArg(args[1], XtNbottom, XtChainTop);
2204 XtSetValues(titleWidget, args, 2);
2207 if (appData.showButtonBar) {
2208 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2209 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2210 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2211 XtSetArg(args[2], XtNtop, XtChainTop);
2212 XtSetArg(args[3], XtNbottom, XtChainTop);
2213 XtSetValues(buttonBarWidget, args, 4);
2216 widgetList[j++] = messageWidget =
2217 XtCreateWidget("message", labelWidgetClass, formWidget,
2218 messageArgs, XtNumber(messageArgs));
2219 XtSetArg(args[0], XtNtop, XtChainTop);
2220 XtSetArg(args[1], XtNbottom, XtChainTop);
2221 XtSetValues(messageWidget, args, 2);
2223 widgetList[j++] = boardWidget =
2224 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2225 XtNumber(boardArgs));
2227 XtManageChildren(widgetList, j);
2229 timerWidth = (boardWidth - sep) / 2;
2230 XtSetArg(args[0], XtNwidth, timerWidth);
2231 XtSetValues(whiteTimerWidget, args, 1);
2232 XtSetValues(blackTimerWidget, args, 1);
2234 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2235 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2236 XtGetValues(whiteTimerWidget, args, 2);
2238 if (appData.showButtonBar) {
2239 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2240 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2241 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2245 * formWidget uses these constraints but they are stored
2249 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2250 XtSetValues(menuBarWidget, args, i);
2251 if (appData.titleInWindow) {
2254 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2255 XtSetValues(whiteTimerWidget, args, i);
2257 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2258 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2259 XtSetValues(blackTimerWidget, args, i);
2261 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2262 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2263 XtSetValues(titleWidget, args, i);
2265 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2266 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2267 XtSetValues(messageWidget, args, i);
2268 if (appData.showButtonBar) {
2270 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2271 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2272 XtSetValues(buttonBarWidget, args, i);
2276 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2277 XtSetValues(whiteTimerWidget, args, i);
2279 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2280 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2281 XtSetValues(blackTimerWidget, args, i);
2283 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2284 XtSetValues(titleWidget, args, i);
2286 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2287 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2288 XtSetValues(messageWidget, args, i);
2289 if (appData.showButtonBar) {
2291 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2292 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2293 XtSetValues(buttonBarWidget, args, i);
2298 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2299 XtSetValues(whiteTimerWidget, args, i);
2301 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2302 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2303 XtSetValues(blackTimerWidget, args, i);
2305 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2306 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2307 XtSetValues(messageWidget, args, i);
2308 if (appData.showButtonBar) {
2310 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2311 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2312 XtSetValues(buttonBarWidget, args, i);
2316 XtSetArg(args[0], XtNfromVert, messageWidget);
2317 XtSetArg(args[1], XtNtop, XtChainTop);
2318 XtSetArg(args[2], XtNbottom, XtChainBottom);
2319 XtSetArg(args[3], XtNleft, XtChainLeft);
2320 XtSetArg(args[4], XtNright, XtChainRight);
2321 XtSetValues(boardWidget, args, 5);
2323 XtRealizeWidget(shellWidget);
2326 XtSetArg(args[0], XtNx, wpMain.x);
2327 XtSetArg(args[1], XtNy, wpMain.y);
2328 XtSetValues(shellWidget, args, 2);
2332 * Correct the width of the message and title widgets.
2333 * It is not known why some systems need the extra fudge term.
2334 * The value "2" is probably larger than needed.
2336 XawFormDoLayout(formWidget, False);
2338 #define WIDTH_FUDGE 2
2340 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2341 XtSetArg(args[i], XtNheight, &h); i++;
2342 XtGetValues(messageWidget, args, i);
2343 if (appData.showButtonBar) {
2345 XtSetArg(args[i], XtNwidth, &w); i++;
2346 XtGetValues(buttonBarWidget, args, i);
2347 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2349 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2352 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2353 if (gres != XtGeometryYes && appData.debugMode) {
2354 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2355 programName, gres, w, h, wr, hr);
2358 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2359 /* The size used for the child widget in layout lags one resize behind
2360 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2362 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2363 if (gres != XtGeometryYes && appData.debugMode) {
2364 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2365 programName, gres, w, h, wr, hr);
2368 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2369 XtSetArg(args[1], XtNright, XtChainRight);
2370 XtSetValues(messageWidget, args, 2);
2372 if (appData.titleInWindow) {
2374 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2375 XtSetArg(args[i], XtNheight, &h); i++;
2376 XtGetValues(titleWidget, args, i);
2378 w = boardWidth - 2*bor;
2380 XtSetArg(args[0], XtNwidth, &w);
2381 XtGetValues(menuBarWidget, args, 1);
2382 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2385 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2386 if (gres != XtGeometryYes && appData.debugMode) {
2388 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2389 programName, gres, w, h, wr, hr);
2392 XawFormDoLayout(formWidget, True);
2394 xBoardWindow = XtWindow(boardWidget);
2396 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2397 // not need to go into InitDrawingSizes().
2401 * Create X checkmark bitmap and initialize option menu checks.
2403 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2404 checkmark_bits, checkmark_width, checkmark_height);
2405 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2406 if (appData.alwaysPromoteToQueen) {
2407 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2410 if (appData.animateDragging) {
2411 XtSetValues(XtNameToWidget(menuBarWidget,
2412 "menuOptions.Animate Dragging"),
2415 if (appData.animate) {
2416 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2419 if (appData.autoCallFlag) {
2420 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2423 if (appData.autoFlipView) {
2424 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2427 if (appData.blindfold) {
2428 XtSetValues(XtNameToWidget(menuBarWidget,
2429 "menuOptions.Blindfold"), args, 1);
2431 if (appData.flashCount > 0) {
2432 XtSetValues(XtNameToWidget(menuBarWidget,
2433 "menuOptions.Flash Moves"),
2437 if (appData.highlightDragging) {
2438 XtSetValues(XtNameToWidget(menuBarWidget,
2439 "menuOptions.Highlight Dragging"),
2443 if (appData.highlightLastMove) {
2444 XtSetValues(XtNameToWidget(menuBarWidget,
2445 "menuOptions.Highlight Last Move"),
2448 if (appData.highlightMoveWithArrow) {
2449 XtSetValues(XtNameToWidget(menuBarWidget,
2450 "menuOptions.Arrow"),
2453 // if (appData.icsAlarm) {
2454 // XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2457 if (appData.ringBellAfterMoves) {
2458 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2461 if (appData.oneClick) {
2462 XtSetValues(XtNameToWidget(menuBarWidget,
2463 "menuOptions.OneClick"), args, 1);
2465 if (appData.periodicUpdates) {
2466 XtSetValues(XtNameToWidget(menuBarWidget,
2467 "menuOptions.Periodic Updates"), args, 1);
2469 if (appData.ponderNextMove) {
2470 XtSetValues(XtNameToWidget(menuBarWidget,
2471 "menuOptions.Ponder Next Move"), args, 1);
2473 if (appData.popupExitMessage) {
2474 XtSetValues(XtNameToWidget(menuBarWidget,
2475 "menuOptions.Popup Exit Message"), args, 1);
2477 if (appData.popupMoveErrors) {
2478 XtSetValues(XtNameToWidget(menuBarWidget,
2479 "menuOptions.Popup Move Errors"), args, 1);
2481 // if (appData.premove) {
2482 // XtSetValues(XtNameToWidget(menuBarWidget,
2483 // "menuOptions.Premove"), args, 1);
2485 if (appData.showCoords) {
2486 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2489 if (appData.hideThinkingFromHuman) {
2490 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2493 if (appData.testLegality) {
2494 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2497 if (saveSettingsOnExit) {
2498 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2505 ReadBitmap(&wIconPixmap, "icon_white.bm",
2506 icon_white_bits, icon_white_width, icon_white_height);
2507 ReadBitmap(&bIconPixmap, "icon_black.bm",
2508 icon_black_bits, icon_black_width, icon_black_height);
2509 iconPixmap = wIconPixmap;
2511 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2512 XtSetValues(shellWidget, args, i);
2515 * Create a cursor for the board widget.
2517 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2518 XChangeWindowAttributes(xDisplay, xBoardWindow,
2519 CWCursor, &window_attributes);
2522 * Inhibit shell resizing.
2524 shellArgs[0].value = (XtArgVal) &w;
2525 shellArgs[1].value = (XtArgVal) &h;
2526 XtGetValues(shellWidget, shellArgs, 2);
2527 shellArgs[4].value = shellArgs[2].value = w;
2528 shellArgs[5].value = shellArgs[3].value = h;
2529 XtSetValues(shellWidget, &shellArgs[2], 4);
2530 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2531 marginH = h - boardHeight;
2533 CatchDeleteWindow(shellWidget, "QuitProc");
2538 if (appData.bitmapDirectory[0] != NULLCHAR) {
2542 CreateXPMBoard(appData.liteBackTextureFile, 1);
2543 CreateXPMBoard(appData.darkBackTextureFile, 0);
2547 /* Create regular pieces */
2548 if (!useImages) CreatePieces();
2553 if (appData.animate || appData.animateDragging)
2556 XtAugmentTranslations(formWidget,
2557 XtParseTranslationTable(globalTranslations));
2558 XtAugmentTranslations(boardWidget,
2559 XtParseTranslationTable(boardTranslations));
2560 XtAugmentTranslations(whiteTimerWidget,
2561 XtParseTranslationTable(whiteTranslations));
2562 XtAugmentTranslations(blackTimerWidget,
2563 XtParseTranslationTable(blackTranslations));
2565 /* Why is the following needed on some versions of X instead
2566 * of a translation? */
2567 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2568 (XtEventHandler) EventProc, NULL);
2571 /* [AS] Restore layout */
2572 if( wpMoveHistory.visible ) {
2576 if( wpEvalGraph.visible )
2581 if( wpEngineOutput.visible ) {
2582 EngineOutputPopUp();
2587 if (errorExitStatus == -1) {
2588 if (appData.icsActive) {
2589 /* We now wait until we see "login:" from the ICS before
2590 sending the logon script (problems with timestamp otherwise) */
2591 /*ICSInitScript();*/
2592 if (appData.icsInputBox) ICSInputBoxPopUp();
2596 signal(SIGWINCH, TermSizeSigHandler);
2598 signal(SIGINT, IntSigHandler);
2599 signal(SIGTERM, IntSigHandler);
2600 if (*appData.cmailGameName != NULLCHAR) {
2601 signal(SIGUSR1, CmailSigHandler);
2604 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2606 XtSetKeyboardFocus(shellWidget, formWidget);
2608 XtAppMainLoop(appContext);
2609 if (appData.debugMode) fclose(debugFP); // [DM] debug
2616 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2617 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2619 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2620 unlink(gameCopyFilename);
2621 unlink(gamePasteFilename);
2624 RETSIGTYPE TermSizeSigHandler(int sig)
2637 CmailSigHandler(sig)
2643 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2645 /* Activate call-back function CmailSigHandlerCallBack() */
2646 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2648 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2652 CmailSigHandlerCallBack(isr, closure, message, count, error)
2660 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2662 /**** end signal code ****/
2668 /* try to open the icsLogon script, either in the location given
2669 * or in the users HOME directory
2676 f = fopen(appData.icsLogon, "r");
2679 homedir = getenv("HOME");
2680 if (homedir != NULL)
2682 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2683 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2684 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2685 f = fopen(buf, "r");
2690 ProcessICSInitScript(f);
2692 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2701 EditCommentPopDown();
2716 if (!menuBarWidget) return;
2717 w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2719 DisplayError("menuEdit.Revert", 0);
2721 XtSetSensitive(w, !grey);
2723 w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2725 DisplayError("menuEdit.Annotate", 0);
2727 XtSetSensitive(w, !grey);
2732 SetMenuEnables(enab)
2736 if (!menuBarWidget) return;
2737 while (enab->name != NULL) {
2738 w = XtNameToWidget(menuBarWidget, enab->name);
2740 DisplayError(enab->name, 0);
2742 XtSetSensitive(w, enab->value);
2748 Enables icsEnables[] = {
2749 { "menuFile.Mail Move", False },
2750 { "menuFile.Reload CMail Message", False },
2751 { "menuMode.Machine Black", False },
2752 { "menuMode.Machine White", False },
2753 { "menuMode.Analysis Mode", False },
2754 { "menuMode.Analyze File", False },
2755 { "menuMode.Two Machines", False },
2757 { "menuEngine.Hint", False },
2758 { "menuEngine.Book", False },
2759 { "menuEngine.Move Now", False },
2760 { "menuOptions.Periodic Updates", False },
2761 { "menuOptions.Hide Thinking", False },
2762 { "menuOptions.Ponder Next Move", False },
2763 { "menuEngine.Engine #1 Settings", False },
2765 { "menuEngine.Engine #2 Settings", False },
2766 { "menuEdit.Annotate", False },
2770 Enables ncpEnables[] = {
2771 { "menuFile.Mail Move", False },
2772 { "menuFile.Reload CMail Message", False },
2773 { "menuMode.Machine White", False },
2774 { "menuMode.Machine Black", False },
2775 { "menuMode.Analysis Mode", False },
2776 { "menuMode.Analyze File", False },
2777 { "menuMode.Two Machines", False },
2778 { "menuMode.ICS Client", False },
2779 { "menuView.ICS Input Box", False },
2780 { "Action", False },
2781 { "menuEdit.Revert", False },
2782 { "menuEdit.Annotate", False },
2783 { "menuEngine.Engine #1 Settings", False },
2784 { "menuEngine.Engine #2 Settings", False },
2785 { "menuEngine.Move Now", False },
2786 { "menuEngine.Retract Move", False },
2787 { "menuOptions.Auto Flag", False },
2788 { "menuOptions.Auto Flip View", False },
2789 { "menuOptions.ICS", False },
2790 // { "menuOptions.ICS Alarm", False },
2791 { "menuOptions.Move Sound", False },
2792 { "menuOptions.Hide Thinking", False },
2793 { "menuOptions.Periodic Updates", False },
2794 { "menuOptions.Ponder Next Move", False },
2795 { "menuEngine.Hint", False },
2796 { "menuEngine.Book", False },
2800 Enables gnuEnables[] = {
2801 { "menuMode.ICS Client", False },
2802 { "menuView.ICS Input Box", False },
2803 { "menuAction.Accept", False },
2804 { "menuAction.Decline", False },
2805 { "menuAction.Rematch", False },
2806 { "menuAction.Adjourn", False },
2807 { "menuAction.Stop Examining", False },
2808 { "menuAction.Stop Observing", False },
2809 { "menuAction.Upload to Examine", False },
2810 { "menuEdit.Revert", False },
2811 { "menuEdit.Annotate", False },
2812 { "menuOptions.ICS", False },
2814 /* The next two options rely on SetCmailMode being called *after* */
2815 /* SetGNUMode so that when GNU is being used to give hints these */
2816 /* menu options are still available */
2818 { "menuFile.Mail Move", False },
2819 { "menuFile.Reload CMail Message", False },
2823 Enables cmailEnables[] = {
2825 { "menuAction.Call Flag", False },
2826 { "menuAction.Draw", True },
2827 { "menuAction.Adjourn", False },
2828 { "menuAction.Abort", False },
2829 { "menuAction.Stop Observing", False },
2830 { "menuAction.Stop Examining", False },
2831 { "menuFile.Mail Move", True },
2832 { "menuFile.Reload CMail Message", True },
2836 Enables trainingOnEnables[] = {
2837 { "menuMode.Edit Comment", False },
2838 { "menuMode.Pause", False },
2839 { "menuEdit.Forward", False },
2840 { "menuEdit.Backward", False },
2841 { "menuEdit.Forward to End", False },
2842 { "menuEdit.Back to Start", False },
2843 { "menuEngine.Move Now", False },
2844 { "menuEdit.Truncate Game", False },
2848 Enables trainingOffEnables[] = {
2849 { "menuMode.Edit Comment", True },
2850 { "menuMode.Pause", True },
2851 { "menuEdit.Forward", True },
2852 { "menuEdit.Backward", True },
2853 { "menuEdit.Forward to End", True },
2854 { "menuEdit.Back to Start", True },
2855 { "menuEngine.Move Now", True },
2856 { "menuEdit.Truncate Game", True },
2860 Enables machineThinkingEnables[] = {
2861 { "menuFile.Load Game", False },
2862 // { "menuFile.Load Next Game", False },
2863 // { "menuFile.Load Previous Game", False },
2864 // { "menuFile.Reload Same Game", False },
2865 { "menuEdit.Paste Game", False },
2866 { "menuFile.Load Position", False },
2867 // { "menuFile.Load Next Position", False },
2868 // { "menuFile.Load Previous Position", False },
2869 // { "menuFile.Reload Same Position", False },
2870 { "menuEdit.Paste Position", False },
2871 { "menuMode.Machine White", False },
2872 { "menuMode.Machine Black", False },
2873 { "menuMode.Two Machines", False },
2874 { "menuEngine.Retract Move", False },
2878 Enables userThinkingEnables[] = {
2879 { "menuFile.Load Game", True },
2880 // { "menuFile.Load Next Game", True },
2881 // { "menuFile.Load Previous Game", True },
2882 // { "menuFile.Reload Same Game", True },
2883 { "menuEdit.Paste Game", True },
2884 { "menuFile.Load Position", True },
2885 // { "menuFile.Load Next Position", True },
2886 // { "menuFile.Load Previous Position", True },
2887 // { "menuFile.Reload Same Position", True },
2888 { "menuEdit.Paste Position", True },
2889 { "menuMode.Machine White", True },
2890 { "menuMode.Machine Black", True },
2891 { "menuMode.Two Machines", True },
2892 { "menuEngine.Retract Move", True },
2898 SetMenuEnables(icsEnables);
2901 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2902 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2909 SetMenuEnables(ncpEnables);
2915 SetMenuEnables(gnuEnables);
2921 SetMenuEnables(cmailEnables);
2927 SetMenuEnables(trainingOnEnables);
2928 if (appData.showButtonBar) {
2929 XtSetSensitive(buttonBarWidget, False);
2935 SetTrainingModeOff()
2937 SetMenuEnables(trainingOffEnables);
2938 if (appData.showButtonBar) {
2939 XtSetSensitive(buttonBarWidget, True);
2944 SetUserThinkingEnables()
2946 if (appData.noChessProgram) return;
2947 SetMenuEnables(userThinkingEnables);
2951 SetMachineThinkingEnables()
2953 if (appData.noChessProgram) return;
2954 SetMenuEnables(machineThinkingEnables);
2956 case MachinePlaysBlack:
2957 case MachinePlaysWhite:
2958 case TwoMachinesPlay:
2959 XtSetSensitive(XtNameToWidget(menuBarWidget,
2960 ModeToWidgetName(gameMode)), True);
2967 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2968 #define HISTORY_SIZE 64
2969 static char *history[HISTORY_SIZE];
2970 int histIn = 0, histP = 0;
2973 SaveInHistory(char *cmd)
2975 if (history[histIn] != NULL) {
2976 free(history[histIn]);
2977 history[histIn] = NULL;
2979 if (*cmd == NULLCHAR) return;
2980 history[histIn] = StrSave(cmd);
2981 histIn = (histIn + 1) % HISTORY_SIZE;
2982 if (history[histIn] != NULL) {
2983 free(history[histIn]);
2984 history[histIn] = NULL;
2990 PrevInHistory(char *cmd)
2993 if (histP == histIn) {
2994 if (history[histIn] != NULL) free(history[histIn]);
2995 history[histIn] = StrSave(cmd);
2997 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
2998 if (newhp == histIn || history[newhp] == NULL) return NULL;
3000 return history[histP];
3006 if (histP == histIn) return NULL;
3007 histP = (histP + 1) % HISTORY_SIZE;
3008 return history[histP];
3010 // end of borrowed code
3012 #define Abs(n) ((n)<0 ? -(n) : (n))
3015 * Find a font that matches "pattern" that is as close as
3016 * possible to the targetPxlSize. Prefer fonts that are k
3017 * pixels smaller to fonts that are k pixels larger. The
3018 * pattern must be in the X Consortium standard format,
3019 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3020 * The return value should be freed with XtFree when no
3024 FindFont(pattern, targetPxlSize)
3028 char **fonts, *p, *best, *scalable, *scalableTail;
3029 int i, j, nfonts, minerr, err, pxlSize;
3032 char **missing_list;
3034 char *def_string, *base_fnt_lst, strInt[3];
3036 XFontStruct **fnt_list;
3038 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3039 snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize);
3040 p = strstr(pattern, "--");
3041 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3042 strcat(base_fnt_lst, strInt);
3043 strcat(base_fnt_lst, strchr(p + 2, '-'));
3045 if ((fntSet = XCreateFontSet(xDisplay,
3049 &def_string)) == NULL) {
3051 fprintf(stderr, _("Unable to create font set.\n"));
3055 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3057 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3059 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3060 programName, pattern);
3068 for (i=0; i<nfonts; i++) {
3071 if (*p != '-') continue;
3073 if (*p == NULLCHAR) break;
3074 if (*p++ == '-') j++;
3076 if (j < 7) continue;
3079 scalable = fonts[i];
3082 err = pxlSize - targetPxlSize;
3083 if (Abs(err) < Abs(minerr) ||
3084 (minerr > 0 && err < 0 && -err == minerr)) {
3090 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3091 /* If the error is too big and there is a scalable font,
3092 use the scalable font. */
3093 int headlen = scalableTail - scalable;
3094 p = (char *) XtMalloc(strlen(scalable) + 10);
3095 while (isdigit(*scalableTail)) scalableTail++;
3096 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3098 p = (char *) XtMalloc(strlen(best) + 2);
3099 safeStrCpy(p, best, strlen(best)+1 );
3101 if (appData.debugMode) {
3102 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3103 pattern, targetPxlSize, p);
3106 if (missing_count > 0)
3107 XFreeStringList(missing_list);
3108 XFreeFontSet(xDisplay, fntSet);
3110 XFreeFontNames(fonts);
3116 { // [HGM] deletes GCs that are to be remade, to prevent resource leak;
3117 // must be called before all non-first callse to CreateGCs()
3118 XtReleaseGC(shellWidget, highlineGC);
3119 XtReleaseGC(shellWidget, lightSquareGC);
3120 XtReleaseGC(shellWidget, darkSquareGC);
3121 if (appData.monoMode) {
3122 if (DefaultDepth(xDisplay, xScreen) == 1) {
3123 XtReleaseGC(shellWidget, wbPieceGC);
3125 XtReleaseGC(shellWidget, bwPieceGC);
3128 XtReleaseGC(shellWidget, prelineGC);
3129 XtReleaseGC(shellWidget, jailSquareGC);
3130 XtReleaseGC(shellWidget, wdPieceGC);
3131 XtReleaseGC(shellWidget, wlPieceGC);
3132 XtReleaseGC(shellWidget, wjPieceGC);
3133 XtReleaseGC(shellWidget, bdPieceGC);
3134 XtReleaseGC(shellWidget, blPieceGC);
3135 XtReleaseGC(shellWidget, bjPieceGC);
3139 void CreateGCs(int redo)
3141 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3142 | GCBackground | GCFunction | GCPlaneMask;
3143 XGCValues gc_values;
3146 gc_values.plane_mask = AllPlanes;
3147 gc_values.line_width = lineGap;
3148 gc_values.line_style = LineSolid;
3149 gc_values.function = GXcopy;
3152 DeleteGCs(); // called a second time; clean up old GCs first
3153 } else { // [HGM] grid and font GCs created on first call only
3154 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3155 gc_values.background = XBlackPixel(xDisplay, xScreen);
3156 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3158 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3159 gc_values.background = XWhitePixel(xDisplay, xScreen);
3160 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3161 XSetFont(xDisplay, coordGC, coordFontID);
3163 // [HGM] make font for holdings counts (white on black)
3164 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3165 gc_values.background = XBlackPixel(xDisplay, xScreen);
3166 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3167 XSetFont(xDisplay, countGC, countFontID);
3169 if (appData.monoMode) {
3170 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3171 gc_values.background = XWhitePixel(xDisplay, xScreen);
3172 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3174 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3175 gc_values.background = XBlackPixel(xDisplay, xScreen);
3176 lightSquareGC = wbPieceGC
3177 = XtGetGC(shellWidget, value_mask, &gc_values);
3179 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3180 gc_values.background = XWhitePixel(xDisplay, xScreen);
3181 darkSquareGC = bwPieceGC
3182 = XtGetGC(shellWidget, value_mask, &gc_values);
3184 if (DefaultDepth(xDisplay, xScreen) == 1) {
3185 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3186 gc_values.function = GXcopyInverted;
3187 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3188 gc_values.function = GXcopy;
3189 if (XBlackPixel(xDisplay, xScreen) == 1) {
3190 bwPieceGC = darkSquareGC;
3191 wbPieceGC = copyInvertedGC;
3193 bwPieceGC = copyInvertedGC;
3194 wbPieceGC = lightSquareGC;
3198 gc_values.foreground = highlightSquareColor;
3199 gc_values.background = highlightSquareColor;
3200 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3202 gc_values.foreground = premoveHighlightColor;
3203 gc_values.background = premoveHighlightColor;
3204 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3206 gc_values.foreground = lightSquareColor;
3207 gc_values.background = darkSquareColor;
3208 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3210 gc_values.foreground = darkSquareColor;
3211 gc_values.background = lightSquareColor;
3212 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3214 gc_values.foreground = jailSquareColor;
3215 gc_values.background = jailSquareColor;
3216 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3218 gc_values.foreground = whitePieceColor;
3219 gc_values.background = darkSquareColor;
3220 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3222 gc_values.foreground = whitePieceColor;
3223 gc_values.background = lightSquareColor;
3224 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3226 gc_values.foreground = whitePieceColor;
3227 gc_values.background = jailSquareColor;
3228 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3230 gc_values.foreground = blackPieceColor;
3231 gc_values.background = darkSquareColor;
3232 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3234 gc_values.foreground = blackPieceColor;
3235 gc_values.background = lightSquareColor;
3236 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3238 gc_values.foreground = blackPieceColor;
3239 gc_values.background = jailSquareColor;
3240 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3244 void loadXIM(xim, xmask, filename, dest, mask)
3257 fp = fopen(filename, "rb");
3259 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3266 for (y=0; y<h; ++y) {
3267 for (x=0; x<h; ++x) {
3272 XPutPixel(xim, x, y, blackPieceColor);
3274 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3277 XPutPixel(xim, x, y, darkSquareColor);
3279 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3282 XPutPixel(xim, x, y, whitePieceColor);
3284 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3287 XPutPixel(xim, x, y, lightSquareColor);
3289 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3297 /* create Pixmap of piece */
3298 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3300 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3303 /* create Pixmap of clipmask
3304 Note: We assume the white/black pieces have the same
3305 outline, so we make only 6 masks. This is okay
3306 since the XPM clipmask routines do the same. */
3308 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3310 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3313 /* now create the 1-bit version */
3314 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3317 values.foreground = 1;
3318 values.background = 0;
3320 /* Don't use XtGetGC, not read only */
3321 maskGC = XCreateGC(xDisplay, *mask,
3322 GCForeground | GCBackground, &values);
3323 XCopyPlane(xDisplay, temp, *mask, maskGC,
3324 0, 0, squareSize, squareSize, 0, 0, 1);
3325 XFreePixmap(xDisplay, temp);
3330 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3332 void CreateXIMPieces()
3337 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3342 /* The XSynchronize calls were copied from CreatePieces.
3343 Not sure if needed, but can't hurt */
3344 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3347 /* temp needed by loadXIM() */
3348 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3349 0, 0, ss, ss, AllPlanes, XYPixmap);
3351 if (strlen(appData.pixmapDirectory) == 0) {
3355 if (appData.monoMode) {
3356 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3360 fprintf(stderr, _("\nLoading XIMs...\n"));
3362 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3363 fprintf(stderr, "%d", piece+1);
3364 for (kind=0; kind<4; kind++) {
3365 fprintf(stderr, ".");
3366 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3367 ExpandPathName(appData.pixmapDirectory),
3368 piece <= (int) WhiteKing ? "" : "w",
3369 pieceBitmapNames[piece],
3371 ximPieceBitmap[kind][piece] =
3372 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3373 0, 0, ss, ss, AllPlanes, XYPixmap);
3374 if (appData.debugMode)
3375 fprintf(stderr, _("(File:%s:) "), buf);
3376 loadXIM(ximPieceBitmap[kind][piece],
3378 &(xpmPieceBitmap2[kind][piece]),
3379 &(ximMaskPm2[piece]));
3380 if(piece <= (int)WhiteKing)
3381 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3383 fprintf(stderr," ");
3385 /* Load light and dark squares */
3386 /* If the LSQ and DSQ pieces don't exist, we will
3387 draw them with solid squares. */
3388 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3389 if (access(buf, 0) != 0) {
3393 fprintf(stderr, _("light square "));
3395 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3396 0, 0, ss, ss, AllPlanes, XYPixmap);
3397 if (appData.debugMode)
3398 fprintf(stderr, _("(File:%s:) "), buf);
3400 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3401 fprintf(stderr, _("dark square "));
3402 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3403 ExpandPathName(appData.pixmapDirectory), ss);
3404 if (appData.debugMode)
3405 fprintf(stderr, _("(File:%s:) "), buf);
3407 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3408 0, 0, ss, ss, AllPlanes, XYPixmap);
3409 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3410 xpmJailSquare = xpmLightSquare;
3412 fprintf(stderr, _("Done.\n"));
3414 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3418 void CreateXPMBoard(char *s, int kind)
3422 if(s == NULL || *s == 0 || *s == '*') { useTexture &= ~(kind+1); return; }
3423 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3424 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3428 void FreeXPMPieces()
3429 { // [HGM] to prevent resoucre leak on calling CreaeXPMPieces() a second time,
3430 // thisroutine has to be called t free the old piece pixmaps
3432 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++)
3433 for (kind=0; kind<4; kind++) XFreePixmap(xDisplay, xpmPieceBitmap2[kind][piece]);
3435 XFreePixmap(xDisplay, xpmLightSquare);
3436 XFreePixmap(xDisplay, xpmDarkSquare);
3440 void CreateXPMPieces()
3444 u_int ss = squareSize;
3446 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3447 XpmColorSymbol symbols[4];
3448 static int redo = False;
3450 if(redo) FreeXPMPieces(); else redo = 1;
3452 /* The XSynchronize calls were copied from CreatePieces.
3453 Not sure if needed, but can't hurt */
3454 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3456 /* Setup translations so piece colors match square colors */
3457 symbols[0].name = "light_piece";
3458 symbols[0].value = appData.whitePieceColor;
3459 symbols[1].name = "dark_piece";
3460 symbols[1].value = appData.blackPieceColor;
3461 symbols[2].name = "light_square";
3462 symbols[2].value = appData.lightSquareColor;
3463 symbols[3].name = "dark_square";
3464 symbols[3].value = appData.darkSquareColor;
3466 attr.valuemask = XpmColorSymbols;
3467 attr.colorsymbols = symbols;
3468 attr.numsymbols = 4;
3470 if (appData.monoMode) {
3471 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3475 if (strlen(appData.pixmapDirectory) == 0) {
3476 XpmPieces* pieces = builtInXpms;
3479 while (pieces->size != squareSize && pieces->size) pieces++;
3480 if (!pieces->size) {
3481 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3484 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3485 for (kind=0; kind<4; kind++) {
3487 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3488 pieces->xpm[piece][kind],
3489 &(xpmPieceBitmap2[kind][piece]),
3490 NULL, &attr)) != 0) {
3491 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3495 if(piece <= (int) WhiteKing)
3496 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3500 xpmJailSquare = xpmLightSquare;
3504 fprintf(stderr, _("\nLoading XPMs...\n"));
3507 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3508 fprintf(stderr, "%d ", piece+1);
3509 for (kind=0; kind<4; kind++) {
3510 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3511 ExpandPathName(appData.pixmapDirectory),
3512 piece > (int) WhiteKing ? "w" : "",
3513 pieceBitmapNames[piece],
3515 if (appData.debugMode) {
3516 fprintf(stderr, _("(File:%s:) "), buf);
3518 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3519 &(xpmPieceBitmap2[kind][piece]),
3520 NULL, &attr)) != 0) {
3521 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3522 // [HGM] missing: read of unorthodox piece failed; substitute King.
3523 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3524 ExpandPathName(appData.pixmapDirectory),
3526 if (appData.debugMode) {
3527 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3529 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3530 &(xpmPieceBitmap2[kind][piece]),
3534 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3539 if(piece <= (int) WhiteKing)
3540 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3543 /* Load light and dark squares */
3544 /* If the LSQ and DSQ pieces don't exist, we will
3545 draw them with solid squares. */
3546 fprintf(stderr, _("light square "));
3547 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3548 if (access(buf, 0) != 0) {
3552 if (appData.debugMode)
3553 fprintf(stderr, _("(File:%s:) "), buf);
3555 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3556 &xpmLightSquare, NULL, &attr)) != 0) {
3557 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3560 fprintf(stderr, _("dark square "));
3561 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3562 ExpandPathName(appData.pixmapDirectory), ss);
3563 if (appData.debugMode) {
3564 fprintf(stderr, _("(File:%s:) "), buf);
3566 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3567 &xpmDarkSquare, NULL, &attr)) != 0) {
3568 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3572 xpmJailSquare = xpmLightSquare;
3573 fprintf(stderr, _("Done.\n"));
3575 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3578 #endif /* HAVE_LIBXPM */
3581 /* No built-in bitmaps */
3586 u_int ss = squareSize;
3588 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3591 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3592 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3593 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3594 pieceBitmapNames[piece],
3595 ss, kind == SOLID ? 's' : 'o');
3596 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3597 if(piece <= (int)WhiteKing)
3598 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3602 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3606 /* With built-in bitmaps */
3609 BuiltInBits* bib = builtInBits;
3612 u_int ss = squareSize;
3614 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3617 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3619 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3620 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3621 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3622 pieceBitmapNames[piece],
3623 ss, kind == SOLID ? 's' : 'o');
3624 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3625 bib->bits[kind][piece], ss, ss);
3626 if(piece <= (int)WhiteKing)
3627 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3631 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3636 void ReadBitmap(pm, name, bits, wreq, hreq)
3639 unsigned char bits[];
3645 char msg[MSG_SIZ], fullname[MSG_SIZ];
3647 if (*appData.bitmapDirectory != NULLCHAR) {
3648 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3649 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3650 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3651 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3652 &w, &h, pm, &x_hot, &y_hot);
3653 fprintf(stderr, "load %s\n", name);
3654 if (errcode != BitmapSuccess) {
3656 case BitmapOpenFailed:
3657 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3659 case BitmapFileInvalid:
3660 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3662 case BitmapNoMemory:
3663 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3667 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3671 fprintf(stderr, _("%s: %s...using built-in\n"),
3673 } else if (w != wreq || h != hreq) {
3675 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3676 programName, fullname, w, h, wreq, hreq);
3682 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3691 if (lineGap == 0) return;
3693 /* [HR] Split this into 2 loops for non-square boards. */
3695 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3696 gridSegments[i].x1 = 0;
3697 gridSegments[i].x2 =
3698 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3699 gridSegments[i].y1 = gridSegments[i].y2
3700 = lineGap / 2 + (i * (squareSize + lineGap));
3703 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3704 gridSegments[j + i].y1 = 0;
3705 gridSegments[j + i].y2 =
3706 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3707 gridSegments[j + i].x1 = gridSegments[j + i].x2
3708 = lineGap / 2 + (j * (squareSize + lineGap));
3712 static void MenuBarSelect(w, addr, index)
3717 XtActionProc proc = (XtActionProc) addr;
3719 (proc)(NULL, NULL, NULL, NULL);
3722 void CreateMenuBarPopup(parent, name, mb)
3732 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3735 XtSetArg(args[j], XtNleftMargin, 20); j++;
3736 XtSetArg(args[j], XtNrightMargin, 20); j++;
3738 while (mi->string != NULL) {
3739 if (strcmp(mi->string, "----") == 0) {
3740 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3743 XtSetArg(args[j], XtNlabel, XtNewString(mi->string));
3744 entry = XtCreateManagedWidget(mi->ref, smeBSBObjectClass,
3746 XtAddCallback(entry, XtNcallback,
3747 (XtCallbackProc) MenuBarSelect,
3748 (caddr_t) mi->proc);
3754 Widget CreateMenuBar(mb)
3758 Widget anchor, menuBar;
3760 char menuName[MSG_SIZ];
3763 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3764 XtSetArg(args[j], XtNvSpace, 0); j++;
3765 XtSetArg(args[j], XtNborderWidth, 0); j++;
3766 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3767 formWidget, args, j);
3769 while (mb->name != NULL) {
3770 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3771 strncat(menuName, mb->ref, MSG_SIZ - strlen(menuName) - 1);
3773 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3776 shortName[0] = mb->name[0];
3777 shortName[1] = NULLCHAR;
3778 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3781 XtSetArg(args[j], XtNlabel, XtNewString(mb->name)); j++;
3784 XtSetArg(args[j], XtNborderWidth, 0); j++;
3785 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3787 CreateMenuBarPopup(menuBar, menuName, mb);
3793 Widget CreateButtonBar(mi)
3797 Widget button, buttonBar;
3801 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3803 XtSetArg(args[j], XtNhSpace, 0); j++;
3805 XtSetArg(args[j], XtNborderWidth, 0); j++;
3806 XtSetArg(args[j], XtNvSpace, 0); j++;
3807 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3808 formWidget, args, j);
3810 while (mi->string != NULL) {
3813 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3814 XtSetArg(args[j], XtNborderWidth, 0); j++;
3816 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3817 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3818 buttonBar, args, j);
3819 XtAddCallback(button, XtNcallback,
3820 (XtCallbackProc) MenuBarSelect,
3821 (caddr_t) mi->proc);
3828 CreatePieceMenu(name, color)
3835 ChessSquare selection;
3837 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3838 boardWidget, args, 0);
3840 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3841 String item = pieceMenuStrings[color][i];
3843 if (strcmp(item, "----") == 0) {
3844 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3847 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3848 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3850 selection = pieceMenuTranslation[color][i];
3851 XtAddCallback(entry, XtNcallback,
3852 (XtCallbackProc) PieceMenuSelect,
3853 (caddr_t) selection);
3854 if (selection == WhitePawn || selection == BlackPawn) {
3855 XtSetArg(args[0], XtNpopupOnEntry, entry);
3856 XtSetValues(menu, args, 1);
3869 ChessSquare selection;
3871 whitePieceMenu = CreatePieceMenu("menuW", 0);
3872 blackPieceMenu = CreatePieceMenu("menuB", 1);
3874 XtRegisterGrabAction(PieceMenuPopup, True,
3875 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3876 GrabModeAsync, GrabModeAsync);
3878 XtSetArg(args[0], XtNlabel, _("Drop"));
3879 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3880 boardWidget, args, 1);
3881 for (i = 0; i < DROP_MENU_SIZE; i++) {
3882 String item = dropMenuStrings[i];
3884 if (strcmp(item, "----") == 0) {
3885 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3888 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3889 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3891 selection = dropMenuTranslation[i];
3892 XtAddCallback(entry, XtNcallback,
3893 (XtCallbackProc) DropMenuSelect,
3894 (caddr_t) selection);
3899 void SetupDropMenu()
3907 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3908 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3909 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3910 dmEnables[i].piece);
3911 XtSetSensitive(entry, p != NULL || !appData.testLegality
3912 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3913 && !appData.icsActive));
3915 while (p && *p++ == dmEnables[i].piece) count++;
3916 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3918 XtSetArg(args[j], XtNlabel, label); j++;
3919 XtSetValues(entry, args, j);
3923 void PieceMenuPopup(w, event, params, num_params)
3927 Cardinal *num_params;
3929 String whichMenu; int menuNr;
3930 if (event->type == ButtonRelease)
3931 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3932 else if (event->type == ButtonPress)
3933 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3935 case 0: whichMenu = params[0]; break;
3936 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3938 case -1: if (errorUp) ErrorPopDown();
3941 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3944 static void PieceMenuSelect(w, piece, junk)
3949 if (pmFromX < 0 || pmFromY < 0) return;
3950 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3953 static void DropMenuSelect(w, piece, junk)
3958 if (pmFromX < 0 || pmFromY < 0) return;
3959 DropMenuEvent(piece, pmFromX, pmFromY);
3962 void WhiteClock(w, event, prms, nprms)
3971 void BlackClock(w, event, prms, nprms)
3982 * If the user selects on a border boundary, return -1; if off the board,
3983 * return -2. Otherwise map the event coordinate to the square.
3985 int EventToSquare(x, limit)
3993 if ((x % (squareSize + lineGap)) >= squareSize)
3995 x /= (squareSize + lineGap);
4001 static void do_flash_delay(msec)
4007 static void drawHighlight(file, rank, gc)
4013 if (lineGap == 0) return;
4016 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
4017 (squareSize + lineGap);
4018 y = lineGap/2 + rank * (squareSize + lineGap);
4020 x = lineGap/2 + file * (squareSize + lineGap);
4021 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
4022 (squareSize + lineGap);
4025 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
4026 squareSize+lineGap, squareSize+lineGap);
4029 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
4030 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4033 SetHighlights(fromX, fromY, toX, toY)
4034 int fromX, fromY, toX, toY;
4036 if (hi1X != fromX || hi1Y != fromY) {
4037 if (hi1X >= 0 && hi1Y >= 0) {
4038 drawHighlight(hi1X, hi1Y, lineGC);
4040 } // [HGM] first erase both, then draw new!
4041 if (hi2X != toX || hi2Y != toY) {
4042 if (hi2X >= 0 && hi2Y >= 0) {
4043 drawHighlight(hi2X, hi2Y, lineGC);
4046 if (hi1X != fromX || hi1Y != fromY) {
4047 if (fromX >= 0 && fromY >= 0) {
4048 drawHighlight(fromX, fromY, highlineGC);
4051 if (hi2X != toX || hi2Y != toY) {
4052 if (toX >= 0 && toY >= 0) {
4053 drawHighlight(toX, toY, highlineGC);
4065 SetHighlights(-1, -1, -1, -1);
4070 SetPremoveHighlights(fromX, fromY, toX, toY)
4071 int fromX, fromY, toX, toY;
4073 if (pm1X != fromX || pm1Y != fromY) {
4074 if (pm1X >= 0 && pm1Y >= 0) {
4075 drawHighlight(pm1X, pm1Y, lineGC);
4077 if (fromX >= 0 && fromY >= 0) {
4078 drawHighlight(fromX, fromY, prelineGC);
4081 if (pm2X != toX || pm2Y != toY) {
4082 if (pm2X >= 0 && pm2Y >= 0) {
4083 drawHighlight(pm2X, pm2Y, lineGC);
4085 if (toX >= 0 && toY >= 0) {
4086 drawHighlight(toX, toY, prelineGC);
4096 ClearPremoveHighlights()
4098 SetPremoveHighlights(-1, -1, -1, -1);
4101 static int CutOutSquare(x, y, x0, y0, kind)
4102 int x, y, *x0, *y0, kind;
4104 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
4105 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
4107 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
4108 if(textureW[kind] < W*squareSize)
4109 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
4111 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
4112 if(textureH[kind] < H*squareSize)
4113 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
4115 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
4119 static void BlankSquare(x, y, color, piece, dest, fac)
4120 int x, y, color, fac;
4123 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
4125 if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
4126 XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
4127 squareSize, squareSize, x*fac, y*fac);
4129 if (useImages && useImageSqs) {
4133 pm = xpmLightSquare;
4138 case 2: /* neutral */
4143 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4144 squareSize, squareSize, x*fac, y*fac);
4154 case 2: /* neutral */
4159 XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
4164 I split out the routines to draw a piece so that I could
4165 make a generic flash routine.
4167 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4169 int square_color, x, y;
4172 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4173 switch (square_color) {
4175 case 2: /* neutral */
4177 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4178 ? *pieceToOutline(piece)
4179 : *pieceToSolid(piece),
4180 dest, bwPieceGC, 0, 0,
4181 squareSize, squareSize, x, y);
4184 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4185 ? *pieceToSolid(piece)
4186 : *pieceToOutline(piece),
4187 dest, wbPieceGC, 0, 0,
4188 squareSize, squareSize, x, y);
4193 static void monoDrawPiece(piece, square_color, x, y, dest)
4195 int square_color, x, y;
4198 switch (square_color) {
4200 case 2: /* neutral */
4202 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4203 ? *pieceToOutline(piece)
4204 : *pieceToSolid(piece),
4205 dest, bwPieceGC, 0, 0,
4206 squareSize, squareSize, x, y, 1);
4209 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4210 ? *pieceToSolid(piece)
4211 : *pieceToOutline(piece),
4212 dest, wbPieceGC, 0, 0,
4213 squareSize, squareSize, x, y, 1);
4218 static void colorDrawPiece(piece, square_color, x, y, dest)
4220 int square_color, x, y;
4223 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4224 switch (square_color) {
4226 XCopyPlane(xDisplay, *pieceToSolid(piece),
4227 dest, (int) piece < (int) BlackPawn
4228 ? wlPieceGC : blPieceGC, 0, 0,
4229 squareSize, squareSize, x, y, 1);
4232 XCopyPlane(xDisplay, *pieceToSolid(piece),
4233 dest, (int) piece < (int) BlackPawn
4234 ? wdPieceGC : bdPieceGC, 0, 0,
4235 squareSize, squareSize, x, y, 1);
4237 case 2: /* neutral */
4239 XCopyPlane(xDisplay, *pieceToSolid(piece),
4240 dest, (int) piece < (int) BlackPawn
4241 ? wjPieceGC : bjPieceGC, 0, 0,
4242 squareSize, squareSize, x, y, 1);
4247 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4249 int square_color, x, y;
4252 int kind, p = piece;
4254 switch (square_color) {
4256 case 2: /* neutral */
4258 if ((int)piece < (int) BlackPawn) {
4266 if ((int)piece < (int) BlackPawn) {
4274 if(appData.upsideDown && flipView) { kind ^= 2; p += p < BlackPawn ? BlackPawn : -BlackPawn; }// swap white and black pieces
4275 if(useTexture & square_color+1) {
4276 BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background
4277 XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]);
4278 XSetClipOrigin(xDisplay, wlPieceGC, x, y);
4279 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y);
4280 XSetClipMask(xDisplay, wlPieceGC, None);
4281 XSetClipOrigin(xDisplay, wlPieceGC, 0, 0);
4283 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4284 dest, wlPieceGC, 0, 0,
4285 squareSize, squareSize, x, y);
4288 typedef void (*DrawFunc)();
4290 DrawFunc ChooseDrawFunc()
4292 if (appData.monoMode) {
4293 if (DefaultDepth(xDisplay, xScreen) == 1) {
4294 return monoDrawPiece_1bit;
4296 return monoDrawPiece;
4300 return colorDrawPieceImage;
4302 return colorDrawPiece;
4306 /* [HR] determine square color depending on chess variant. */
4307 static int SquareColor(row, column)
4312 if (gameInfo.variant == VariantXiangqi) {
4313 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4315 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4317 } else if (row <= 4) {
4323 square_color = ((column + row) % 2) == 1;
4326 /* [hgm] holdings: next line makes all holdings squares light */
4327 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4329 return square_color;
4332 void DrawSquare(row, column, piece, do_flash)
4333 int row, column, do_flash;
4336 int square_color, x, y, direction, font_ascent, font_descent;
4339 XCharStruct overall;
4343 /* Calculate delay in milliseconds (2-delays per complete flash) */
4344 flash_delay = 500 / appData.flashRate;
4347 x = lineGap + ((BOARD_WIDTH-1)-column) *
4348 (squareSize + lineGap);
4349 y = lineGap + row * (squareSize + lineGap);
4351 x = lineGap + column * (squareSize + lineGap);
4352 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4353 (squareSize + lineGap);
4356 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4358 square_color = SquareColor(row, column);
4360 if ( // [HGM] holdings: blank out area between board and holdings
4361 column == BOARD_LEFT-1 || column == BOARD_RGHT
4362 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4363 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4364 BlankSquare(x, y, 2, EmptySquare, xBoardWindow, 1);
4366 // [HGM] print piece counts next to holdings
4367 string[1] = NULLCHAR;
4368 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4369 string[0] = '0' + piece;
4370 XTextExtents(countFontStruct, string, 1, &direction,
4371 &font_ascent, &font_descent, &overall);
4372 if (appData.monoMode) {
4373 XDrawImageString(xDisplay, xBoardWindow, countGC,
4374 x + squareSize - overall.width - 2,
4375 y + font_ascent + 1, string, 1);
4377 XDrawString(xDisplay, xBoardWindow, countGC,
4378 x + squareSize - overall.width - 2,
4379 y + font_ascent + 1, string, 1);
4382 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4383 string[0] = '0' + piece;
4384 XTextExtents(countFontStruct, string, 1, &direction,
4385 &font_ascent, &font_descent, &overall);
4386 if (appData.monoMode) {
4387 XDrawImageString(xDisplay, xBoardWindow, countGC,
4388 x + 2, y + font_ascent + 1, string, 1);
4390 XDrawString(xDisplay, xBoardWindow, countGC,
4391 x + 2, y + font_ascent + 1, string, 1);
4395 if (piece == EmptySquare || appData.blindfold) {
4396 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4398 drawfunc = ChooseDrawFunc();
4399 if (do_flash && appData.flashCount > 0) {
4400 for (i=0; i<appData.flashCount; ++i) {
4402 drawfunc(piece, square_color, x, y, xBoardWindow);
4403 XSync(xDisplay, False);
4404 do_flash_delay(flash_delay);
4406 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4407 XSync(xDisplay, False);
4408 do_flash_delay(flash_delay);
4411 drawfunc(piece, square_color, x, y, xBoardWindow);
4415 string[1] = NULLCHAR;
4416 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4417 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4418 string[0] = 'a' + column - BOARD_LEFT;
4419 XTextExtents(coordFontStruct, string, 1, &direction,
4420 &font_ascent, &font_descent, &overall);
4421 if (appData.monoMode) {
4422 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4423 x + squareSize - overall.width - 2,
4424 y + squareSize - font_descent - 1, string, 1);
4426 XDrawString(xDisplay, xBoardWindow, coordGC,
4427 x + squareSize - overall.width - 2,
4428 y + squareSize - font_descent - 1, string, 1);
4431 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4432 string[0] = ONE + row;
4433 XTextExtents(coordFontStruct, string, 1, &direction,
4434 &font_ascent, &font_descent, &overall);
4435 if (appData.monoMode) {
4436 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4437 x + 2, y + font_ascent + 1, string, 1);
4439 XDrawString(xDisplay, xBoardWindow, coordGC,
4440 x + 2, y + font_ascent + 1, string, 1);
4443 if(!partnerUp && marker[row][column]) {
4444 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4445 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4450 /* Why is this needed on some versions of X? */
4451 void EventProc(widget, unused, event)
4456 if (!XtIsRealized(widget))
4459 switch (event->type) {
4461 if (event->xexpose.count > 0) return; /* no clipping is done */
4462 XDrawPosition(widget, True, NULL);
4463 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4464 flipView = !flipView; partnerUp = !partnerUp;
4465 XDrawPosition(widget, True, NULL);
4466 flipView = !flipView; partnerUp = !partnerUp;
4470 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
4477 void DrawPosition(fullRedraw, board)
4478 /*Boolean*/int fullRedraw;
4481 XDrawPosition(boardWidget, fullRedraw, board);
4484 /* Returns 1 if there are "too many" differences between b1 and b2
4485 (i.e. more than 1 move was made) */
4486 static int too_many_diffs(b1, b2)
4492 for (i=0; i<BOARD_HEIGHT; ++i) {
4493 for (j=0; j<BOARD_WIDTH; ++j) {
4494 if (b1[i][j] != b2[i][j]) {
4495 if (++c > 4) /* Castling causes 4 diffs */
4504 /* Matrix describing castling maneuvers */
4505 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4506 static int castling_matrix[4][5] = {
4507 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4508 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4509 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4510 { 7, 7, 4, 5, 6 } /* 0-0, black */
4513 /* Checks whether castling occurred. If it did, *rrow and *rcol
4514 are set to the destination (row,col) of the rook that moved.
4516 Returns 1 if castling occurred, 0 if not.
4518 Note: Only handles a max of 1 castling move, so be sure
4519 to call too_many_diffs() first.
4521 static int check_castle_draw(newb, oldb, rrow, rcol)
4528 /* For each type of castling... */
4529 for (i=0; i<4; ++i) {
4530 r = castling_matrix[i];
4532 /* Check the 4 squares involved in the castling move */
4534 for (j=1; j<=4; ++j) {
4535 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4542 /* All 4 changed, so it must be a castling move */
4551 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4552 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4554 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4557 void DrawSeekBackground( int left, int top, int right, int bottom )
4559 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4562 void DrawSeekText(char *buf, int x, int y)
4564 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4567 void DrawSeekDot(int x, int y, int colorNr)
4569 int square = colorNr & 0x80;
4572 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4574 XFillRectangle(xDisplay, xBoardWindow, color,
4575 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4577 XFillArc(xDisplay, xBoardWindow, color,
4578 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4581 static int damage[2][BOARD_RANKS][BOARD_FILES];
4584 * event handler for redrawing the board
4586 void XDrawPosition(w, repaint, board)
4588 /*Boolean*/int repaint;
4592 static int lastFlipView = 0;
4593 static int lastBoardValid[2] = {0, 0};
4594 static Board lastBoard[2];
4597 int nr = twoBoards*partnerUp;
4599 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4601 if (board == NULL) {
4602 if (!lastBoardValid[nr]) return;
4603 board = lastBoard[nr];
4605 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4606 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4607 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Flip View"),
4612 * It would be simpler to clear the window with XClearWindow()
4613 * but this causes a very distracting flicker.
4616 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4618 if ( lineGap && IsDrawArrowEnabled())
4619 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4620 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4622 /* If too much changes (begin observing new game, etc.), don't
4624 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4626 /* Special check for castling so we don't flash both the king
4627 and the rook (just flash the king). */
4629 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4630 /* Draw rook with NO flashing. King will be drawn flashing later */
4631 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4632 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4636 /* First pass -- Draw (newly) empty squares and repair damage.
4637 This prevents you from having a piece show up twice while it
4638 is flashing on its new square */
4639 for (i = 0; i < BOARD_HEIGHT; i++)
4640 for (j = 0; j < BOARD_WIDTH; j++)
4641 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4642 || damage[nr][i][j]) {
4643 DrawSquare(i, j, board[i][j], 0);
4644 damage[nr][i][j] = False;
4647 /* Second pass -- Draw piece(s) in new position and flash them */
4648 for (i = 0; i < BOARD_HEIGHT; i++)
4649 for (j = 0; j < BOARD_WIDTH; j++)
4650 if (board[i][j] != lastBoard[nr][i][j]) {
4651 DrawSquare(i, j, board[i][j], do_flash);
4655 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4656 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4657 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4659 for (i = 0; i < BOARD_HEIGHT; i++)
4660 for (j = 0; j < BOARD_WIDTH; j++) {
4661 DrawSquare(i, j, board[i][j], 0);
4662 damage[nr][i][j] = False;
4666 CopyBoard(lastBoard[nr], board);
4667 lastBoardValid[nr] = 1;
4668 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4669 lastFlipView = flipView;
4671 /* Draw highlights */
4672 if (pm1X >= 0 && pm1Y >= 0) {
4673 drawHighlight(pm1X, pm1Y, prelineGC);
4675 if (pm2X >= 0 && pm2Y >= 0) {
4676 drawHighlight(pm2X, pm2Y, prelineGC);
4678 if (hi1X >= 0 && hi1Y >= 0) {
4679 drawHighlight(hi1X, hi1Y, highlineGC);
4681 if (hi2X >= 0 && hi2Y >= 0) {
4682 drawHighlight(hi2X, hi2Y, highlineGC);
4684 DrawArrowHighlight(hi1X, hi1Y, hi2X, hi2Y);
4686 /* If piece being dragged around board, must redraw that too */
4689 XSync(xDisplay, False);
4694 * event handler for redrawing the board
4696 void DrawPositionProc(w, event, prms, nprms)
4702 XDrawPosition(w, True, NULL);
4707 * event handler for parsing user moves
4709 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4710 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4711 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4712 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4713 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4714 // and at the end FinishMove() to perform the move after optional promotion popups.
4715 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4716 void HandleUserMove(w, event, prms, nprms)
4722 if (w != boardWidget || errorExitStatus != -1) return;
4723 if(nprms) shiftKey = !strcmp(prms[0], "1");
4726 if (event->type == ButtonPress) {
4727 XtPopdown(promotionShell);
4728 XtDestroyWidget(promotionShell);
4729 promotionUp = False;
4737 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4738 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4739 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4742 void AnimateUserMove (Widget w, XEvent * event,
4743 String * params, Cardinal * nParams)
4745 DragPieceMove(event->xmotion.x, event->xmotion.y);
4748 void HandlePV (Widget w, XEvent * event,
4749 String * params, Cardinal * nParams)
4750 { // [HGM] pv: walk PV
4751 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4754 Widget CommentCreate(name, text, mutable, callback, lines)
4756 int /*Boolean*/ mutable;
4757 XtCallbackProc callback;
4761 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4766 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4767 XtGetValues(boardWidget, args, j);
4770 XtSetArg(args[j], XtNresizable, True); j++;
4773 XtCreatePopupShell(name, topLevelShellWidgetClass,
4774 shellWidget, args, j);
4777 XtCreatePopupShell(name, transientShellWidgetClass,
4778 shellWidget, args, j);
4781 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4782 layoutArgs, XtNumber(layoutArgs));
4784 XtCreateManagedWidget("form", formWidgetClass, layout,
4785 formArgs, XtNumber(formArgs));
4789 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4790 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4792 XtSetArg(args[j], XtNstring, text); j++;
4793 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4794 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4795 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4796 XtSetArg(args[j], XtNright, XtChainRight); j++;
4797 XtSetArg(args[j], XtNresizable, True); j++;
4798 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4799 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4800 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4801 XtSetArg(args[j], XtNautoFill, True); j++;
4802 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4804 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4805 XtOverrideTranslations(edit, XtParseTranslationTable(commentTranslations));
4809 XtSetArg(args[j], XtNfromVert, edit); j++;
4810 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4811 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4812 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4813 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4815 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4816 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4819 XtSetArg(args[j], XtNfromVert, edit); j++;
4820 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4821 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4822 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4823 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4824 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4826 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4827 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4830 XtSetArg(args[j], XtNfromVert, edit); j++;
4831 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4832 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4833 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4834 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4835 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4837 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4838 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4841 XtSetArg(args[j], XtNfromVert, edit); j++;
4842 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4843 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4844 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4845 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4847 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4848 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4851 XtSetArg(args[j], XtNfromVert, edit); j++;
4852 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4853 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4854 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4855 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4856 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4858 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4859 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4862 XtRealizeWidget(shell);
4864 if (commentX == -1) {
4867 Dimension pw_height;
4868 Dimension ew_height;
4871 XtSetArg(args[j], XtNheight, &ew_height); j++;
4872 XtGetValues(edit, args, j);
4875 XtSetArg(args[j], XtNheight, &pw_height); j++;
4876 XtGetValues(shell, args, j);
4877 commentH = pw_height + (lines - 1) * ew_height;
4878 commentW = bw_width - 16;
4880 XSync(xDisplay, False);
4882 /* This code seems to tickle an X bug if it is executed too soon
4883 after xboard starts up. The coordinates get transformed as if
4884 the main window was positioned at (0, 0).
4886 XtTranslateCoords(shellWidget,
4887 (bw_width - commentW) / 2, 0 - commentH / 2,
4888 &commentX, &commentY);
4890 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4891 RootWindowOfScreen(XtScreen(shellWidget)),
4892 (bw_width - commentW) / 2, 0 - commentH / 2,
4897 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4900 if(wpComment.width > 0) {
4901 commentX = wpComment.x;
4902 commentY = wpComment.y;
4903 commentW = wpComment.width;
4904 commentH = wpComment.height;
4908 XtSetArg(args[j], XtNheight, commentH); j++;
4909 XtSetArg(args[j], XtNwidth, commentW); j++;
4910 XtSetArg(args[j], XtNx, commentX); j++;
4911 XtSetArg(args[j], XtNy, commentY); j++;
4912 XtSetValues(shell, args, j);
4913 XtSetKeyboardFocus(shell, edit);
4918 /* Used for analysis window and ICS input window */
4919 Widget MiscCreate(name, text, mutable, callback, lines)
4921 int /*Boolean*/ mutable;
4922 XtCallbackProc callback;
4926 Widget shell, layout, form, edit;
4928 Dimension bw_width, pw_height, ew_height, w, h;
4934 XtSetArg(args[j], XtNresizable, True); j++;
4937 XtCreatePopupShell(name, topLevelShellWidgetClass,
4938 shellWidget, args, j);
4941 XtCreatePopupShell(name, transientShellWidgetClass,
4942 shellWidget, args, j);
4945 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4946 layoutArgs, XtNumber(layoutArgs));
4948 XtCreateManagedWidget("form", formWidgetClass, layout,
4949 formArgs, XtNumber(formArgs));
4953 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4954 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4956 XtSetArg(args[j], XtNstring, text); j++;
4957 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4958 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4959 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4960 XtSetArg(args[j], XtNright, XtChainRight); j++;
4961 XtSetArg(args[j], XtNresizable, True); j++;
4962 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4963 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4964 XtSetArg(args[j], XtNautoFill, True); j++;
4965 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4967 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4969 XtRealizeWidget(shell);
4972 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4973 XtGetValues(boardWidget, args, j);
4976 XtSetArg(args[j], XtNheight, &ew_height); j++;
4977 XtGetValues(edit, args, j);
4980 XtSetArg(args[j], XtNheight, &pw_height); j++;
4981 XtGetValues(shell, args, j);
4982 h = pw_height + (lines - 1) * ew_height;
4985 XSync(xDisplay, False);
4987 /* This code seems to tickle an X bug if it is executed too soon
4988 after xboard starts up. The coordinates get transformed as if
4989 the main window was positioned at (0, 0).
4991 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4993 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4994 RootWindowOfScreen(XtScreen(shellWidget)),
4995 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4999 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5002 XtSetArg(args[j], XtNheight, h); j++;
5003 XtSetArg(args[j], XtNwidth, w); j++;
5004 XtSetArg(args[j], XtNx, x); j++;
5005 XtSetArg(args[j], XtNy, y); j++;
5006 XtSetValues(shell, args, j);
5012 static int savedIndex; /* gross that this is global */
5014 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
5017 XawTextPosition index, dummy;
5020 XawTextGetSelectionPos(w, &index, &dummy);
5021 XtSetArg(arg, XtNstring, &val);
5022 XtGetValues(w, &arg, 1);
5023 ReplaceComment(savedIndex, val);
5024 if(savedIndex != currentMove) ToNrEvent(savedIndex);
5025 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
5028 void EditCommentPopUp(index, title, text)
5037 if (text == NULL) text = "";
5039 if (editShell == NULL) {
5041 CommentCreate(title, text, True, EditCommentCallback, 4);
5042 XtRealizeWidget(editShell);
5043 CatchDeleteWindow(editShell, "EditCommentPopDown");
5045 edit = XtNameToWidget(editShell, "*form.text");
5047 XtSetArg(args[j], XtNstring, text); j++;
5048 XtSetValues(edit, args, j);
5050 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5051 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5052 XtSetValues(editShell, args, j);
5055 XtPopup(editShell, XtGrabNone);
5059 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5060 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"),
5062 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"),
5066 void EditCommentCallback(w, client_data, call_data)
5068 XtPointer client_data, call_data;
5076 XtSetArg(args[j], XtNlabel, &name); j++;
5077 XtGetValues(w, args, j);
5079 if (strcmp(name, _("ok")) == 0) {
5080 edit = XtNameToWidget(editShell, "*form.text");
5082 XtSetArg(args[j], XtNstring, &val); j++;
5083 XtGetValues(edit, args, j);
5084 ReplaceComment(savedIndex, val);
5085 EditCommentPopDown();
5086 } else if (strcmp(name, _("cancel")) == 0) {
5087 EditCommentPopDown();
5088 } else if (strcmp(name, _("clear")) == 0) {
5089 edit = XtNameToWidget(editShell, "*form.text");
5090 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5091 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5095 void EditCommentPopDown()
5100 if (!editUp) return;
5102 XtSetArg(args[j], XtNx, &commentX); j++;
5103 XtSetArg(args[j], XtNy, &commentY); j++;
5104 XtSetArg(args[j], XtNheight, &commentH); j++;
5105 XtSetArg(args[j], XtNwidth, &commentW); j++;
5106 XtGetValues(editShell, args, j);
5107 XtPopdown(editShell);
5110 XtSetArg(args[j], XtNleftBitmap, None); j++;
5111 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"),
5113 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"),
5117 void ICSInputBoxPopUp()
5122 char *title = _("ICS Input");
5125 if (ICSInputShell == NULL) {
5126 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
5127 tr = XtParseTranslationTable(ICSInputTranslations);
5128 edit = XtNameToWidget(ICSInputShell, "*form.text");
5129 XtOverrideTranslations(edit, tr);
5130 XtRealizeWidget(ICSInputShell);
5131 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
5134 edit = XtNameToWidget(ICSInputShell, "*form.text");
5136 XtSetArg(args[j], XtNstring, ""); j++;
5137 XtSetValues(edit, args, j);
5139 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5140 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5141 XtSetValues(ICSInputShell, args, j);
5144 XtPopup(ICSInputShell, XtGrabNone);
5145 XtSetKeyboardFocus(ICSInputShell, edit);
5147 ICSInputBoxUp = True;
5149 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5150 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.ICS Input Box"),
5154 void ICSInputSendText()
5161 edit = XtNameToWidget(ICSInputShell, "*form.text");
5163 XtSetArg(args[j], XtNstring, &val); j++;
5164 XtGetValues(edit, args, j);
5166 SendMultiLineToICS(val);
5167 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5168 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5171 void ICSInputBoxPopDown()
5176 if (!ICSInputBoxUp) return;
5178 XtPopdown(ICSInputShell);
5179 ICSInputBoxUp = False;
5181 XtSetArg(args[j], XtNleftBitmap, None); j++;
5182 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.ICS Input Box"),
5186 void CommentPopUp(title, text)
5193 savedIndex = currentMove; // [HGM] vari
5194 if (commentShell == NULL) {
5196 CommentCreate(title, text, False, CommentCallback, 4);
5197 XtRealizeWidget(commentShell);
5198 CatchDeleteWindow(commentShell, "CommentPopDown");
5200 edit = XtNameToWidget(commentShell, "*form.text");
5202 XtSetArg(args[j], XtNstring, text); j++;
5203 XtSetValues(edit, args, j);
5205 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5206 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5207 XtSetValues(commentShell, args, j);
5210 XtPopup(commentShell, XtGrabNone);
5211 XSync(xDisplay, False);
5216 void CommentCallback(w, client_data, call_data)
5218 XtPointer client_data, call_data;
5225 XtSetArg(args[j], XtNlabel, &name); j++;
5226 XtGetValues(w, args, j);
5228 if (strcmp(name, _("close")) == 0) {
5230 } else if (strcmp(name, _("edit")) == 0) {
5237 void CommentPopDown()
5242 if (!commentUp) return;
5244 XtSetArg(args[j], XtNx, &commentX); j++;
5245 XtSetArg(args[j], XtNy, &commentY); j++;
5246 XtSetArg(args[j], XtNwidth, &commentW); j++;
5247 XtSetArg(args[j], XtNheight, &commentH); j++;
5248 XtGetValues(commentShell, args, j);
5249 XtPopdown(commentShell);
5250 XSync(xDisplay, False);
5254 void FileNamePopUp(label, def, proc, openMode)
5260 fileProc = proc; /* I can't see a way not */
5261 fileOpenMode = openMode; /* to use globals here */
5262 { // [HGM] use file-selector dialog stolen from Ghostview
5264 int index; // this is not supported yet
5266 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5267 def, openMode, NULL, &name))
5268 (void) (*fileProc)(f, index=0, name);
5272 void FileNamePopDown()
5274 if (!filenameUp) return;
5275 XtPopdown(fileNameShell);
5276 XtDestroyWidget(fileNameShell);
5281 void FileNameCallback(w, client_data, call_data)
5283 XtPointer client_data, call_data;
5288 XtSetArg(args[0], XtNlabel, &name);
5289 XtGetValues(w, args, 1);
5291 if (strcmp(name, _("cancel")) == 0) {
5296 FileNameAction(w, NULL, NULL, NULL);
5299 void FileNameAction(w, event, prms, nprms)
5311 name = XawDialogGetValueString(w = XtParent(w));
5313 if ((name != NULL) && (*name != NULLCHAR)) {
5314 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
5315 XtPopdown(w = XtParent(XtParent(w)));
5319 p = strrchr(buf, ' ');
5326 fullname = ExpandPathName(buf);
5328 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5331 f = fopen(fullname, fileOpenMode);
5333 DisplayError(_("Failed to open file"), errno);
5335 (void) (*fileProc)(f, index, buf);
5342 XtPopdown(w = XtParent(XtParent(w)));
5348 void PromotionPopUp()
5351 Widget dialog, layout;
5353 Dimension bw_width, pw_width;
5357 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5358 XtGetValues(boardWidget, args, j);
5361 XtSetArg(args[j], XtNresizable, True); j++;
5362 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5364 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5365 shellWidget, args, j);
5367 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5368 layoutArgs, XtNumber(layoutArgs));
5371 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5372 XtSetArg(args[j], XtNborderWidth, 0); j++;
5373 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5376 if(gameInfo.variant != VariantShogi) {
5377 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) {
5378 XawDialogAddButton(dialog, _("Warlord"), PromotionCallback,
5379 (XtPointer) dialog);
5380 XawDialogAddButton(dialog, _("General"), PromotionCallback,
5381 (XtPointer) dialog);
5382 XawDialogAddButton(dialog, _("Lieutenant"), PromotionCallback,
5383 (XtPointer) dialog);
5384 XawDialogAddButton(dialog, _("Captain"), PromotionCallback,
5385 (XtPointer) dialog);
5387 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5388 (XtPointer) dialog);
5389 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5390 (XtPointer) dialog);
5391 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5392 (XtPointer) dialog);
5393 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5394 (XtPointer) dialog);
5396 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5397 gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
\r
5398 gameInfo.variant == VariantGiveaway) {
5399 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5400 (XtPointer) dialog);
5402 if(gameInfo.variant == VariantCapablanca ||
5403 gameInfo.variant == VariantGothic ||
5404 gameInfo.variant == VariantCapaRandom) {
5405 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5406 (XtPointer) dialog);
5407 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5408 (XtPointer) dialog);
5410 } else // [HGM] shogi
5412 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5413 (XtPointer) dialog);
5414 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5415 (XtPointer) dialog);
5417 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5418 (XtPointer) dialog);
5420 XtRealizeWidget(promotionShell);
5421 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5424 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5425 XtGetValues(promotionShell, args, j);
5427 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5428 lineGap + squareSize/3 +
5429 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5430 0 : 6*(squareSize + lineGap)), &x, &y);
5433 XtSetArg(args[j], XtNx, x); j++;
5434 XtSetArg(args[j], XtNy, y); j++;
5435 XtSetValues(promotionShell, args, j);
5437 XtPopup(promotionShell, XtGrabNone);
5442 void PromotionPopDown()
5444 if (!promotionUp) return;
5445 XtPopdown(promotionShell);
5446 XtDestroyWidget(promotionShell);
5447 promotionUp = False;
5450 void PromotionCallback(w, client_data, call_data)
5452 XtPointer client_data, call_data;
5458 XtSetArg(args[0], XtNlabel, &name);
5459 XtGetValues(w, args, 1);
5463 if (fromX == -1) return;
5465 if (strcmp(name, _("cancel")) == 0) {
5469 } else if (strcmp(name, _("Knight")) == 0) {
5471 } else if (strcmp(name, _("Promote")) == 0) {
5473 } else if (strcmp(name, _("Defer")) == 0) {
5476 promoChar = ToLower(name[0]);
5479 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5481 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5482 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5487 void ErrorCallback(w, client_data, call_data)
5489 XtPointer client_data, call_data;
5492 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5494 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5500 if (!errorUp) return;
5502 XtPopdown(errorShell);
5503 XtDestroyWidget(errorShell);
5504 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5507 void ErrorPopUp(title, label, modal)
5508 char *title, *label;
5512 Widget dialog, layout;
5516 Dimension bw_width, pw_width;
5517 Dimension pw_height;
5521 XtSetArg(args[i], XtNresizable, True); i++;
5522 XtSetArg(args[i], XtNtitle, title); i++;
5524 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5525 shellWidget, args, i);
5527 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5528 layoutArgs, XtNumber(layoutArgs));
5531 XtSetArg(args[i], XtNlabel, label); i++;
5532 XtSetArg(args[i], XtNborderWidth, 0); i++;
5533 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5536 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5538 XtRealizeWidget(errorShell);
5539 CatchDeleteWindow(errorShell, "ErrorPopDown");
5542 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5543 XtGetValues(boardWidget, args, i);
5545 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5546 XtSetArg(args[i], XtNheight, &pw_height); i++;
5547 XtGetValues(errorShell, args, i);
5550 /* This code seems to tickle an X bug if it is executed too soon
5551 after xboard starts up. The coordinates get transformed as if
5552 the main window was positioned at (0, 0).
5554 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5555 0 - pw_height + squareSize / 3, &x, &y);
5557 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5558 RootWindowOfScreen(XtScreen(boardWidget)),
5559 (bw_width - pw_width) / 2,
5560 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5564 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5567 XtSetArg(args[i], XtNx, x); i++;
5568 XtSetArg(args[i], XtNy, y); i++;
5569 XtSetValues(errorShell, args, i);
5572 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5575 /* Disable all user input other than deleting the window */
5576 static int frozen = 0;
5580 /* Grab by a widget that doesn't accept input */
5581 XtAddGrab(messageWidget, TRUE, FALSE);
5585 /* Undo a FreezeUI */
5588 if (!frozen) return;
5589 XtRemoveGrab(messageWidget);
5593 char *ModeToWidgetName(mode)
5597 case BeginningOfGame:
5598 if (appData.icsActive)
5599 return "menuMode.ICS Client";
5600 else if (appData.noChessProgram ||
5601 *appData.cmailGameName != NULLCHAR)
5602 return "menuMode.Edit Game";
5604 return "menuMode.Machine Black";
5605 case MachinePlaysBlack:
5606 return "menuMode.Machine Black";
5607 case MachinePlaysWhite:
5608 return "menuMode.Machine White";
5610 return "menuMode.Analysis Mode";
5612 return "menuMode.Analyze File";
5613 case TwoMachinesPlay:
5614 return "menuMode.Two Machines";
5616 return "menuMode.Edit Game";
5617 case PlayFromGameFile:
5618 return "menuFile.Load Game";
5620 return "menuMode.Edit Position";
5622 return "menuMode.Training";
5623 case IcsPlayingWhite:
5624 case IcsPlayingBlack:
5628 return "menuMode.ICS Client";
5635 void ModeHighlight()
5638 static int oldPausing = FALSE;
5639 static GameMode oldmode = (GameMode) -1;
5642 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5644 if (pausing != oldPausing) {
5645 oldPausing = pausing;
5647 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5649 XtSetArg(args[0], XtNleftBitmap, None);
5651 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5654 if (appData.showButtonBar) {
5655 /* Always toggle, don't set. Previous code messes up when
5656 invoked while the button is pressed, as releasing it
5657 toggles the state again. */
5660 XtSetArg(args[0], XtNbackground, &oldbg);
5661 XtSetArg(args[1], XtNforeground, &oldfg);
5662 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5664 XtSetArg(args[0], XtNbackground, oldfg);
5665 XtSetArg(args[1], XtNforeground, oldbg);
5667 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5671 wname = ModeToWidgetName(oldmode);
5672 if (wname != NULL) {
5673 XtSetArg(args[0], XtNleftBitmap, None);
5674 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5676 wname = ModeToWidgetName(gameMode);
5677 if (wname != NULL) {
5678 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5679 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5683 /* Maybe all the enables should be handled here, not just this one */
5684 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5685 gameMode == Training || gameMode == PlayFromGameFile);
5690 * Button/menu procedures
5692 void ResetProc(w, event, prms, nprms)
5701 int LoadGamePopUp(f, gameNumber, title)
5706 cmailMsgLoaded = FALSE;
5707 if (gameNumber == 0) {
5708 int error = GameListBuild(f);
5710 DisplayError(_("Cannot build game list"), error);
5711 } else if (!ListEmpty(&gameList) &&
5712 ((ListGame *) gameList.tailPred)->number > 1) {
5713 GameListPopUp(f, title);
5719 return LoadGame(f, gameNumber, title, FALSE);
5722 void LoadGameProc(w, event, prms, nprms)
5728 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5731 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5734 void LoadNextGameProc(w, event, prms, nprms)
5743 void LoadPrevGameProc(w, event, prms, nprms)
5752 void ReloadGameProc(w, event, prms, nprms)
5761 void LoadNextPositionProc(w, event, prms, nprms)
5770 void LoadPrevPositionProc(w, event, prms, nprms)
5779 void ReloadPositionProc(w, event, prms, nprms)
5788 void LoadPositionProc(w, event, prms, nprms)
5794 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5797 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5800 void SaveGameProc(w, event, prms, nprms)
5806 FileNamePopUp(_("Save game file name?"),
5807 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5811 void SavePositionProc(w, event, prms, nprms)
5817 FileNamePopUp(_("Save position file name?"),
5818 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5822 void ReloadCmailMsgProc(w, event, prms, nprms)
5828 ReloadCmailMsgEvent(FALSE);
5831 void MailMoveProc(w, event, prms, nprms)
5840 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5841 char *selected_fen_position=NULL;
5844 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5845 Atom *type_return, XtPointer *value_return,
5846 unsigned long *length_return, int *format_return)
5848 char *selection_tmp;
5850 if (!selected_fen_position) return False; /* should never happen */
5851 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5852 /* note: since no XtSelectionDoneProc was registered, Xt will
5853 * automatically call XtFree on the value returned. So have to
5854 * make a copy of it allocated with XtMalloc */
5855 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5856 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
5858 *value_return=selection_tmp;
5859 *length_return=strlen(selection_tmp);
5860 *type_return=*target;
5861 *format_return = 8; /* bits per byte */
5863 } else if (*target == XA_TARGETS(xDisplay)) {
5864 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5865 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5866 targets_tmp[1] = XA_STRING;
5867 *value_return = targets_tmp;
5868 *type_return = XA_ATOM;
5870 *format_return = 8 * sizeof(Atom);
5871 if (*format_return > 32) {
5872 *length_return *= *format_return / 32;
5873 *format_return = 32;
5881 /* note: when called from menu all parameters are NULL, so no clue what the
5882 * Widget which was clicked on was, or what the click event was
5884 void CopyPositionProc(w, event, prms, nprms)
5891 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5892 * have a notion of a position that is selected but not copied.
5893 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5895 if(gameMode == EditPosition) EditPositionDone(TRUE);
5896 if (selected_fen_position) free(selected_fen_position);
5897 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5898 if (!selected_fen_position) return;
5899 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5901 SendPositionSelection,
5902 NULL/* lose_ownership_proc */ ,
5903 NULL/* transfer_done_proc */);
5904 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5906 SendPositionSelection,
5907 NULL/* lose_ownership_proc */ ,
5908 NULL/* transfer_done_proc */);
5911 /* function called when the data to Paste is ready */
5913 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5914 Atom *type, XtPointer value, unsigned long *len, int *format)
5917 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5918 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5919 EditPositionPasteFEN(fenstr);
5923 /* called when Paste Position button is pressed,
5924 * all parameters will be NULL */
5925 void PastePositionProc(w, event, prms, nprms)
5931 XtGetSelectionValue(menuBarWidget,
5932 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5933 /* (XtSelectionCallbackProc) */ PastePositionCB,
5934 NULL, /* client_data passed to PastePositionCB */
5936 /* better to use the time field from the event that triggered the
5937 * call to this function, but that isn't trivial to get
5945 SendGameSelection(Widget w, Atom *selection, Atom *target,
5946 Atom *type_return, XtPointer *value_return,
5947 unsigned long *length_return, int *format_return)
5949 char *selection_tmp;
5951 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5952 FILE* f = fopen(gameCopyFilename, "r");
5955 if (f == NULL) return False;
5959 selection_tmp = XtMalloc(len + 1);
5960 count = fread(selection_tmp, 1, len, f);
5963 XtFree(selection_tmp);
5966 selection_tmp[len] = NULLCHAR;
5967 *value_return = selection_tmp;
5968 *length_return = len;
5969 *type_return = *target;
5970 *format_return = 8; /* bits per byte */
5972 } else if (*target == XA_TARGETS(xDisplay)) {
5973 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5974 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5975 targets_tmp[1] = XA_STRING;
5976 *value_return = targets_tmp;
5977 *type_return = XA_ATOM;
5979 *format_return = 8 * sizeof(Atom);
5980 if (*format_return > 32) {
5981 *length_return *= *format_return / 32;
5982 *format_return = 32;
5990 /* note: when called from menu all parameters are NULL, so no clue what the
5991 * Widget which was clicked on was, or what the click event was
5993 void CopyGameProc(w, event, prms, nprms)
6001 ret = SaveGameToFile(gameCopyFilename, FALSE);
6005 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
6006 * have a notion of a game that is selected but not copied.
6007 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
6009 XtOwnSelection(menuBarWidget, XA_PRIMARY,
6012 NULL/* lose_ownership_proc */ ,
6013 NULL/* transfer_done_proc */);
6014 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
6017 NULL/* lose_ownership_proc */ ,
6018 NULL/* transfer_done_proc */);
6021 /* function called when the data to Paste is ready */
6023 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
6024 Atom *type, XtPointer value, unsigned long *len, int *format)
6027 if (value == NULL || *len == 0) {
6028 return; /* nothing had been selected to copy */
6030 f = fopen(gamePasteFilename, "w");
6032 DisplayError(_("Can't open temp file"), errno);
6035 fwrite(value, 1, *len, f);
6038 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
6041 /* called when Paste Game button is pressed,
6042 * all parameters will be NULL */
6043 void PasteGameProc(w, event, prms, nprms)
6049 XtGetSelectionValue(menuBarWidget,
6050 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
6051 /* (XtSelectionCallbackProc) */ PasteGameCB,
6052 NULL, /* client_data passed to PasteGameCB */
6054 /* better to use the time field from the event that triggered the
6055 * call to this function, but that isn't trivial to get
6065 SaveGameProc(NULL, NULL, NULL, NULL);
6069 void QuitProc(w, event, prms, nprms)
6078 void PauseProc(w, event, prms, nprms)
6088 void MachineBlackProc(w, event, prms, nprms)
6094 MachineBlackEvent();
6097 void MachineWhiteProc(w, event, prms, nprms)
6103 MachineWhiteEvent();
6106 void AnalyzeModeProc(w, event, prms, nprms)
6114 if (!first.analysisSupport) {
6115 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6116 DisplayError(buf, 0);
6119 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
6120 if (appData.icsActive) {
6121 if (gameMode != IcsObserving) {
6122 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
6123 DisplayError(buf, 0);
6125 if (appData.icsEngineAnalyze) {
6126 if (appData.debugMode)
6127 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
6133 /* if enable, use want disable icsEngineAnalyze */
6134 if (appData.icsEngineAnalyze) {
6139 appData.icsEngineAnalyze = TRUE;
6140 if (appData.debugMode)
6141 fprintf(debugFP, _("ICS engine analyze starting... \n"));
6143 if (!appData.showThinking)
6144 ShowThinkingProc(w,event,prms,nprms);
6149 void AnalyzeFileProc(w, event, prms, nprms)
6155 if (!first.analysisSupport) {
6157 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6158 DisplayError(buf, 0);
6163 if (!appData.showThinking)
6164 ShowThinkingProc(w,event,prms,nprms);
6167 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
6168 AnalysisPeriodicEvent(1);
6171 void TwoMachinesProc(w, event, prms, nprms)
6180 void IcsClientProc(w, event, prms, nprms)
6189 void EditGameProc(w, event, prms, nprms)
6198 void EditPositionProc(w, event, prms, nprms)
6204 EditPositionEvent();
6207 void TrainingProc(w, event, prms, nprms)
6216 void EditCommentProc(w, event, prms, nprms)
6223 EditCommentPopDown();
6229 void IcsInputBoxProc(w, event, prms, nprms)
6235 if (ICSInputBoxUp) {
6236 ICSInputBoxPopDown();
6242 void AcceptProc(w, event, prms, nprms)
6251 void DeclineProc(w, event, prms, nprms)
6260 void RematchProc(w, event, prms, nprms)
6269 void CallFlagProc(w, event, prms, nprms)
6278 void DrawProc(w, event, prms, nprms)
6287 void AbortProc(w, event, prms, nprms)
6296 void AdjournProc(w, event, prms, nprms)
6305 void ResignProc(w, event, prms, nprms)
6314 void AdjuWhiteProc(w, event, prms, nprms)
6320 UserAdjudicationEvent(+1);
6323 void AdjuBlackProc(w, event, prms, nprms)
6329 UserAdjudicationEvent(-1);
6332 void AdjuDrawProc(w, event, prms, nprms)
6338 UserAdjudicationEvent(0);
6341 void EnterKeyProc(w, event, prms, nprms)
6347 if (ICSInputBoxUp == True)
6351 void UpKeyProc(w, event, prms, nprms)
6356 { // [HGM] input: let up-arrow recall previous line from history
6363 if (!ICSInputBoxUp) return;
6364 edit = XtNameToWidget(ICSInputShell, "*form.text");
6366 XtSetArg(args[j], XtNstring, &val); j++;
6367 XtGetValues(edit, args, j);
6368 val = PrevInHistory(val);
6369 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6370 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6372 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6373 XawTextReplace(edit, 0, 0, &t);
6374 XawTextSetInsertionPoint(edit, 9999);
6378 void DownKeyProc(w, event, prms, nprms)
6383 { // [HGM] input: let down-arrow recall next line from history
6388 if (!ICSInputBoxUp) return;
6389 edit = XtNameToWidget(ICSInputShell, "*form.text");
6390 val = NextInHistory();
6391 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6392 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6394 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6395 XawTextReplace(edit, 0, 0, &t);
6396 XawTextSetInsertionPoint(edit, 9999);
6400 void StopObservingProc(w, event, prms, nprms)
6406 StopObservingEvent();
6409 void StopExaminingProc(w, event, prms, nprms)
6415 StopExaminingEvent();
6418 void UploadProc(w, event, prms, nprms)
6428 void ForwardProc(w, event, prms, nprms)
6438 void BackwardProc(w, event, prms, nprms)
6447 void ToStartProc(w, event, prms, nprms)
6456 void ToEndProc(w, event, prms, nprms)
6465 void RevertProc(w, event, prms, nprms)
6474 void AnnotateProc(w, event, prms, nprms)
6483 void TruncateGameProc(w, event, prms, nprms)
6489 TruncateGameEvent();
6491 void RetractMoveProc(w, event, prms, nprms)
6500 void MoveNowProc(w, event, prms, nprms)
6510 void AlwaysQueenProc(w, event, prms, nprms)
6518 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6520 if (appData.alwaysPromoteToQueen) {
6521 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6523 XtSetArg(args[0], XtNleftBitmap, None);
6525 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6529 void AnimateDraggingProc(w, event, prms, nprms)
6537 appData.animateDragging = !appData.animateDragging;
6539 if (appData.animateDragging) {
6540 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6543 XtSetArg(args[0], XtNleftBitmap, None);
6545 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6549 void AnimateMovingProc(w, event, prms, nprms)
6557 appData.animate = !appData.animate;
6559 if (appData.animate) {
6560 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6563 XtSetArg(args[0], XtNleftBitmap, None);
6565 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6569 void AutoflagProc(w, event, prms, nprms)
6577 appData.autoCallFlag = !appData.autoCallFlag;
6579 if (appData.autoCallFlag) {
6580 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6582 XtSetArg(args[0], XtNleftBitmap, None);
6584 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6588 void AutoflipProc(w, event, prms, nprms)
6596 appData.autoFlipView = !appData.autoFlipView;
6598 if (appData.autoFlipView) {
6599 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6601 XtSetArg(args[0], XtNleftBitmap, None);
6603 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6607 void BlindfoldProc(w, event, prms, nprms)
6615 appData.blindfold = !appData.blindfold;
6617 if (appData.blindfold) {
6618 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6620 XtSetArg(args[0], XtNleftBitmap, None);
6622 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6625 DrawPosition(True, NULL);
6628 void TestLegalityProc(w, event, prms, nprms)
6636 appData.testLegality = !appData.testLegality;
6638 if (appData.testLegality) {
6639 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6641 XtSetArg(args[0], XtNleftBitmap, None);
6643 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6648 void FlashMovesProc(w, event, prms, nprms)
6656 if (appData.flashCount == 0) {
6657 appData.flashCount = 3;
6659 appData.flashCount = -appData.flashCount;
6662 if (appData.flashCount > 0) {
6663 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6665 XtSetArg(args[0], XtNleftBitmap, None);
6667 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6671 void FlipViewProc(w, event, prms, nprms)
6677 flipView = !flipView;
6678 DrawPosition(True, NULL);
6682 void HighlightDraggingProc(w, event, prms, nprms)
6690 appData.highlightDragging = !appData.highlightDragging;
6692 if (appData.highlightDragging) {
6693 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6695 XtSetArg(args[0], XtNleftBitmap, None);
6697 XtSetValues(XtNameToWidget(menuBarWidget,
6698 "menuOptions.Highlight Dragging"), args, 1);
6702 void HighlightLastMoveProc(w, event, prms, nprms)
6710 appData.highlightLastMove = !appData.highlightLastMove;
6712 if (appData.highlightLastMove) {
6713 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6715 XtSetArg(args[0], XtNleftBitmap, None);
6717 XtSetValues(XtNameToWidget(menuBarWidget,
6718 "menuOptions.Highlight Last Move"), args, 1);
6721 void HighlightArrowProc(w, event, prms, nprms)
6729 appData.highlightMoveWithArrow = !appData.highlightMoveWithArrow;
6731 if (appData.highlightMoveWithArrow) {
6732 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6734 XtSetArg(args[0], XtNleftBitmap, None);
6736 XtSetValues(XtNameToWidget(menuBarWidget,
6737 "menuOptions.Arrow"), args, 1);
6741 void IcsAlarmProc(w, event, prms, nprms)
6749 appData.icsAlarm = !appData.icsAlarm;
6751 if (appData.icsAlarm) {
6752 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6754 XtSetArg(args[0], XtNleftBitmap, None);
6756 XtSetValues(XtNameToWidget(menuBarWidget,
6757 "menuOptions.ICS Alarm"), args, 1);
6761 void MoveSoundProc(w, event, prms, nprms)
6769 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6771 if (appData.ringBellAfterMoves) {
6772 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6774 XtSetArg(args[0], XtNleftBitmap, None);
6776 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6780 void OneClickProc(w, event, prms, nprms)
6788 appData.oneClick = !appData.oneClick;
6790 if (appData.oneClick) {
6791 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6793 XtSetArg(args[0], XtNleftBitmap, None);
6795 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.OneClick"),
6799 void PeriodicUpdatesProc(w, event, prms, nprms)
6807 PeriodicUpdatesEvent(!appData.periodicUpdates);
6809 if (appData.periodicUpdates) {
6810 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6812 XtSetArg(args[0], XtNleftBitmap, None);
6814 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6818 void PonderNextMoveProc(w, event, prms, nprms)
6826 PonderNextMoveEvent(!appData.ponderNextMove);
6828 if (appData.ponderNextMove) {
6829 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6831 XtSetArg(args[0], XtNleftBitmap, None);
6833 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6837 void PopupExitMessageProc(w, event, prms, nprms)
6845 appData.popupExitMessage = !appData.popupExitMessage;
6847 if (appData.popupExitMessage) {
6848 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6850 XtSetArg(args[0], XtNleftBitmap, None);
6852 XtSetValues(XtNameToWidget(menuBarWidget,
6853 "menuOptions.Popup Exit Message"), args, 1);
6856 void PopupMoveErrorsProc(w, event, prms, nprms)
6864 appData.popupMoveErrors = !appData.popupMoveErrors;
6866 if (appData.popupMoveErrors) {
6867 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6869 XtSetArg(args[0], XtNleftBitmap, None);
6871 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6876 void PremoveProc(w, event, prms, nprms)
6884 appData.premove = !appData.premove;
6886 if (appData.premove) {
6887 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6889 XtSetArg(args[0], XtNleftBitmap, None);
6891 XtSetValues(XtNameToWidget(menuBarWidget,
6892 "menuOptions.Premove"), args, 1);
6896 void ShowCoordsProc(w, event, prms, nprms)
6904 appData.showCoords = !appData.showCoords;
6906 if (appData.showCoords) {
6907 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6909 XtSetArg(args[0], XtNleftBitmap, None);
6911 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6914 DrawPosition(True, NULL);
6917 void ShowThinkingProc(w, event, prms, nprms)
6923 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6924 ShowThinkingEvent();
6927 void HideThinkingProc(w, event, prms, nprms)
6935 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6936 ShowThinkingEvent();
6938 if (appData.hideThinkingFromHuman) {
6939 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6941 XtSetArg(args[0], XtNleftBitmap, None);
6943 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6947 void SaveOnExitProc(w, event, prms, nprms)
6955 saveSettingsOnExit = !saveSettingsOnExit;
6957 if (saveSettingsOnExit) {
6958 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6960 XtSetArg(args[0], XtNleftBitmap, None);
6962 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6966 void SaveSettingsProc(w, event, prms, nprms)
6972 SaveSettings(settingsFileName);
6975 void InfoProc(w, event, prms, nprms)
6982 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6987 void ManProc(w, event, prms, nprms)
6995 if (nprms && *nprms > 0)
6999 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
7003 void HintProc(w, event, prms, nprms)
7012 void BookProc(w, event, prms, nprms)
7021 void AboutProc(w, event, prms, nprms)
7029 char *zippy = " (with Zippy code)";
7033 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
7034 programVersion, zippy,
7035 "Copyright 1991 Digital Equipment Corporation",
7036 "Enhancements Copyright 1992-2009 Free Software Foundation",
7037 "Enhancements Copyright 2005 Alessandro Scotti",
7038 PACKAGE, " is free software and carries NO WARRANTY;",
7039 "see the file COPYING for more information.");
7040 ErrorPopUp(_("About XBoard"), buf, FALSE);
7043 void DebugProc(w, event, prms, nprms)
7049 appData.debugMode = !appData.debugMode;
7052 void AboutGameProc(w, event, prms, nprms)
7061 void NothingProc(w, event, prms, nprms)
7070 void Iconify(w, event, prms, nprms)
7079 XtSetArg(args[0], XtNiconic, True);
7080 XtSetValues(shellWidget, args, 1);
7083 void DisplayMessage(message, extMessage)
7084 char *message, *extMessage;
7086 /* display a message in the message widget */
7095 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
7100 message = extMessage;
7104 /* need to test if messageWidget already exists, since this function
7105 can also be called during the startup, if for example a Xresource
7106 is not set up correctly */
7109 XtSetArg(arg, XtNlabel, message);
7110 XtSetValues(messageWidget, &arg, 1);
7116 void DisplayTitle(text)
7121 char title[MSG_SIZ];
7124 if (text == NULL) text = "";
7126 if (appData.titleInWindow) {
7128 XtSetArg(args[i], XtNlabel, text); i++;
7129 XtSetValues(titleWidget, args, i);
7132 if (*text != NULLCHAR) {
7133 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
7134 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
7135 } else if (appData.icsActive) {
7136 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7137 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7138 } else if (appData.cmailGameName[0] != NULLCHAR) {
7139 snprintf(icon, sizeof(icon), "%s", "CMail");
7140 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7142 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7143 } else if (gameInfo.variant == VariantGothic) {
7144 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7145 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
7148 } else if (gameInfo.variant == VariantFalcon) {
7149 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7150 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
7152 } else if (appData.noChessProgram) {
7153 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7154 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
7156 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
7157 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7160 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7161 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7162 XtSetValues(shellWidget, args, i);
7167 DisplayError(message, error)
7174 if (appData.debugMode || appData.matchMode) {
7175 fprintf(stderr, "%s: %s\n", programName, message);
7178 if (appData.debugMode || appData.matchMode) {
7179 fprintf(stderr, "%s: %s: %s\n",
7180 programName, message, strerror(error));
7182 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7185 ErrorPopUp(_("Error"), message, FALSE);
7189 void DisplayMoveError(message)
7194 DrawPosition(FALSE, NULL);
7195 if (appData.debugMode || appData.matchMode) {
7196 fprintf(stderr, "%s: %s\n", programName, message);
7198 if (appData.popupMoveErrors) {
7199 ErrorPopUp(_("Error"), message, FALSE);
7201 DisplayMessage(message, "");
7206 void DisplayFatalError(message, error, status)
7212 errorExitStatus = status;
7214 fprintf(stderr, "%s: %s\n", programName, message);
7216 fprintf(stderr, "%s: %s: %s\n",
7217 programName, message, strerror(error));
7218 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7221 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7222 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7228 void DisplayInformation(message)
7232 ErrorPopUp(_("Information"), message, TRUE);
7235 void DisplayNote(message)
7239 ErrorPopUp(_("Note"), message, FALSE);
7243 NullXErrorCheck(dpy, error_event)
7245 XErrorEvent *error_event;
7250 void DisplayIcsInteractionTitle(message)
7253 if (oldICSInteractionTitle == NULL) {
7254 /* Magic to find the old window title, adapted from vim */
7255 char *wina = getenv("WINDOWID");
7257 Window win = (Window) atoi(wina);
7258 Window root, parent, *children;
7259 unsigned int nchildren;
7260 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7262 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7263 if (!XQueryTree(xDisplay, win, &root, &parent,
7264 &children, &nchildren)) break;
7265 if (children) XFree((void *)children);
7266 if (parent == root || parent == 0) break;
7269 XSetErrorHandler(oldHandler);
7271 if (oldICSInteractionTitle == NULL) {
7272 oldICSInteractionTitle = "xterm";
7275 printf("\033]0;%s\007", message);
7279 char pendingReplyPrefix[MSG_SIZ];
7280 ProcRef pendingReplyPR;
7282 void AskQuestionProc(w, event, prms, nprms)
7289 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7293 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7296 void AskQuestionPopDown()
7298 if (!askQuestionUp) return;
7299 XtPopdown(askQuestionShell);
7300 XtDestroyWidget(askQuestionShell);
7301 askQuestionUp = False;
7304 void AskQuestionReplyAction(w, event, prms, nprms)
7314 reply = XawDialogGetValueString(w = XtParent(w));
7315 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
7316 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
7317 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
7318 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
7319 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7320 AskQuestionPopDown();
7322 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7325 void AskQuestionCallback(w, client_data, call_data)
7327 XtPointer client_data, call_data;
7332 XtSetArg(args[0], XtNlabel, &name);
7333 XtGetValues(w, args, 1);
7335 if (strcmp(name, _("cancel")) == 0) {
7336 AskQuestionPopDown();
7338 AskQuestionReplyAction(w, NULL, NULL, NULL);
7342 void AskQuestion(title, question, replyPrefix, pr)
7343 char *title, *question, *replyPrefix;
7347 Widget popup, layout, dialog, edit;
7353 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
7354 pendingReplyPR = pr;
7357 XtSetArg(args[i], XtNresizable, True); i++;
7358 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7359 askQuestionShell = popup =
7360 XtCreatePopupShell(title, transientShellWidgetClass,
7361 shellWidget, args, i);
7364 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7365 layoutArgs, XtNumber(layoutArgs));
7368 XtSetArg(args[i], XtNlabel, question); i++;
7369 XtSetArg(args[i], XtNvalue, ""); i++;
7370 XtSetArg(args[i], XtNborderWidth, 0); i++;
7371 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7374 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7375 (XtPointer) dialog);
7376 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7377 (XtPointer) dialog);
7379 XtRealizeWidget(popup);
7380 CatchDeleteWindow(popup, "AskQuestionPopDown");
7382 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7383 &x, &y, &win_x, &win_y, &mask);
7385 XtSetArg(args[0], XtNx, x - 10);
7386 XtSetArg(args[1], XtNy, y - 30);
7387 XtSetValues(popup, args, 2);
7389 XtPopup(popup, XtGrabExclusive);
7390 askQuestionUp = True;
7392 edit = XtNameToWidget(dialog, "*value");
7393 XtSetKeyboardFocus(popup, edit);
7401 if (*name == NULLCHAR) {
7403 } else if (strcmp(name, "$") == 0) {
7404 putc(BELLCHAR, stderr);
7407 char *prefix = "", *sep = "";
7408 if(!strchr(name, '/')) { prefix = appData.soundDirectory; sep = "/"; }
7409 snprintf(buf, sizeof(buf), "%s '%s%s%s' &", appData.soundProgram, prefix, sep, name);
7417 PlaySound(appData.soundMove);
7423 PlaySound(appData.soundIcsWin);
7429 PlaySound(appData.soundIcsLoss);
7435 PlaySound(appData.soundIcsDraw);
7439 PlayIcsUnfinishedSound()
7441 PlaySound(appData.soundIcsUnfinished);
7447 PlaySound(appData.soundIcsAlarm);
7453 system("stty echo");
7459 system("stty -echo");
7463 Colorize(cc, continuation)
7468 int count, outCount, error;
7470 if (textColors[(int)cc].bg > 0) {
7471 if (textColors[(int)cc].fg > 0) {
7472 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7473 textColors[(int)cc].fg, textColors[(int)cc].bg);
7475 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7476 textColors[(int)cc].bg);
7479 if (textColors[(int)cc].fg > 0) {
7480 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7481 textColors[(int)cc].fg);
7483 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7486 count = strlen(buf);
7487 outCount = OutputToProcess(NoProc, buf, count, &error);
7488 if (outCount < count) {
7489 DisplayFatalError(_("Error writing to display"), error, 1);
7492 if (continuation) return;
7495 PlaySound(appData.soundShout);
7498 PlaySound(appData.soundSShout);
7501 PlaySound(appData.soundChannel1);
7504 PlaySound(appData.soundChannel);
7507 PlaySound(appData.soundKibitz);
7510 PlaySound(appData.soundTell);
7512 case ColorChallenge:
7513 PlaySound(appData.soundChallenge);
7516 PlaySound(appData.soundRequest);
7519 PlaySound(appData.soundSeek);
7530 return getpwuid(getuid())->pw_name;
7534 ExpandPathName(path)
7537 static char static_buf[4*MSG_SIZ];
7538 char *d, *s, buf[4*MSG_SIZ];
7544 while (*s && isspace(*s))
7553 if (*(s+1) == '/') {
7554 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7558 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7559 { char *p; if(p = strchr(buf, '/')) *p = 0; }
7560 pwd = getpwnam(buf);
7563 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7567 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7568 strcat(d, strchr(s+1, '/'));
7572 safeStrCpy(d, s, 4*MSG_SIZ );
7579 static char host_name[MSG_SIZ];
7581 #if HAVE_GETHOSTNAME
7582 gethostname(host_name, MSG_SIZ);
7584 #else /* not HAVE_GETHOSTNAME */
7585 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7586 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7588 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7590 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7591 #endif /* not HAVE_GETHOSTNAME */
7594 XtIntervalId delayedEventTimerXID = 0;
7595 DelayedEventCallback delayedEventCallback = 0;
7600 delayedEventTimerXID = 0;
7601 delayedEventCallback();
7605 ScheduleDelayedEvent(cb, millisec)
7606 DelayedEventCallback cb; long millisec;
7608 if(delayedEventTimerXID && delayedEventCallback == cb)
7609 // [HGM] alive: replace, rather than add or flush identical event
7610 XtRemoveTimeOut(delayedEventTimerXID);
7611 delayedEventCallback = cb;
7612 delayedEventTimerXID =
7613 XtAppAddTimeOut(appContext, millisec,
7614 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7617 DelayedEventCallback
7620 if (delayedEventTimerXID) {
7621 return delayedEventCallback;
7628 CancelDelayedEvent()
7630 if (delayedEventTimerXID) {
7631 XtRemoveTimeOut(delayedEventTimerXID);
7632 delayedEventTimerXID = 0;
7636 XtIntervalId loadGameTimerXID = 0;
7638 int LoadGameTimerRunning()
7640 return loadGameTimerXID != 0;
7643 int StopLoadGameTimer()
7645 if (loadGameTimerXID != 0) {
7646 XtRemoveTimeOut(loadGameTimerXID);
7647 loadGameTimerXID = 0;
7655 LoadGameTimerCallback(arg, id)
7659 loadGameTimerXID = 0;
7664 StartLoadGameTimer(millisec)
7668 XtAppAddTimeOut(appContext, millisec,
7669 (XtTimerCallbackProc) LoadGameTimerCallback,
7673 XtIntervalId analysisClockXID = 0;
7676 AnalysisClockCallback(arg, id)
7680 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7681 || appData.icsEngineAnalyze) { // [DM]
7682 AnalysisPeriodicEvent(0);
7683 StartAnalysisClock();
7688 StartAnalysisClock()
7691 XtAppAddTimeOut(appContext, 2000,
7692 (XtTimerCallbackProc) AnalysisClockCallback,
7696 XtIntervalId clockTimerXID = 0;
7698 int ClockTimerRunning()
7700 return clockTimerXID != 0;
7703 int StopClockTimer()
7705 if (clockTimerXID != 0) {
7706 XtRemoveTimeOut(clockTimerXID);
7715 ClockTimerCallback(arg, id)
7724 StartClockTimer(millisec)
7728 XtAppAddTimeOut(appContext, millisec,
7729 (XtTimerCallbackProc) ClockTimerCallback,
7734 DisplayTimerLabel(w, color, timer, highlight)
7743 /* check for low time warning */
7744 Pixel foregroundOrWarningColor = timerForegroundPixel;
7747 appData.lowTimeWarning &&
7748 (timer / 1000) < appData.icsAlarmTime)
7749 foregroundOrWarningColor = lowTimeWarningColor;
7751 if (appData.clockMode) {
7752 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7753 XtSetArg(args[0], XtNlabel, buf);
7755 snprintf(buf, MSG_SIZ, "%s ", color);
7756 XtSetArg(args[0], XtNlabel, buf);
7761 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7762 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7764 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7765 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7768 XtSetValues(w, args, 3);
7772 DisplayWhiteClock(timeRemaining, highlight)
7778 if(appData.noGUI) return;
7779 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7780 if (highlight && iconPixmap == bIconPixmap) {
7781 iconPixmap = wIconPixmap;
7782 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7783 XtSetValues(shellWidget, args, 1);
7788 DisplayBlackClock(timeRemaining, highlight)
7794 if(appData.noGUI) return;
7795 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7796 if (highlight && iconPixmap == wIconPixmap) {
7797 iconPixmap = bIconPixmap;
7798 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7799 XtSetValues(shellWidget, args, 1);
7817 int StartChildProcess(cmdLine, dir, pr)
7824 int to_prog[2], from_prog[2];
7828 if (appData.debugMode) {
7829 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7832 /* We do NOT feed the cmdLine to the shell; we just
7833 parse it into blank-separated arguments in the
7834 most simple-minded way possible.
7837 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7840 while(*p == ' ') p++;
7842 if(*p == '"' || *p == '\'')
7843 p = strchr(++argv[i-1], *p);
7844 else p = strchr(p, ' ');
7845 if (p == NULL) break;
7850 SetUpChildIO(to_prog, from_prog);
7852 if ((pid = fork()) == 0) {
7854 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7855 close(to_prog[1]); // first close the unused pipe ends
7856 close(from_prog[0]);
7857 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7858 dup2(from_prog[1], 1);
7859 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7860 close(from_prog[1]); // and closing again loses one of the pipes!
7861 if(fileno(stderr) >= 2) // better safe than sorry...
7862 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7864 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7869 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7871 execvp(argv[0], argv);
7873 /* If we get here, exec failed */
7878 /* Parent process */
7880 close(from_prog[1]);
7882 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7885 cp->fdFrom = from_prog[0];
7886 cp->fdTo = to_prog[1];
7891 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7892 static RETSIGTYPE AlarmCallBack(int n)
7898 DestroyChildProcess(pr, signalType)
7902 ChildProc *cp = (ChildProc *) pr;
7904 if (cp->kind != CPReal) return;
7906 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7907 signal(SIGALRM, AlarmCallBack);
7909 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7910 kill(cp->pid, SIGKILL); // kill it forcefully
7911 wait((int *) 0); // and wait again
7915 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7917 /* Process is exiting either because of the kill or because of
7918 a quit command sent by the backend; either way, wait for it to die.
7927 InterruptChildProcess(pr)
7930 ChildProc *cp = (ChildProc *) pr;
7932 if (cp->kind != CPReal) return;
7933 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7936 int OpenTelnet(host, port, pr)
7941 char cmdLine[MSG_SIZ];
7943 if (port[0] == NULLCHAR) {
7944 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7946 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7948 return StartChildProcess(cmdLine, "", pr);
7951 int OpenTCP(host, port, pr)
7957 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7958 #else /* !OMIT_SOCKETS */
7960 struct sockaddr_in sa;
7962 unsigned short uport;
7965 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7969 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7970 sa.sin_family = AF_INET;
7971 sa.sin_addr.s_addr = INADDR_ANY;
7972 uport = (unsigned short) 0;
7973 sa.sin_port = htons(uport);
7974 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7978 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7979 if (!(hp = gethostbyname(host))) {
7981 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7982 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7983 hp->h_addrtype = AF_INET;
7985 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7986 hp->h_addr_list[0] = (char *) malloc(4);
7987 hp->h_addr_list[0][0] = b0;
7988 hp->h_addr_list[0][1] = b1;
7989 hp->h_addr_list[0][2] = b2;
7990 hp->h_addr_list[0][3] = b3;
7995 sa.sin_family = hp->h_addrtype;
7996 uport = (unsigned short) atoi(port);
7997 sa.sin_port = htons(uport);
7998 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
8000 if (connect(s, (struct sockaddr *) &sa,
8001 sizeof(struct sockaddr_in)) < 0) {
8005 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8012 #endif /* !OMIT_SOCKETS */
8017 int OpenCommPort(name, pr)
8024 fd = open(name, 2, 0);
8025 if (fd < 0) return errno;
8027 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8037 int OpenLoopback(pr)
8043 SetUpChildIO(to, from);
8045 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8048 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
8055 int OpenRcmd(host, user, cmd, pr)
8056 char *host, *user, *cmd;
8059 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
8063 #define INPUT_SOURCE_BUF_SIZE 8192
8072 char buf[INPUT_SOURCE_BUF_SIZE];
8077 DoInputCallback(closure, source, xid)
8082 InputSource *is = (InputSource *) closure;
8087 if (is->lineByLine) {
8088 count = read(is->fd, is->unused,
8089 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
8091 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
8094 is->unused += count;
8096 while (p < is->unused) {
8097 q = memchr(p, '\n', is->unused - p);
8098 if (q == NULL) break;
8100 (is->func)(is, is->closure, p, q - p, 0);
8104 while (p < is->unused) {
8109 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8114 (is->func)(is, is->closure, is->buf, count, error);
8118 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8125 ChildProc *cp = (ChildProc *) pr;
8127 is = (InputSource *) calloc(1, sizeof(InputSource));
8128 is->lineByLine = lineByLine;
8132 is->fd = fileno(stdin);
8134 is->kind = cp->kind;
8135 is->fd = cp->fdFrom;
8138 is->unused = is->buf;
8141 is->xid = XtAppAddInput(appContext, is->fd,
8142 (XtPointer) (XtInputReadMask),
8143 (XtInputCallbackProc) DoInputCallback,
8145 is->closure = closure;
8146 return (InputSourceRef) is;
8150 RemoveInputSource(isr)
8153 InputSource *is = (InputSource *) isr;
8155 if (is->xid == 0) return;
8156 XtRemoveInput(is->xid);
8160 int OutputToProcess(pr, message, count, outError)
8166 static int line = 0;
8167 ChildProc *cp = (ChildProc *) pr;
8172 if (appData.noJoin || !appData.useInternalWrap)
8173 outCount = fwrite(message, 1, count, stdout);
8176 int width = get_term_width();
8177 int len = wrap(NULL, message, count, width, &line);
8178 char *msg = malloc(len);
8182 outCount = fwrite(message, 1, count, stdout);
8185 dbgchk = wrap(msg, message, count, width, &line);
8186 if (dbgchk != len && appData.debugMode)
8187 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8188 outCount = fwrite(msg, 1, dbgchk, stdout);
8194 outCount = write(cp->fdTo, message, count);
8204 /* Output message to process, with "ms" milliseconds of delay
8205 between each character. This is needed when sending the logon
8206 script to ICC, which for some reason doesn't like the
8207 instantaneous send. */
8208 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8215 ChildProc *cp = (ChildProc *) pr;
8220 r = write(cp->fdTo, message++, 1);
8233 /**** Animation code by Hugh Fisher, DCS, ANU.
8235 Known problem: if a window overlapping the board is
8236 moved away while a piece is being animated underneath,
8237 the newly exposed area won't be updated properly.
8238 I can live with this.
8240 Known problem: if you look carefully at the animation
8241 of pieces in mono mode, they are being drawn as solid
8242 shapes without interior detail while moving. Fixing
8243 this would be a major complication for minimal return.
8246 /* Masks for XPM pieces. Black and white pieces can have
8247 different shapes, but in the interest of retaining my
8248 sanity pieces must have the same outline on both light
8249 and dark squares, and all pieces must use the same
8250 background square colors/images. */
8252 static int xpmDone = 0;
8255 CreateAnimMasks (pieceDepth)
8262 unsigned long plane;
8265 /* Need a bitmap just to get a GC with right depth */
8266 buf = XCreatePixmap(xDisplay, xBoardWindow,
8268 values.foreground = 1;
8269 values.background = 0;
8270 /* Don't use XtGetGC, not read only */
8271 maskGC = XCreateGC(xDisplay, buf,
8272 GCForeground | GCBackground, &values);
8273 XFreePixmap(xDisplay, buf);
8275 buf = XCreatePixmap(xDisplay, xBoardWindow,
8276 squareSize, squareSize, pieceDepth);
8277 values.foreground = XBlackPixel(xDisplay, xScreen);
8278 values.background = XWhitePixel(xDisplay, xScreen);
8279 bufGC = XCreateGC(xDisplay, buf,
8280 GCForeground | GCBackground, &values);
8282 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8283 /* Begin with empty mask */
8284 if(!xpmDone) // [HGM] pieces: keep using existing
8285 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8286 squareSize, squareSize, 1);
8287 XSetFunction(xDisplay, maskGC, GXclear);
8288 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8289 0, 0, squareSize, squareSize);
8291 /* Take a copy of the piece */
8296 XSetFunction(xDisplay, bufGC, GXcopy);
8297 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8299 0, 0, squareSize, squareSize, 0, 0);
8301 /* XOR the background (light) over the piece */
8302 XSetFunction(xDisplay, bufGC, GXxor);
8304 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8305 0, 0, squareSize, squareSize, 0, 0);
8307 XSetForeground(xDisplay, bufGC, lightSquareColor);
8308 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8311 /* We now have an inverted piece image with the background
8312 erased. Construct mask by just selecting all the non-zero
8313 pixels - no need to reconstruct the original image. */
8314 XSetFunction(xDisplay, maskGC, GXor);
8316 /* Might be quicker to download an XImage and create bitmap
8317 data from it rather than this N copies per piece, but it
8318 only takes a fraction of a second and there is a much
8319 longer delay for loading the pieces. */
8320 for (n = 0; n < pieceDepth; n ++) {
8321 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8322 0, 0, squareSize, squareSize,
8328 XFreePixmap(xDisplay, buf);
8329 XFreeGC(xDisplay, bufGC);
8330 XFreeGC(xDisplay, maskGC);
8334 InitAnimState (anim, info)
8336 XWindowAttributes * info;
8341 /* Each buffer is square size, same depth as window */
8342 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8343 squareSize, squareSize, info->depth);
8344 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8345 squareSize, squareSize, info->depth);
8347 /* Create a plain GC for blitting */
8348 mask = GCForeground | GCBackground | GCFunction |
8349 GCPlaneMask | GCGraphicsExposures;
8350 values.foreground = XBlackPixel(xDisplay, xScreen);
8351 values.background = XWhitePixel(xDisplay, xScreen);
8352 values.function = GXcopy;
8353 values.plane_mask = AllPlanes;
8354 values.graphics_exposures = False;
8355 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8357 /* Piece will be copied from an existing context at
8358 the start of each new animation/drag. */
8359 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8361 /* Outline will be a read-only copy of an existing */
8362 anim->outlineGC = None;
8368 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8369 XWindowAttributes info;
8371 if (xpmDone && gameInfo.variant == old) return;
8372 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8373 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8375 InitAnimState(&game, &info);
8376 InitAnimState(&player, &info);
8378 /* For XPM pieces, we need bitmaps to use as masks. */
8380 CreateAnimMasks(info.depth);
8386 static Boolean frameWaiting;
8388 static RETSIGTYPE FrameAlarm (sig)
8391 frameWaiting = False;
8392 /* In case System-V style signals. Needed?? */
8393 signal(SIGALRM, FrameAlarm);
8400 struct itimerval delay;
8402 XSync(xDisplay, False);
8405 frameWaiting = True;
8406 signal(SIGALRM, FrameAlarm);
8407 delay.it_interval.tv_sec =
8408 delay.it_value.tv_sec = time / 1000;
8409 delay.it_interval.tv_usec =
8410 delay.it_value.tv_usec = (time % 1000) * 1000;
8411 setitimer(ITIMER_REAL, &delay, NULL);
8412 while (frameWaiting) pause();
8413 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8414 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8415 setitimer(ITIMER_REAL, &delay, NULL);
8425 XSync(xDisplay, False);
8427 usleep(time * 1000);
8432 /* Convert board position to corner of screen rect and color */
8435 ScreenSquare(column, row, pt, color)
8436 int column; int row; XPoint * pt; int * color;
8439 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8440 pt->y = lineGap + row * (squareSize + lineGap);
8442 pt->x = lineGap + column * (squareSize + lineGap);
8443 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8445 *color = SquareColor(row, column);
8448 /* Convert window coords to square */
8451 BoardSquare(x, y, column, row)
8452 int x; int y; int * column; int * row;
8454 *column = EventToSquare(x, BOARD_WIDTH);
8455 if (flipView && *column >= 0)
8456 *column = BOARD_WIDTH - 1 - *column;
8457 *row = EventToSquare(y, BOARD_HEIGHT);
8458 if (!flipView && *row >= 0)
8459 *row = BOARD_HEIGHT - 1 - *row;
8464 #undef Max /* just in case */
8466 #define Max(a, b) ((a) > (b) ? (a) : (b))
8467 #define Min(a, b) ((a) < (b) ? (a) : (b))
8470 SetRect(rect, x, y, width, height)
8471 XRectangle * rect; int x; int y; int width; int height;
8475 rect->width = width;
8476 rect->height = height;
8479 /* Test if two frames overlap. If they do, return
8480 intersection rect within old and location of
8481 that rect within new. */
8484 Intersect(old, new, size, area, pt)
8485 XPoint * old; XPoint * new;
8486 int size; XRectangle * area; XPoint * pt;
8488 if (old->x > new->x + size || new->x > old->x + size ||
8489 old->y > new->y + size || new->y > old->y + size) {
8492 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8493 size - abs(old->x - new->x), size - abs(old->y - new->y));
8494 pt->x = Max(old->x - new->x, 0);
8495 pt->y = Max(old->y - new->y, 0);
8500 /* For two overlapping frames, return the rect(s)
8501 in the old that do not intersect with the new. */
8504 CalcUpdateRects(old, new, size, update, nUpdates)
8505 XPoint * old; XPoint * new; int size;
8506 XRectangle update[]; int * nUpdates;
8510 /* If old = new (shouldn't happen) then nothing to draw */
8511 if (old->x == new->x && old->y == new->y) {
8515 /* Work out what bits overlap. Since we know the rects
8516 are the same size we don't need a full intersect calc. */
8518 /* Top or bottom edge? */
8519 if (new->y > old->y) {
8520 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8522 } else if (old->y > new->y) {
8523 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8524 size, old->y - new->y);
8527 /* Left or right edge - don't overlap any update calculated above. */
8528 if (new->x > old->x) {
8529 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8530 new->x - old->x, size - abs(new->y - old->y));
8532 } else if (old->x > new->x) {
8533 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8534 old->x - new->x, size - abs(new->y - old->y));
8541 /* Generate a series of frame coords from start->mid->finish.
8542 The movement rate doubles until the half way point is
8543 reached, then halves back down to the final destination,
8544 which gives a nice slow in/out effect. The algorithmn
8545 may seem to generate too many intermediates for short
8546 moves, but remember that the purpose is to attract the
8547 viewers attention to the piece about to be moved and
8548 then to where it ends up. Too few frames would be less
8552 Tween(start, mid, finish, factor, frames, nFrames)
8553 XPoint * start; XPoint * mid;
8554 XPoint * finish; int factor;
8555 XPoint frames[]; int * nFrames;
8557 int fraction, n, count;
8561 /* Slow in, stepping 1/16th, then 1/8th, ... */
8563 for (n = 0; n < factor; n++)
8565 for (n = 0; n < factor; n++) {
8566 frames[count].x = start->x + (mid->x - start->x) / fraction;
8567 frames[count].y = start->y + (mid->y - start->y) / fraction;
8569 fraction = fraction / 2;
8573 frames[count] = *mid;
8576 /* Slow out, stepping 1/2, then 1/4, ... */
8578 for (n = 0; n < factor; n++) {
8579 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8580 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8582 fraction = fraction * 2;
8587 /* Draw a piece on the screen without disturbing what's there */
8590 SelectGCMask(piece, clip, outline, mask)
8591 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8595 /* Bitmap for piece being moved. */
8596 if (appData.monoMode) {
8597 *mask = *pieceToSolid(piece);
8598 } else if (useImages) {
8600 *mask = xpmMask[piece];
8602 *mask = ximMaskPm[piece];
8605 *mask = *pieceToSolid(piece);
8608 /* GC for piece being moved. Square color doesn't matter, but
8609 since it gets modified we make a copy of the original. */
8611 if (appData.monoMode)
8616 if (appData.monoMode)
8621 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8623 /* Outline only used in mono mode and is not modified */
8625 *outline = bwPieceGC;
8627 *outline = wbPieceGC;
8631 OverlayPiece(piece, clip, outline, dest)
8632 ChessSquare piece; GC clip; GC outline; Drawable dest;
8637 /* Draw solid rectangle which will be clipped to shape of piece */
8638 XFillRectangle(xDisplay, dest, clip,
8639 0, 0, squareSize, squareSize);
8640 if (appData.monoMode)
8641 /* Also draw outline in contrasting color for black
8642 on black / white on white cases */
8643 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8644 0, 0, squareSize, squareSize, 0, 0, 1);
8646 /* Copy the piece */
8651 if(appData.upsideDown && flipView) kind ^= 2;
8652 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8654 0, 0, squareSize, squareSize,
8659 /* Animate the movement of a single piece */
8662 BeginAnimation(anim, piece, startColor, start)
8670 if(appData.upsideDown && flipView) piece += piece < BlackPawn ? BlackPawn : -BlackPawn;
8671 /* The old buffer is initialised with the start square (empty) */
8672 BlankSquare(start->x, start->y, startColor, EmptySquare, anim->saveBuf, 0);
8673 anim->prevFrame = *start;
8675 /* The piece will be drawn using its own bitmap as a matte */
8676 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8677 XSetClipMask(xDisplay, anim->pieceGC, mask);
8681 AnimationFrame(anim, frame, piece)
8686 XRectangle updates[4];
8691 /* Save what we are about to draw into the new buffer */
8692 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8693 frame->x, frame->y, squareSize, squareSize,
8696 /* Erase bits of the previous frame */
8697 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8698 /* Where the new frame overlapped the previous,
8699 the contents in newBuf are wrong. */
8700 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8701 overlap.x, overlap.y,
8702 overlap.width, overlap.height,
8704 /* Repaint the areas in the old that don't overlap new */
8705 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8706 for (i = 0; i < count; i++)
8707 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8708 updates[i].x - anim->prevFrame.x,
8709 updates[i].y - anim->prevFrame.y,
8710 updates[i].width, updates[i].height,
8711 updates[i].x, updates[i].y);
8713 /* Easy when no overlap */
8714 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8715 0, 0, squareSize, squareSize,
8716 anim->prevFrame.x, anim->prevFrame.y);
8719 /* Save this frame for next time round */
8720 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8721 0, 0, squareSize, squareSize,
8723 anim->prevFrame = *frame;
8725 /* Draw piece over original screen contents, not current,
8726 and copy entire rect. Wipes out overlapping piece images. */
8727 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8728 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8729 0, 0, squareSize, squareSize,
8730 frame->x, frame->y);
8734 EndAnimation (anim, finish)
8738 XRectangle updates[4];
8743 /* The main code will redraw the final square, so we
8744 only need to erase the bits that don't overlap. */
8745 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8746 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8747 for (i = 0; i < count; i++)
8748 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8749 updates[i].x - anim->prevFrame.x,
8750 updates[i].y - anim->prevFrame.y,
8751 updates[i].width, updates[i].height,
8752 updates[i].x, updates[i].y);
8754 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8755 0, 0, squareSize, squareSize,
8756 anim->prevFrame.x, anim->prevFrame.y);
8761 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8763 ChessSquare piece; int startColor;
8764 XPoint * start; XPoint * finish;
8765 XPoint frames[]; int nFrames;
8769 BeginAnimation(anim, piece, startColor, start);
8770 for (n = 0; n < nFrames; n++) {
8771 AnimationFrame(anim, &(frames[n]), piece);
8772 FrameDelay(appData.animSpeed);
8774 EndAnimation(anim, finish);
8778 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
8781 ChessSquare piece = board[fromY][toY];
8782 board[fromY][toY] = EmptySquare;
8783 DrawPosition(FALSE, board);
8785 x = lineGap + ((BOARD_WIDTH-1)-toX) * (squareSize + lineGap);
8786 y = lineGap + toY * (squareSize + lineGap);
8788 x = lineGap + toX * (squareSize + lineGap);
8789 y = lineGap + ((BOARD_HEIGHT-1)-toY) * (squareSize + lineGap);
8791 for(i=1; i<4*kFactor; i++) {
8792 int r = squareSize * 9 * i/(20*kFactor - 5);
8793 XFillArc(xDisplay, xBoardWindow, highlineGC,
8794 x + squareSize/2 - r, y+squareSize/2 - r, 2*r, 2*r, 0, 64*360);
8795 FrameDelay(appData.animSpeed);
8797 board[fromY][toY] = piece;
8800 /* Main control logic for deciding what to animate and how */
8803 AnimateMove(board, fromX, fromY, toX, toY)
8812 XPoint start, finish, mid;
8813 XPoint frames[kFactor * 2 + 1];
8814 int nFrames, startColor, endColor;
8816 /* Are we animating? */
8817 if (!appData.animate || appData.blindfold)
8820 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8821 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8822 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8824 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8825 piece = board[fromY][fromX];
8826 if (piece >= EmptySquare) return;
8831 hop = abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1;
8834 if (appData.debugMode) {
8835 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8836 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8837 piece, fromX, fromY, toX, toY); }
8839 ScreenSquare(fromX, fromY, &start, &startColor);
8840 ScreenSquare(toX, toY, &finish, &endColor);
8843 /* Knight: make straight movement then diagonal */
8844 if (abs(toY - fromY) < abs(toX - fromX)) {
8845 mid.x = start.x + (finish.x - start.x) / 2;
8849 mid.y = start.y + (finish.y - start.y) / 2;
8852 mid.x = start.x + (finish.x - start.x) / 2;
8853 mid.y = start.y + (finish.y - start.y) / 2;
8856 /* Don't use as many frames for very short moves */
8857 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8858 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8860 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8861 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8862 if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged
8864 for(i=0; i<BOARD_WIDTH; i++) for(j=0; j<BOARD_HEIGHT; j++)
8865 if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] = True;
8868 /* Be sure end square is redrawn */
8869 damage[0][toY][toX] = True;
8873 DragPieceBegin(x, y)
8876 int boardX, boardY, color;
8879 /* Are we animating? */
8880 if (!appData.animateDragging || appData.blindfold)
8883 /* Figure out which square we start in and the
8884 mouse position relative to top left corner. */
8885 BoardSquare(x, y, &boardX, &boardY);
8886 player.startBoardX = boardX;
8887 player.startBoardY = boardY;
8888 ScreenSquare(boardX, boardY, &corner, &color);
8889 player.startSquare = corner;
8890 player.startColor = color;
8891 /* As soon as we start dragging, the piece will jump slightly to
8892 be centered over the mouse pointer. */
8893 player.mouseDelta.x = squareSize/2;
8894 player.mouseDelta.y = squareSize/2;
8895 /* Initialise animation */
8896 player.dragPiece = PieceForSquare(boardX, boardY);
8898 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8899 player.dragActive = True;
8900 BeginAnimation(&player, player.dragPiece, color, &corner);
8901 /* Mark this square as needing to be redrawn. Note that
8902 we don't remove the piece though, since logically (ie
8903 as seen by opponent) the move hasn't been made yet. */
8904 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8905 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8906 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8907 corner.x, corner.y, squareSize, squareSize,
8908 0, 0); // [HGM] zh: unstack in stead of grab
8909 if(gatingPiece != EmptySquare) {
8910 /* Kludge alert: When gating we want the introduced
8911 piece to appear on the from square. To generate an
8912 image of it, we draw it on the board, copy the image,
8913 and draw the original piece again. */
8914 ChessSquare piece = boards[currentMove][boardY][boardX];
8915 DrawSquare(boardY, boardX, gatingPiece, 0);
8916 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8917 corner.x, corner.y, squareSize, squareSize, 0, 0);
8918 DrawSquare(boardY, boardX, piece, 0);
8920 damage[0][boardY][boardX] = True;
8922 player.dragActive = False;
8932 /* Are we animating? */
8933 if (!appData.animateDragging || appData.blindfold)
8937 if (! player.dragActive)
8939 /* Move piece, maintaining same relative position
8940 of mouse within square */
8941 corner.x = x - player.mouseDelta.x;
8942 corner.y = y - player.mouseDelta.y;
8943 AnimationFrame(&player, &corner, player.dragPiece);
8945 if (appData.highlightDragging) {
8947 BoardSquare(x, y, &boardX, &boardY);
8948 SetHighlights(fromX, fromY, boardX, boardY);
8957 int boardX, boardY, color;
8960 /* Are we animating? */
8961 if (!appData.animateDragging || appData.blindfold)
8965 if (! player.dragActive)
8967 /* Last frame in sequence is square piece is
8968 placed on, which may not match mouse exactly. */
8969 BoardSquare(x, y, &boardX, &boardY);
8970 ScreenSquare(boardX, boardY, &corner, &color);
8971 EndAnimation(&player, &corner);
8973 /* Be sure end square is redrawn */
8974 damage[0][boardY][boardX] = True;
8976 /* This prevents weird things happening with fast successive
8977 clicks which on my Sun at least can cause motion events
8978 without corresponding press/release. */
8979 player.dragActive = False;
8982 /* Handle expose event while piece being dragged */
8987 if (!player.dragActive || appData.blindfold)
8990 /* What we're doing: logically, the move hasn't been made yet,
8991 so the piece is still in it's original square. But visually
8992 it's being dragged around the board. So we erase the square
8993 that the piece is on and draw it at the last known drag point. */
8994 BlankSquare(player.startSquare.x, player.startSquare.y,
8995 player.startColor, EmptySquare, xBoardWindow, 1);
8996 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8997 damage[0][player.startBoardY][player.startBoardX] = TRUE;
9000 #include <sys/ioctl.h>
9001 int get_term_width()
9003 int fd, default_width;
9006 default_width = 79; // this is FICS default anyway...
9008 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
9010 if (!ioctl(fd, TIOCGSIZE, &win))
9011 default_width = win.ts_cols;
9012 #elif defined(TIOCGWINSZ)
9014 if (!ioctl(fd, TIOCGWINSZ, &win))
9015 default_width = win.ws_col;
9017 return default_width;
9023 static int old_width = 0;
9024 int new_width = get_term_width();
9026 if (old_width != new_width)
9027 ics_printf("set width %d\n", new_width);
9028 old_width = new_width;
9031 void NotifyFrontendLogin()
9036 /* [AS] Arrow highlighting support */
9038 static double A_WIDTH = 5; /* Width of arrow body */
9040 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
9041 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
9043 static double Sqr( double x )
9048 static int Round( double x )
9050 return (int) (x + 0.5);
9053 void SquareToPos(int rank, int file, int *x, int *y)
9056 *x = lineGap + ((BOARD_WIDTH-1)-file) * (squareSize + lineGap);
9057 *y = lineGap + rank * (squareSize + lineGap);
9059 *x = lineGap + file * (squareSize + lineGap);
9060 *y = lineGap + ((BOARD_HEIGHT-1)-rank) * (squareSize + lineGap);
9064 /* Draw an arrow between two points using current settings */
9065 void DrawArrowBetweenPoints( int s_x, int s_y, int d_x, int d_y )
9068 double dx, dy, j, k, x, y;
9071 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
9073 arrow[0].x = s_x + A_WIDTH + 0.5;
9076 arrow[1].x = s_x + A_WIDTH + 0.5;
9077 arrow[1].y = d_y - h;
9079 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9080 arrow[2].y = d_y - h;
9085 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
9086 arrow[5].y = d_y - h;
9088 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9089 arrow[4].y = d_y - h;
9091 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
9094 else if( d_y == s_y ) {
9095 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
9098 arrow[0].y = s_y + A_WIDTH + 0.5;
9100 arrow[1].x = d_x - w;
9101 arrow[1].y = s_y + A_WIDTH + 0.5;
9103 arrow[2].x = d_x - w;
9104 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9109 arrow[5].x = d_x - w;
9110 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
9112 arrow[4].x = d_x - w;
9113 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9116 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
9119 /* [AS] Needed a lot of paper for this! :-) */
9120 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
9121 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
9123 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
9125 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
9130 arrow[0].x = Round(x - j);
9131 arrow[0].y = Round(y + j*dx);
9133 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
9134 arrow[1].y = Round(arrow[0].y - 2*j*dx);
9137 x = (double) d_x - k;
9138 y = (double) d_y - k*dy;
9141 x = (double) d_x + k;
9142 y = (double) d_y + k*dy;
9145 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
9147 arrow[6].x = Round(x - j);
9148 arrow[6].y = Round(y + j*dx);
9150 arrow[2].x = Round(arrow[6].x + 2*j);
9151 arrow[2].y = Round(arrow[6].y - 2*j*dx);
9153 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
9154 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
9159 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
9160 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
9163 XFillPolygon(xDisplay, xBoardWindow, highlineGC, arrow, 7, Nonconvex, CoordModeOrigin);
9164 // Polygon( hdc, arrow, 7 );
9167 /* [AS] Draw an arrow between two squares */
9168 void DrawArrowBetweenSquares( int s_col, int s_row, int d_col, int d_row )
9170 int s_x, s_y, d_x, d_y, hor, vert, i;
9172 if( s_col == d_col && s_row == d_row ) {
9176 /* Get source and destination points */
9177 SquareToPos( s_row, s_col, &s_x, &s_y);
9178 SquareToPos( d_row, d_col, &d_x, &d_y);
9181 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
9183 else if( d_y < s_y ) {
9184 d_y += squareSize / 2 + squareSize / 4;
9187 d_y += squareSize / 2;
9191 d_x += squareSize / 2 - squareSize / 4;
9193 else if( d_x < s_x ) {
9194 d_x += squareSize / 2 + squareSize / 4;
9197 d_x += squareSize / 2;
9200 s_x += squareSize / 2;
9201 s_y += squareSize / 2;
9204 A_WIDTH = squareSize / 14.; //[HGM] make float
9206 DrawArrowBetweenPoints( s_x, s_y, d_x, d_y );
9208 hor = 64*s_col + 32; vert = 64*s_row + 32;
9209 for(i=0; i<= 64; i++) {
9210 damage[0][vert+6>>6][hor+6>>6] = True;
9211 damage[0][vert-6>>6][hor+6>>6] = True;
9212 damage[0][vert+6>>6][hor-6>>6] = True;
9213 damage[0][vert-6>>6][hor-6>>6] = True;
9214 hor += d_col - s_col; vert += d_row - s_row;
9218 Boolean IsDrawArrowEnabled()
9220 return appData.highlightMoveWithArrow && squareSize >= 32;
9223 void DrawArrowHighlight(int fromX, int fromY, int toX,int toY)
9225 if( IsDrawArrowEnabled() && fromX >= 0 && fromY >= 0 && toX >= 0 && toY >= 0)
9226 DrawArrowBetweenSquares(fromX, fromY, toX, toY);