2 * xboard.c -- X front end for XBoard
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
8 * 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
10 * The following terms apply to Digital Equipment Corporation's copyright
12 * ------------------------------------------------------------------------
15 * Permission to use, copy, modify, and distribute this software and its
16 * documentation for any purpose and without fee is hereby granted,
17 * provided that the above copyright notice appear in all copies and that
18 * both that copyright notice and this permission notice appear in
19 * supporting documentation, and that the name of Digital not be
20 * used in advertising or publicity pertaining to distribution of the
21 * software without specific, written prior permission.
23 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
30 * ------------------------------------------------------------------------
32 * The following terms apply to the enhanced version of XBoard
33 * distributed by the Free Software Foundation:
34 * ------------------------------------------------------------------------
36 * GNU XBoard is free software: you can redistribute it and/or modify
37 * it under the terms of the GNU General Public License as published by
38 * the Free Software Foundation, either version 3 of the License, or (at
39 * your option) any later version.
41 * GNU XBoard is distributed in the hope that it will be useful, but
42 * WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44 * General Public License for more details.
46 * You should have received a copy of the GNU General Public License
47 * along with this program. If not, see http://www.gnu.org/licenses/. *
49 *------------------------------------------------------------------------
50 ** See the file ChangeLog for a revision history. */
60 #include <sys/types.h>
66 # if HAVE_SYS_SOCKET_H
67 # include <sys/socket.h>
68 # include <netinet/in.h>
70 # else /* not HAVE_SYS_SOCKET_H */
71 # if HAVE_LAN_SOCKET_H
72 # include <lan/socket.h>
74 # include <lan/netdb.h>
75 # else /* not HAVE_LAN_SOCKET_H */
76 # define OMIT_SOCKETS 1
77 # endif /* not HAVE_LAN_SOCKET_H */
78 # endif /* not HAVE_SYS_SOCKET_H */
79 #endif /* !OMIT_SOCKETS */
84 #else /* not STDC_HEADERS */
85 extern char *getenv();
88 # else /* not HAVE_STRING_H */
90 # endif /* not HAVE_STRING_H */
91 #endif /* not STDC_HEADERS */
94 # include <sys/fcntl.h>
95 #else /* not HAVE_SYS_FCNTL_H */
98 # endif /* HAVE_FCNTL_H */
99 #endif /* not HAVE_SYS_FCNTL_H */
101 #if HAVE_SYS_SYSTEMINFO_H
102 # include <sys/systeminfo.h>
103 #endif /* HAVE_SYS_SYSTEMINFO_H */
105 #if TIME_WITH_SYS_TIME
106 # include <sys/time.h>
110 # include <sys/time.h>
121 # include <sys/wait.h>
126 # define NAMLEN(dirent) strlen((dirent)->d_name)
127 # define HAVE_DIR_STRUCT
129 # define dirent direct
130 # define NAMLEN(dirent) (dirent)->d_namlen
132 # include <sys/ndir.h>
133 # define HAVE_DIR_STRUCT
136 # include <sys/dir.h>
137 # define HAVE_DIR_STRUCT
141 # define HAVE_DIR_STRUCT
145 #include <X11/Intrinsic.h>
146 #include <X11/StringDefs.h>
147 #include <X11/Shell.h>
148 #include <X11/cursorfont.h>
149 #include <X11/Xatom.h>
150 #include <X11/Xmu/Atoms.h>
152 #include <X11/Xaw3d/Dialog.h>
153 #include <X11/Xaw3d/Form.h>
154 #include <X11/Xaw3d/List.h>
155 #include <X11/Xaw3d/Label.h>
156 #include <X11/Xaw3d/SimpleMenu.h>
157 #include <X11/Xaw3d/SmeBSB.h>
158 #include <X11/Xaw3d/SmeLine.h>
159 #include <X11/Xaw3d/Box.h>
160 #include <X11/Xaw3d/MenuButton.h>
161 #include <X11/Xaw3d/Text.h>
162 #include <X11/Xaw3d/AsciiText.h>
164 #include <X11/Xaw/Dialog.h>
165 #include <X11/Xaw/Form.h>
166 #include <X11/Xaw/List.h>
167 #include <X11/Xaw/Label.h>
168 #include <X11/Xaw/SimpleMenu.h>
169 #include <X11/Xaw/SmeBSB.h>
170 #include <X11/Xaw/SmeLine.h>
171 #include <X11/Xaw/Box.h>
172 #include <X11/Xaw/MenuButton.h>
173 #include <X11/Xaw/Text.h>
174 #include <X11/Xaw/AsciiText.h>
177 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
182 #include "pixmaps/pixmaps.h"
183 #define IMAGE_EXT "xpm"
185 #define IMAGE_EXT "xim"
186 #include "bitmaps/bitmaps.h"
189 #include "bitmaps/icon_white.bm"
190 #include "bitmaps/icon_black.bm"
191 #include "bitmaps/checkmark.bm"
193 #include "frontend.h"
195 #include "backendz.h"
199 #include "xgamelist.h"
200 #include "xhistory.h"
201 #include "xedittags.h"
204 // must be moved to xengineoutput.h
206 void EngineOutputProc P((Widget w, XEvent *event,
207 String *prms, Cardinal *nprms));
208 void EvalGraphProc P((Widget w, XEvent *event,
209 String *prms, Cardinal *nprms));
216 #define usleep(t) _sleep2(((t)+500)/1000)
220 # define _(s) gettext (s)
221 # define N_(s) gettext_noop (s)
239 int main P((int argc, char **argv));
240 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
241 char *init_path, char *mode, int (*show_entry)(), char **name_return));
242 RETSIGTYPE CmailSigHandler P((int sig));
243 RETSIGTYPE IntSigHandler P((int sig));
244 RETSIGTYPE TermSizeSigHandler P((int sig));
245 void CreateGCs P((void));
246 void CreateXIMPieces P((void));
247 void CreateXPMPieces P((void));
248 void CreateXPMBoard P((char *s, int n));
249 void CreatePieces P((void));
250 void CreatePieceMenus P((void));
251 Widget CreateMenuBar P((Menu *mb));
252 Widget CreateButtonBar P ((MenuItem *mi));
253 char *FindFont P((char *pattern, int targetPxlSize));
254 void PieceMenuPopup P((Widget w, XEvent *event,
255 String *params, Cardinal *num_params));
256 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
257 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
258 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
259 u_int wreq, u_int hreq));
260 void CreateGrid P((void));
261 int EventToSquare P((int x, int limit));
262 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
263 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
264 void HandleUserMove P((Widget w, XEvent *event,
265 String *prms, Cardinal *nprms));
266 void AnimateUserMove P((Widget w, XEvent * event,
267 String * params, Cardinal * nParams));
268 void HandlePV P((Widget w, XEvent * event,
269 String * params, Cardinal * nParams));
270 void SelectPV P((Widget w, XEvent * event,
271 String * params, Cardinal * nParams));
272 void StopPV P((Widget w, XEvent * event,
273 String * params, Cardinal * nParams));
274 void WhiteClock P((Widget w, XEvent *event,
275 String *prms, Cardinal *nprms));
276 void BlackClock P((Widget w, XEvent *event,
277 String *prms, Cardinal *nprms));
278 void DrawPositionProc P((Widget w, XEvent *event,
279 String *prms, Cardinal *nprms));
280 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
282 void CommentClick P((Widget w, XEvent * event,
283 String * params, Cardinal * nParams));
284 void CommentPopUp P((char *title, char *label));
285 void CommentPopDown P((void));
286 void CommentCallback P((Widget w, XtPointer client_data,
287 XtPointer call_data));
288 void ICSInputBoxPopUp P((void));
289 void ICSInputBoxPopDown P((void));
290 void FileNamePopUp P((char *label, char *def,
291 FileProc proc, char *openMode));
292 void FileNamePopDown P((void));
293 void FileNameCallback P((Widget w, XtPointer client_data,
294 XtPointer call_data));
295 void FileNameAction P((Widget w, XEvent *event,
296 String *prms, Cardinal *nprms));
297 void AskQuestionReplyAction P((Widget w, XEvent *event,
298 String *prms, Cardinal *nprms));
299 void AskQuestionProc P((Widget w, XEvent *event,
300 String *prms, Cardinal *nprms));
301 void AskQuestionPopDown P((void));
302 void PromotionPopDown P((void));
303 void PromotionCallback P((Widget w, XtPointer client_data,
304 XtPointer call_data));
305 void EditCommentPopDown P((void));
306 void EditCommentCallback P((Widget w, XtPointer client_data,
307 XtPointer call_data));
308 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
309 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
310 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
311 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
313 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
315 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
317 void LoadPositionProc P((Widget w, XEvent *event,
318 String *prms, Cardinal *nprms));
319 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
321 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
323 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
325 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
327 void PastePositionProc P((Widget w, XEvent *event, String *prms,
329 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
330 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
331 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
332 void SavePositionProc P((Widget w, XEvent *event,
333 String *prms, Cardinal *nprms));
334 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
335 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
337 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
338 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
339 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
341 void MachineWhiteProc P((Widget w, XEvent *event,
342 String *prms, Cardinal *nprms));
343 void AnalyzeModeProc P((Widget w, XEvent *event,
344 String *prms, Cardinal *nprms));
345 void AnalyzeFileProc P((Widget w, XEvent *event,
346 String *prms, Cardinal *nprms));
347 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
349 void IcsClientProc P((Widget w, XEvent *event, String *prms,
351 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
352 void EditPositionProc P((Widget w, XEvent *event,
353 String *prms, Cardinal *nprms));
354 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
355 void EditCommentProc P((Widget w, XEvent *event,
356 String *prms, Cardinal *nprms));
357 void IcsInputBoxProc P((Widget w, XEvent *event,
358 String *prms, Cardinal *nprms));
359 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
365 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
369 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
370 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
371 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
372 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
373 void StopObservingProc P((Widget w, XEvent *event, String *prms,
375 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
377 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
379 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
380 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
384 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
386 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
388 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
389 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
391 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
393 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
395 void AutocommProc P((Widget w, XEvent *event, String *prms,
397 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
398 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
399 void AutobsProc P((Widget w, XEvent *event, String *prms,
401 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
402 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
403 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
404 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
406 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
407 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
409 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
411 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
413 void HighlightArrowProc P((Widget w, XEvent *event, String *prms,
415 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
416 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
417 void OneClickProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
418 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
420 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
422 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
424 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
426 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
427 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
428 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
430 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
432 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
434 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
436 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
437 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
442 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
443 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
444 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
445 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
446 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
447 void DisplayMove P((int moveNumber));
448 void DisplayTitle P((char *title));
449 void ICSInitScript P((void));
450 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
451 void ErrorPopUp P((char *title, char *text, int modal));
452 void ErrorPopDown P((void));
453 static char *ExpandPathName P((char *path));
454 static void CreateAnimVars P((void));
455 static void DragPieceMove P((int x, int y));
456 static void DrawDragPiece P((void));
457 char *ModeToWidgetName P((GameMode mode));
458 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
459 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
460 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
461 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
462 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
463 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
464 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
465 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
466 void GameListOptionsPopDown P(());
467 void ShufflePopDown P(());
468 void EnginePopDown P(());
469 void UciPopDown P(());
470 void TimeControlPopDown P(());
471 void NewVariantPopDown P(());
472 void SettingsPopDown P(());
473 void update_ics_width P(());
474 int get_term_width P(());
475 int CopyMemoProc P(());
476 void DrawArrowHighlight P((int fromX, int fromY, int toX,int toY));
477 Boolean IsDrawArrowEnabled P(());
480 * XBoard depends on Xt R4 or higher
482 int xtVersion = XtSpecificationRelease;
487 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
488 jailSquareColor, highlightSquareColor, premoveHighlightColor;
489 Pixel lowTimeWarningColor;
490 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
491 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
492 wjPieceGC, bjPieceGC, prelineGC, countGC;
493 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
494 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
495 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
496 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
497 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
498 ICSInputShell, fileNameShell, askQuestionShell;
499 Widget historyShell, evalGraphShell, gameListShell;
500 int hOffset; // [HGM] dual
501 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
502 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
503 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
504 Font clockFontID, coordFontID, countFontID;
505 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
506 XtAppContext appContext;
508 char *oldICSInteractionTitle;
512 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
514 Position commentX = -1, commentY = -1;
515 Dimension commentW, commentH;
516 typedef unsigned int BoardSize;
518 Boolean chessProgram;
520 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
521 int squareSize, smallLayout = 0, tinyLayout = 0,
522 marginW, marginH, // [HGM] for run-time resizing
523 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
524 ICSInputBoxUp = False, askQuestionUp = False,
525 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
526 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
527 Pixel timerForegroundPixel, timerBackgroundPixel;
528 Pixel buttonForegroundPixel, buttonBackgroundPixel;
529 char *chessDir, *programName, *programVersion,
530 *gameCopyFilename, *gamePasteFilename;
531 Boolean alwaysOnTop = False;
532 Boolean saveSettingsOnExit;
533 char *settingsFileName;
534 char *icsTextMenuString;
536 char *firstChessProgramNames;
537 char *secondChessProgramNames;
539 WindowPlacement wpMain;
540 WindowPlacement wpConsole;
541 WindowPlacement wpComment;
542 WindowPlacement wpMoveHistory;
543 WindowPlacement wpEvalGraph;
544 WindowPlacement wpEngineOutput;
545 WindowPlacement wpGameList;
546 WindowPlacement wpTags;
550 Pixmap pieceBitmap[2][(int)BlackPawn];
551 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
552 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
553 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
554 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
555 Pixmap xpmBoardBitmap[2];
556 int useImages, useImageSqs, useTexture, textureW[2], textureH[2];
557 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
558 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
559 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
560 XImage *ximLightSquare, *ximDarkSquare;
563 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
564 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
566 #define White(piece) ((int)(piece) < (int)BlackPawn)
568 /* Variables for doing smooth animation. This whole thing
569 would be much easier if the board was double-buffered,
570 but that would require a fairly major rewrite. */
575 GC blitGC, pieceGC, outlineGC;
576 XPoint startSquare, prevFrame, mouseDelta;
580 int startBoardX, startBoardY;
583 /* There can be two pieces being animated at once: a player
584 can begin dragging a piece before the remote opponent has moved. */
586 static AnimState game, player;
588 /* Bitmaps for use as masks when drawing XPM pieces.
589 Need one for each black and white piece. */
590 static Pixmap xpmMask[BlackKing + 1];
592 /* This magic number is the number of intermediate frames used
593 in each half of the animation. For short moves it's reduced
594 by 1. The total number of frames will be factor * 2 + 1. */
597 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
599 MenuItem fileMenu[] = {
600 {N_("New Game Ctrl+N"), "New Game", ResetProc},
601 {N_("New Shuffle Game ..."), "New Shuffle Game", ShuffleMenuProc},
602 {N_("New Variant ... Alt+Shift+V"), "New Variant", NewVariantProc}, // [HGM] variant: not functional yet
603 {"----", NULL, NothingProc},
604 {N_("Load Game Ctrl+O"), "Load Game", LoadGameProc},
605 {N_("Load Position Ctrl+Shift+O"), "Load Position", LoadPositionProc},
606 // {N_("Load Next Game"), "Load Next Game", LoadNextGameProc},
607 // {N_("Load Previous Game"), "Load Previous Game", LoadPrevGameProc},
608 // {N_("Reload Same Game"), "Reload Same Game", ReloadGameProc},
609 {N_("Next Position Shift+PgDn"), "Load Next Position", LoadNextPositionProc},
610 {N_("Prev Position Shift+PgUp"), "Load Previous Position", LoadPrevPositionProc},
611 {"----", NULL, NothingProc},
612 // {N_("Reload Same Position"), "Reload Same Position", ReloadPositionProc},
613 {N_("Save Game Ctrl+S"), "Save Game", SaveGameProc},
614 {N_("Save Position Ctrl+Shift+S"), "Save Position", SavePositionProc},
615 {"----", NULL, NothingProc},
616 {N_("Mail Move"), "Mail Move", MailMoveProc},
617 {N_("Reload CMail Message"), "Reload CMail Message", ReloadCmailMsgProc},
618 {"----", NULL, NothingProc},
619 {N_("Quit Ctr+Q"), "Exit", QuitProc},
623 MenuItem editMenu[] = {
624 {N_("Copy Game Ctrl+C"), "Copy Game", CopyGameProc},
625 {N_("Copy Position Ctrl+Shift+C"), "Copy Position", CopyPositionProc},
626 {"----", NULL, NothingProc},
627 {N_("Paste Game Ctrl+V"), "Paste Game", PasteGameProc},
628 {N_("Paste Position Ctrl+Shift+V"), "Paste Position", PastePositionProc},
629 {"----", NULL, NothingProc},
630 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
631 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
632 {N_("Edit Tags"), "Edit Tags", EditTagsProc},
633 {N_("Edit Comment"), "Edit Comment", EditCommentProc},
634 {"----", NULL, NothingProc},
635 {N_("Revert Home"), "Revert", RevertProc},
636 {N_("Annotate"), "Annotate", AnnotateProc},
637 {N_("Truncate Game End"), "Truncate Game", TruncateGameProc},
638 {"----", NULL, NothingProc},
639 {N_("Backward Alt+Left"), "Backward", BackwardProc},
640 {N_("Forward Alt+Right"), "Forward", ForwardProc},
641 {N_("Back to Start Alt+Home"), "Back to Start", ToStartProc},
642 {N_("Forward to End Alt+End"), "Forward to End", ToEndProc},
646 MenuItem viewMenu[] = {
647 {N_("Flip View F2"), "Flip View", FlipViewProc},
648 {"----", NULL, NothingProc},
649 {N_("Engine Output Alt+Shift+O"), "Show Engine Output", EngineOutputProc},
650 {N_("Move History Alt+Shift+H"), "Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
651 {N_("Evaluation Graph Alt+Shift+E"), "Show Evaluation Graph", EvalGraphProc},
652 {N_("Game List Alt+Shift+G"), "Show Game List", ShowGameListProc},
653 {"----", NULL, NothingProc},
654 {N_("Tags"), "Show Tags", EditTagsProc},
655 {N_("Comments"), "Show Comments", EditCommentProc},
656 {N_("ICS Input Box"), "ICS Input Box", IcsInputBoxProc},
660 MenuItem modeMenu[] = {
661 {N_("Machine White Ctrl+W"), "Machine White", MachineWhiteProc},
662 {N_("Machine Black Ctrl+B"), "Machine Black", MachineBlackProc},
663 {N_("Two Machines Ctrl+T"), "Two Machines", TwoMachinesProc},
664 {N_("Analysis Mode Ctrl+A"), "Analysis Mode", AnalyzeModeProc},
665 {N_("Analyze File Ctrl+F"), "Analyze File", AnalyzeFileProc },
666 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
667 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
668 {N_("Training"), "Training", TrainingProc},
669 {N_("ICS Client"), "ICS Client", IcsClientProc},
670 {"----", NULL, NothingProc},
671 {N_("Pause Pause"), "Pause", PauseProc},
675 MenuItem actionMenu[] = {
676 {N_("Accept F3"), "Accept", AcceptProc},
677 {N_("Decline F4"), "Decline", DeclineProc},
678 {N_("Rematch F12"), "Rematch", RematchProc},
679 {"----", NULL, NothingProc},
680 {N_("Call Flag F5"), "Call Flag", CallFlagProc},
681 {N_("Draw F6"), "Draw", DrawProc},
682 {N_("Adjourn F7"), "Adjourn", AdjournProc},
683 {N_("Abort F8"),"Abort", AbortProc},
684 {N_("Resign F9"), "Resign", ResignProc},
685 {"----", NULL, NothingProc},
686 {N_("Stop Observing F10"), "Stop Observing", StopObservingProc},
687 {N_("Stop Examining F11"), "Stop Examining", StopExaminingProc},
688 {N_("Upload to Examine"), "Upload to Examine", UploadProc},
689 {"----", NULL, NothingProc},
690 {N_("Adjudicate to White"), "Adjudicate to White", AdjuWhiteProc},
691 {N_("Adjudicate to Black"), "Adjudicate to Black", AdjuBlackProc},
692 {N_("Adjudicate Draw"), "Adjudicate Draw", AdjuDrawProc},
696 MenuItem engineMenu[] = {
697 {N_("Engine #1 Settings ..."), "Engine #1 Settings", FirstSettingsProc},
698 {N_("Engine #2 Settings ..."), "Engine #2 Settings", SecondSettingsProc},
699 {"----", NULL, NothingProc},
700 {N_("Hint"), "Hint", HintProc},
701 {N_("Book"), "Book", BookProc},
702 {"----", NULL, NothingProc},
703 {N_("Move Now Ctrl+M"), "Move Now", MoveNowProc},
704 {N_("Retract Move Ctrl+X"), "Retract Move", RetractMoveProc},
708 MenuItem optionsMenu[] = {
709 {N_("Time Control ... Alt+Shift+T"), "Time Control", TimeControlProc},
710 {N_("Common Engine ... Alt+Shift+U"), "Common Engine", UciMenuProc},
711 {N_("Adjudications ... Alt+Shift+J"), "Adjudications", EngineMenuProc},
712 {N_("Game List ..."), "Game List", GameListOptionsPopUp},
713 {"----", NULL, NothingProc},
714 {N_("Always Queen Ctrl+Shift+Q"), "Always Queen", AlwaysQueenProc},
715 {N_("Animate Dragging"), "Animate Dragging", AnimateDraggingProc},
716 {N_("Animate Moving Ctrl+Shift+A"), "Animate Moving", AnimateMovingProc},
717 {N_("Auto Comment"), "Auto Comment", AutocommProc},
718 {N_("Auto Flag Ctrl+Shift+F"), "Auto Flag", AutoflagProc},
719 {N_("Auto Flip View"), "Auto Flip View", AutoflipProc},
720 {N_("Auto Observe"), "Auto Observe", AutobsProc},
721 {N_("Auto Raise Board"), "Auto Raise Board", AutoraiseProc},
722 {N_("Auto Save"), "Auto Save", AutosaveProc},
723 {N_("Blindfold"), "Blindfold", BlindfoldProc},
724 {N_("Flash Moves"), "Flash Moves", FlashMovesProc},
725 {N_("Get Move List"), "Get Move List", GetMoveListProc},
727 {N_("Highlight Dragging"), "Highlight Dragging", HighlightDraggingProc},
729 {N_("Highlight Last Move"), "Highlight Last Move", HighlightLastMoveProc},
730 {N_("Highlight With Arrow"), "Arrow", HighlightArrowProc},
731 {N_("Move Sound"), "Move Sound", MoveSoundProc},
732 {N_("ICS Alarm"), "ICS Alarm", IcsAlarmProc},
733 {N_("One-Click Moving"), "OneClick", OneClickProc},
734 {N_("Periodic Updates"), "Periodic Updates", PeriodicUpdatesProc},
735 {N_("Ponder Next Move Ctrl+Shift+P"), "Ponder Next Move", PonderNextMoveProc},
736 {N_("Popup Exit Message"), "Popup Exit Message", PopupExitMessageProc},
737 {N_("Popup Move Errors"), "Popup Move Errors", PopupMoveErrorsProc},
738 {N_("Premove"), "Premove", PremoveProc},
739 {N_("Quiet Play"), "Quiet Play", QuietPlayProc},
740 {N_("Show Coords"), "Show Coords", ShowCoordsProc},
741 {N_("Hide Thinking Ctrl+Shift+H"), "Hide Thinking", HideThinkingProc},
742 {N_("Test Legality Ctrl+Shift+L"), "Test Legality", TestLegalityProc},
743 {"----", NULL, NothingProc},
744 {N_("Save Settings Now"), "Save Settings Now", SaveSettingsProc},
745 {N_("Save Settings on Exit"), "Save Settings on Exit", SaveOnExitProc},
749 MenuItem helpMenu[] = {
750 {N_("Info XBoard"), "Info XBoard", InfoProc},
751 {N_("Man XBoard F1"), "Man XBoard", ManProc},
752 {"----", NULL, NothingProc},
753 {N_("About XBoard"), "About XBoard", AboutProc},
758 {N_("File"), "File", fileMenu},
759 {N_("Edit"), "Edit", editMenu},
760 {N_("View"), "View", viewMenu},
761 {N_("Mode"), "Mode", modeMenu},
762 {N_("Action"), "Action", actionMenu},
763 {N_("Engine"), "Engine", engineMenu},
764 {N_("Options"), "Options", optionsMenu},
765 {N_("Help"), "Help", helpMenu},
769 #define PAUSE_BUTTON "P"
770 MenuItem buttonBar[] = {
771 {"<<", "<<", ToStartProc},
772 {"<", "<", BackwardProc},
773 {PAUSE_BUTTON, PAUSE_BUTTON, PauseProc},
774 {">", ">", ForwardProc},
775 {">>", ">>", ToEndProc},
779 #define PIECE_MENU_SIZE 18
780 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
781 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
782 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
783 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
784 N_("Empty square"), N_("Clear board") },
785 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
786 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
787 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
788 N_("Empty square"), N_("Clear board") }
790 /* must be in same order as PieceMenuStrings! */
791 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
792 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
793 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
794 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
795 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
796 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
797 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
798 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
799 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
802 #define DROP_MENU_SIZE 6
803 String dropMenuStrings[DROP_MENU_SIZE] = {
804 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
806 /* must be in same order as PieceMenuStrings! */
807 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
808 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
809 WhiteRook, WhiteQueen
817 DropMenuEnables dmEnables[] = {
835 { XtNborderWidth, 0 },
836 { XtNdefaultDistance, 0 },
840 { XtNborderWidth, 0 },
841 { XtNresizable, (XtArgVal) True },
845 { XtNborderWidth, 0 },
851 { XtNjustify, (XtArgVal) XtJustifyRight },
852 { XtNlabel, (XtArgVal) "..." },
853 { XtNresizable, (XtArgVal) True },
854 { XtNresize, (XtArgVal) False }
857 Arg messageArgs[] = {
858 { XtNjustify, (XtArgVal) XtJustifyLeft },
859 { XtNlabel, (XtArgVal) "..." },
860 { XtNresizable, (XtArgVal) True },
861 { XtNresize, (XtArgVal) False }
865 { XtNborderWidth, 0 },
866 { XtNjustify, (XtArgVal) XtJustifyLeft }
869 XtResource clientResources[] = {
870 { "flashCount", "flashCount", XtRInt, sizeof(int),
871 XtOffset(AppDataPtr, flashCount), XtRImmediate,
872 (XtPointer) FLASH_COUNT },
875 XrmOptionDescRec shellOptions[] = {
876 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
877 { "-flash", "flashCount", XrmoptionNoArg, "3" },
878 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
881 XtActionsRec boardActions[] = {
882 { "DrawPosition", DrawPositionProc },
883 { "HandleUserMove", HandleUserMove },
884 { "AnimateUserMove", AnimateUserMove },
885 { "HandlePV", HandlePV },
886 { "SelectPV", SelectPV },
887 { "StopPV", StopPV },
888 { "FileNameAction", FileNameAction },
889 { "AskQuestionProc", AskQuestionProc },
890 { "AskQuestionReplyAction", AskQuestionReplyAction },
891 { "PieceMenuPopup", PieceMenuPopup },
892 { "WhiteClock", WhiteClock },
893 { "BlackClock", BlackClock },
894 { "Iconify", Iconify },
895 { "ResetProc", ResetProc },
896 { "NewVariantProc", NewVariantProc },
897 { "LoadGameProc", LoadGameProc },
898 { "LoadNextGameProc", LoadNextGameProc },
899 { "LoadPrevGameProc", LoadPrevGameProc },
900 { "LoadSelectedProc", LoadSelectedProc },
901 { "SetFilterProc", SetFilterProc },
902 { "ReloadGameProc", ReloadGameProc },
903 { "LoadPositionProc", LoadPositionProc },
904 { "LoadNextPositionProc", LoadNextPositionProc },
905 { "LoadPrevPositionProc", LoadPrevPositionProc },
906 { "ReloadPositionProc", ReloadPositionProc },
907 { "CopyPositionProc", CopyPositionProc },
908 { "PastePositionProc", PastePositionProc },
909 { "CopyGameProc", CopyGameProc },
910 { "PasteGameProc", PasteGameProc },
911 { "SaveGameProc", SaveGameProc },
912 { "SavePositionProc", SavePositionProc },
913 { "MailMoveProc", MailMoveProc },
914 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
915 { "QuitProc", QuitProc },
916 { "MachineWhiteProc", MachineWhiteProc },
917 { "MachineBlackProc", MachineBlackProc },
918 { "AnalysisModeProc", AnalyzeModeProc },
919 { "AnalyzeFileProc", AnalyzeFileProc },
920 { "TwoMachinesProc", TwoMachinesProc },
921 { "IcsClientProc", IcsClientProc },
922 { "EditGameProc", EditGameProc },
923 { "EditPositionProc", EditPositionProc },
924 { "TrainingProc", EditPositionProc },
925 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
926 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
927 { "ShowGameListProc", ShowGameListProc },
928 { "ShowMoveListProc", HistoryShowProc},
929 { "EditTagsProc", EditCommentProc },
930 { "EditCommentProc", EditCommentProc },
931 { "IcsAlarmProc", IcsAlarmProc },
932 { "IcsInputBoxProc", IcsInputBoxProc },
933 { "PauseProc", PauseProc },
934 { "AcceptProc", AcceptProc },
935 { "DeclineProc", DeclineProc },
936 { "RematchProc", RematchProc },
937 { "CallFlagProc", CallFlagProc },
938 { "DrawProc", DrawProc },
939 { "AdjournProc", AdjournProc },
940 { "AbortProc", AbortProc },
941 { "ResignProc", ResignProc },
942 { "AdjuWhiteProc", AdjuWhiteProc },
943 { "AdjuBlackProc", AdjuBlackProc },
944 { "AdjuDrawProc", AdjuDrawProc },
945 { "EnterKeyProc", EnterKeyProc },
946 { "UpKeyProc", UpKeyProc },
947 { "DownKeyProc", DownKeyProc },
948 { "StopObservingProc", StopObservingProc },
949 { "StopExaminingProc", StopExaminingProc },
950 { "UploadProc", UploadProc },
951 { "BackwardProc", BackwardProc },
952 { "ForwardProc", ForwardProc },
953 { "ToStartProc", ToStartProc },
954 { "ToEndProc", ToEndProc },
955 { "RevertProc", RevertProc },
956 { "AnnotateProc", AnnotateProc },
957 { "TruncateGameProc", TruncateGameProc },
958 { "MoveNowProc", MoveNowProc },
959 { "RetractMoveProc", RetractMoveProc },
960 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
961 { "UciMenuProc", (XtActionProc) UciMenuProc },
962 { "TimeControlProc", (XtActionProc) TimeControlProc },
963 { "AlwaysQueenProc", AlwaysQueenProc },
964 { "AnimateDraggingProc", AnimateDraggingProc },
965 { "AnimateMovingProc", AnimateMovingProc },
966 { "AutoflagProc", AutoflagProc },
967 { "AutoflipProc", AutoflipProc },
968 { "AutobsProc", AutobsProc },
969 { "AutoraiseProc", AutoraiseProc },
970 { "AutosaveProc", AutosaveProc },
971 { "BlindfoldProc", BlindfoldProc },
972 { "FlashMovesProc", FlashMovesProc },
973 { "FlipViewProc", FlipViewProc },
974 { "GetMoveListProc", GetMoveListProc },
976 { "HighlightDraggingProc", HighlightDraggingProc },
978 { "HighlightLastMoveProc", HighlightLastMoveProc },
979 { "IcsAlarmProc", IcsAlarmProc },
980 { "MoveSoundProc", MoveSoundProc },
981 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
982 { "PonderNextMoveProc", PonderNextMoveProc },
983 { "PopupExitMessageProc", PopupExitMessageProc },
984 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
985 { "PremoveProc", PremoveProc },
986 { "QuietPlayProc", QuietPlayProc },
987 { "ShowCoordsProc", ShowCoordsProc },
988 { "ShowThinkingProc", ShowThinkingProc },
989 { "HideThinkingProc", HideThinkingProc },
990 { "TestLegalityProc", TestLegalityProc },
991 { "SaveSettingsProc", SaveSettingsProc },
992 { "SaveOnExitProc", SaveOnExitProc },
993 { "InfoProc", InfoProc },
994 { "ManProc", ManProc },
995 { "HintProc", HintProc },
996 { "BookProc", BookProc },
997 { "AboutGameProc", AboutGameProc },
998 { "AboutProc", AboutProc },
999 { "DebugProc", DebugProc },
1000 { "NothingProc", NothingProc },
1001 { "CommentClick", (XtActionProc) CommentClick },
1002 { "CommentPopDown", (XtActionProc) CommentPopDown },
1003 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
1004 { "TagsPopDown", (XtActionProc) TagsPopDown },
1005 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
1006 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
1007 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
1008 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
1009 { "GameListPopDown", (XtActionProc) GameListPopDown },
1010 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
1011 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1012 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
1013 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1014 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1015 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
1016 { "EnginePopDown", (XtActionProc) EnginePopDown },
1017 { "UciPopDown", (XtActionProc) UciPopDown },
1018 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
1019 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
1020 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
1021 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1024 char globalTranslations[] =
1025 ":<Key>F9: ResignProc() \n \
1026 :Ctrl<Key>n: ResetProc() \n \
1027 :Meta<Key>V: NewVariantProc() \n \
1028 :Ctrl<Key>o: LoadGameProc() \n \
1029 :Meta<Key>Next: LoadNextGameProc() \n \
1030 :Meta<Key>Prior: LoadPrevGameProc() \n \
1031 :Ctrl<Key>s: SaveGameProc() \n \
1032 :Ctrl<Key>c: CopyGameProc() \n \
1033 :Ctrl<Key>v: PasteGameProc() \n \
1034 :Ctrl<Key>O: LoadPositionProc() \n \
1035 :Shift<Key>Next: LoadNextPositionProc() \n \
1036 :Shift<Key>Prior: LoadPrevPositionProc() \n \
1037 :Ctrl<Key>S: SavePositionProc() \n \
1038 :Ctrl<Key>C: CopyPositionProc() \n \
1039 :Ctrl<Key>V: PastePositionProc() \n \
1040 :Ctrl<Key>q: QuitProc() \n \
1041 :Ctrl<Key>w: MachineWhiteProc() \n \
1042 :Ctrl<Key>b: MachineBlackProc() \n \
1043 :Ctrl<Key>t: TwoMachinesProc() \n \
1044 :Ctrl<Key>a: AnalysisModeProc() \n \
1045 :Ctrl<Key>f: AnalyzeFileProc() \n \
1046 :Ctrl<Key>e: EditGameProc() \n \
1047 :Ctrl<Key>E: EditPositionProc() \n \
1048 :Meta<Key>O: EngineOutputProc() \n \
1049 :Meta<Key>E: EvalGraphProc() \n \
1050 :Meta<Key>G: ShowGameListProc() \n \
1051 :Meta<Key>H: ShowMoveListProc() \n \
1052 :<Key>Pause: PauseProc() \n \
1053 :<Key>F3: AcceptProc() \n \
1054 :<Key>F4: DeclineProc() \n \
1055 :<Key>F12: RematchProc() \n \
1056 :<Key>F5: CallFlagProc() \n \
1057 :<Key>F6: DrawProc() \n \
1058 :<Key>F7: AdjournProc() \n \
1059 :<Key>F8: AbortProc() \n \
1060 :<Key>F10: StopObservingProc() \n \
1061 :<Key>F11: StopExaminingProc() \n \
1062 :Meta Ctrl<Key>F12: DebugProc() \n \
1063 :Meta<Key>End: ToEndProc() \n \
1064 :Meta<Key>Right: ForwardProc() \n \
1065 :Meta<Key>Home: ToStartProc() \n \
1066 :Meta<Key>Left: BackwardProc() \n \
1067 :<Key>Home: RevertProc() \n \
1068 :<Key>End: TruncateGameProc() \n \
1069 :Ctrl<Key>m: MoveNowProc() \n \
1070 :Ctrl<Key>x: RetractMoveProc() \n \
1071 :Meta<Key>J: EngineMenuProc() \n \
1072 :Meta<Key>U: UciMenuProc() \n \
1073 :Meta<Key>T: TimeControlProc() \n \
1074 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1075 :Ctrl<Key>F: AutoflagProc() \n \
1076 :Ctrl<Key>A: AnimateMovingProc() \n \
1077 :Ctrl<Key>P: PonderNextMoveProc() \n \
1078 :Ctrl<Key>L: TestLegalityProc() \n \
1079 :Ctrl<Key>H: HideThinkingProc() \n \
1080 :<Key>-: Iconify() \n \
1081 :<Key>F1: ManProc() \n \
1082 :<Key>F2: FlipViewProc() \n \
1083 <KeyDown>.: BackwardProc() \n \
1084 <KeyUp>.: ForwardProc() \n \
1085 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1086 \"Send to chess program:\",,1) \n \
1087 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1088 \"Send to second chess program:\",,2) \n";
1090 char boardTranslations[] =
1091 "<Btn1Down>: HandleUserMove(0) \n \
1092 Shift<Btn1Up>: HandleUserMove(1) \n \
1093 <Btn1Up>: HandleUserMove(0) \n \
1094 <Btn1Motion>: AnimateUserMove() \n \
1095 <Btn3Motion>: HandlePV() \n \
1096 <Btn3Up>: PieceMenuPopup(menuB) \n \
1097 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1098 PieceMenuPopup(menuB) \n \
1099 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1100 PieceMenuPopup(menuW) \n \
1101 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1102 PieceMenuPopup(menuW) \n \
1103 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1104 PieceMenuPopup(menuB) \n";
1106 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1107 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1109 char ICSInputTranslations[] =
1110 "<Key>Up: UpKeyProc() \n "
1111 "<Key>Down: DownKeyProc() \n "
1112 "<Key>Return: EnterKeyProc() \n";
1114 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1115 // as the widget is destroyed before the up-click can call extend-end
1116 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1118 String xboardResources[] = {
1119 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1120 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1121 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1126 /* Max possible square size */
1127 #define MAXSQSIZE 256
1129 static int xpm_avail[MAXSQSIZE];
1131 #ifdef HAVE_DIR_STRUCT
1133 /* Extract piece size from filename */
1135 xpm_getsize(name, len, ext)
1146 if ((p=strchr(name, '.')) == NULL ||
1147 StrCaseCmp(p+1, ext) != 0)
1153 while (*p && isdigit(*p))
1160 /* Setup xpm_avail */
1162 xpm_getavail(dirname, ext)
1170 for (i=0; i<MAXSQSIZE; ++i)
1173 if (appData.debugMode)
1174 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1176 dir = opendir(dirname);
1179 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1180 programName, dirname);
1184 while ((ent=readdir(dir)) != NULL) {
1185 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1186 if (i > 0 && i < MAXSQSIZE)
1196 xpm_print_avail(fp, ext)
1202 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1203 for (i=1; i<MAXSQSIZE; ++i) {
1209 /* Return XPM piecesize closest to size */
1211 xpm_closest_to(dirname, size, ext)
1217 int sm_diff = MAXSQSIZE;
1221 xpm_getavail(dirname, ext);
1223 if (appData.debugMode)
1224 xpm_print_avail(stderr, ext);
1226 for (i=1; i<MAXSQSIZE; ++i) {
1229 diff = (diff<0) ? -diff : diff;
1230 if (diff < sm_diff) {
1238 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1244 #else /* !HAVE_DIR_STRUCT */
1245 /* If we are on a system without a DIR struct, we can't
1246 read the directory, so we can't collect a list of
1247 filenames, etc., so we can't do any size-fitting. */
1249 xpm_closest_to(dirname, size, ext)
1254 fprintf(stderr, _("\
1255 Warning: No DIR structure found on this system --\n\
1256 Unable to autosize for XPM/XIM pieces.\n\
1257 Please report this error to frankm@hiwaay.net.\n\
1258 Include system type & operating system in message.\n"));
1261 #endif /* HAVE_DIR_STRUCT */
1263 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1264 "magenta", "cyan", "white" };
1268 TextColors textColors[(int)NColorClasses];
1270 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1272 parse_color(str, which)
1276 char *p, buf[100], *d;
1279 if (strlen(str) > 99) /* watch bounds on buf */
1284 for (i=0; i<which; ++i) {
1291 /* Could be looking at something like:
1293 .. in which case we want to stop on a comma also */
1294 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1298 return -1; /* Use default for empty field */
1301 if (which == 2 || isdigit(*p))
1304 while (*p && isalpha(*p))
1309 for (i=0; i<8; ++i) {
1310 if (!StrCaseCmp(buf, cnames[i]))
1311 return which? (i+40) : (i+30);
1313 if (!StrCaseCmp(buf, "default")) return -1;
1315 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1320 parse_cpair(cc, str)
1324 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1325 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1330 /* bg and attr are optional */
1331 textColors[(int)cc].bg = parse_color(str, 1);
1332 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1333 textColors[(int)cc].attr = 0;
1339 /* Arrange to catch delete-window events */
1340 Atom wm_delete_window;
1342 CatchDeleteWindow(Widget w, String procname)
1345 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1346 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1347 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1354 XtSetArg(args[0], XtNiconic, False);
1355 XtSetValues(shellWidget, args, 1);
1357 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1360 //---------------------------------------------------------------------------------------------------------
1361 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1364 #define CW_USEDEFAULT (1<<31)
1365 #define ICS_TEXT_MENU_SIZE 90
1366 #define DEBUG_FILE "xboard.debug"
1367 #define SetCurrentDirectory chdir
1368 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1372 // these two must some day move to frontend.h, when they are implemented
1373 Boolean GameListIsUp();
1375 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1378 // front-end part of option handling
1380 // [HGM] This platform-dependent table provides the location for storing the color info
1381 extern char *crWhite, * crBlack;
1385 &appData.whitePieceColor,
1386 &appData.blackPieceColor,
1387 &appData.lightSquareColor,
1388 &appData.darkSquareColor,
1389 &appData.highlightSquareColor,
1390 &appData.premoveHighlightColor,
1391 &appData.lowTimeWarningColor,
1402 // [HGM] font: keep a font for each square size, even non-stndard ones
1403 #define NUM_SIZES 18
1404 #define MAX_SIZE 130
1405 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1406 char *fontTable[NUM_FONTS][MAX_SIZE];
1409 ParseFont(char *name, int number)
1410 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1412 if(sscanf(name, "size%d:", &size)) {
1413 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1414 // defer processing it until we know if it matches our board size
1415 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1416 fontTable[number][size] = strdup(strchr(name, ':')+1);
1417 fontValid[number][size] = True;
1422 case 0: // CLOCK_FONT
1423 appData.clockFont = strdup(name);
1425 case 1: // MESSAGE_FONT
1426 appData.font = strdup(name);
1428 case 2: // COORD_FONT
1429 appData.coordFont = strdup(name);
1434 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1439 { // only 2 fonts currently
1440 appData.clockFont = CLOCK_FONT_NAME;
1441 appData.coordFont = COORD_FONT_NAME;
1442 appData.font = DEFAULT_FONT_NAME;
1447 { // no-op, until we identify the code for this already in XBoard and move it here
1451 ParseColor(int n, char *name)
1452 { // in XBoard, just copy the color-name string
1453 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1457 ParseTextAttribs(ColorClass cc, char *s)
1459 (&appData.colorShout)[cc] = strdup(s);
1463 ParseBoardSize(void *addr, char *name)
1465 appData.boardSize = strdup(name);
1470 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1474 SetCommPortDefaults()
1475 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1478 // [HGM] args: these three cases taken out to stay in front-end
1480 SaveFontArg(FILE *f, ArgDescriptor *ad)
1483 int i, n = (int)ad->argLoc;
1485 case 0: // CLOCK_FONT
1486 name = appData.clockFont;
1488 case 1: // MESSAGE_FONT
1489 name = appData.font;
1491 case 2: // COORD_FONT
1492 name = appData.coordFont;
1497 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1498 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1499 fontTable[n][squareSize] = strdup(name);
1500 fontValid[n][squareSize] = True;
1503 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1504 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1509 { // nothing to do, as the sounds are at all times represented by their text-string names already
1513 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1514 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1515 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1519 SaveColor(FILE *f, ArgDescriptor *ad)
1520 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1521 if(colorVariable[(int)ad->argLoc])
1522 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1526 SaveBoardSize(FILE *f, char *name, void *addr)
1527 { // wrapper to shield back-end from BoardSize & sizeInfo
1528 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1532 ParseCommPortSettings(char *s)
1533 { // no such option in XBoard (yet)
1536 extern Widget engineOutputShell;
1537 extern Widget tagsShell, editTagsShell;
1539 GetActualPlacement(Widget wg, WindowPlacement *wp)
1549 XtSetArg(args[i], XtNx, &x); i++;
1550 XtSetArg(args[i], XtNy, &y); i++;
1551 XtSetArg(args[i], XtNwidth, &w); i++;
1552 XtSetArg(args[i], XtNheight, &h); i++;
1553 XtGetValues(wg, args, i);
1562 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1563 // In XBoard this will have to wait until awareness of window parameters is implemented
1564 GetActualPlacement(shellWidget, &wpMain);
1565 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1566 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1567 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1568 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1569 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1570 else GetActualPlacement(editShell, &wpComment);
1571 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1572 else GetActualPlacement(editTagsShell, &wpTags);
1576 PrintCommPortSettings(FILE *f, char *name)
1577 { // This option does not exist in XBoard
1581 MySearchPath(char *installDir, char *name, char *fullname)
1582 { // just append installDir and name. Perhaps ExpandPath should be used here?
1583 name = ExpandPathName(name);
1584 if(name && name[0] == '/')
1585 safeStrCpy(fullname, name, MSG_SIZ );
1587 sprintf(fullname, "%s%c%s", installDir, '/', name);
1593 MyGetFullPathName(char *name, char *fullname)
1594 { // should use ExpandPath?
1595 name = ExpandPathName(name);
1596 safeStrCpy(fullname, name, MSG_SIZ );
1601 EnsureOnScreen(int *x, int *y, int minX, int minY)
1608 { // [HGM] args: allows testing if main window is realized from back-end
1609 return xBoardWindow != 0;
1613 PopUpStartupDialog()
1614 { // start menu not implemented in XBoard
1618 ConvertToLine(int argc, char **argv)
1620 static char line[128*1024], buf[1024];
1624 for(i=1; i<argc; i++)
1626 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1627 && argv[i][0] != '{' )
1628 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1630 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1631 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1634 line[strlen(line)-1] = NULLCHAR;
1638 //--------------------------------------------------------------------------------------------
1640 extern Boolean twoBoards, partnerUp;
1643 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1645 #define BoardSize int
1646 void InitDrawingSizes(BoardSize boardSize, int flags)
1647 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1648 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1650 XtGeometryResult gres;
1653 if(!formWidget) return;
1656 * Enable shell resizing.
1658 shellArgs[0].value = (XtArgVal) &w;
1659 shellArgs[1].value = (XtArgVal) &h;
1660 XtGetValues(shellWidget, shellArgs, 2);
1662 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1663 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1664 XtSetValues(shellWidget, &shellArgs[2], 4);
1666 XtSetArg(args[0], XtNdefaultDistance, &sep);
1667 XtGetValues(formWidget, args, 1);
1669 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1670 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1672 hOffset = boardWidth + 10;
1673 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1674 secondSegments[i] = gridSegments[i];
1675 secondSegments[i].x1 += hOffset;
1676 secondSegments[i].x2 += hOffset;
1679 XtSetArg(args[0], XtNwidth, boardWidth);
1680 XtSetArg(args[1], XtNheight, boardHeight);
1681 XtSetValues(boardWidget, args, 2);
1683 timerWidth = (boardWidth - sep) / 2;
1684 XtSetArg(args[0], XtNwidth, timerWidth);
1685 XtSetValues(whiteTimerWidget, args, 1);
1686 XtSetValues(blackTimerWidget, args, 1);
1688 XawFormDoLayout(formWidget, False);
1690 if (appData.titleInWindow) {
1692 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1693 XtSetArg(args[i], XtNheight, &h); i++;
1694 XtGetValues(titleWidget, args, i);
1696 w = boardWidth - 2*bor;
1698 XtSetArg(args[0], XtNwidth, &w);
1699 XtGetValues(menuBarWidget, args, 1);
1700 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1703 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1704 if (gres != XtGeometryYes && appData.debugMode) {
1706 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1707 programName, gres, w, h, wr, hr);
1711 XawFormDoLayout(formWidget, True);
1714 * Inhibit shell resizing.
1716 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1717 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1718 shellArgs[4].value = shellArgs[2].value = w;
1719 shellArgs[5].value = shellArgs[3].value = h;
1720 XtSetValues(shellWidget, &shellArgs[0], 6);
1722 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1725 for(i=0; i<4; i++) {
1727 for(p=0; p<=(int)WhiteKing; p++)
1728 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1729 if(gameInfo.variant == VariantShogi) {
1730 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1731 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1732 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1733 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1734 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1737 if(gameInfo.variant == VariantGothic) {
1738 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1741 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1742 xpmPieceBitmap[i][(int)WhiteAngel] = xpmPieceBitmap2[i][(int)WhiteFalcon];
1743 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1746 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1747 for(p=0; p<=(int)WhiteKing; p++)
1748 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1749 if(gameInfo.variant == VariantShogi) {
1750 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1751 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1752 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1753 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1754 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1757 if(gameInfo.variant == VariantGothic) {
1758 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1761 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1762 ximMaskPm[(int)WhiteAngel] = ximMaskPm2[(int)WhiteFalcon];
1763 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1768 for(i=0; i<2; i++) {
1770 for(p=0; p<=(int)WhiteKing; p++)
1771 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1772 if(gameInfo.variant == VariantShogi) {
1773 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1774 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1775 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1776 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1777 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1780 if(gameInfo.variant == VariantGothic) {
1781 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1784 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1785 pieceBitmap[i][(int)WhiteAngel] = pieceBitmap2[i][(int)WhiteFalcon];
1786 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1801 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1802 XSetWindowAttributes window_attributes;
1804 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1805 XrmValue vFrom, vTo;
1806 XtGeometryResult gres;
1809 int forceMono = False;
1811 srandom(time(0)); // [HGM] book: make random truly random
1813 setbuf(stdout, NULL);
1814 setbuf(stderr, NULL);
1817 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1818 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1822 programName = strrchr(argv[0], '/');
1823 if (programName == NULL)
1824 programName = argv[0];
1829 XtSetLanguageProc(NULL, NULL, NULL);
1830 bindtextdomain(PACKAGE, LOCALEDIR);
1831 textdomain(PACKAGE);
1835 XtAppInitialize(&appContext, "XBoard", shellOptions,
1836 XtNumber(shellOptions),
1837 &argc, argv, xboardResources, NULL, 0);
1838 appData.boardSize = "";
1839 InitAppData(ConvertToLine(argc, argv));
1841 if (p == NULL) p = "/tmp";
1842 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1843 gameCopyFilename = (char*) malloc(i);
1844 gamePasteFilename = (char*) malloc(i);
1845 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1846 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1848 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1849 clientResources, XtNumber(clientResources),
1852 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1853 static char buf[MSG_SIZ];
1854 EscapeExpand(buf, appData.initString);
1855 appData.initString = strdup(buf);
1856 EscapeExpand(buf, appData.secondInitString);
1857 appData.secondInitString = strdup(buf);
1858 EscapeExpand(buf, appData.firstComputerString);
1859 appData.firstComputerString = strdup(buf);
1860 EscapeExpand(buf, appData.secondComputerString);
1861 appData.secondComputerString = strdup(buf);
1864 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1867 if (chdir(chessDir) != 0) {
1868 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1874 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1875 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1876 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1877 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1880 setbuf(debugFP, NULL);
1883 /* [HGM,HR] make sure board size is acceptable */
1884 if(appData.NrFiles > BOARD_FILES ||
1885 appData.NrRanks > BOARD_RANKS )
1886 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1889 /* This feature does not work; animation needs a rewrite */
1890 appData.highlightDragging = FALSE;
1894 xDisplay = XtDisplay(shellWidget);
1895 xScreen = DefaultScreen(xDisplay);
1896 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1898 gameInfo.variant = StringToVariant(appData.variant);
1899 InitPosition(FALSE);
1902 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1904 if (isdigit(appData.boardSize[0])) {
1905 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1906 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1907 &fontPxlSize, &smallLayout, &tinyLayout);
1909 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1910 programName, appData.boardSize);
1914 /* Find some defaults; use the nearest known size */
1915 SizeDefaults *szd, *nearest;
1916 int distance = 99999;
1917 nearest = szd = sizeDefaults;
1918 while (szd->name != NULL) {
1919 if (abs(szd->squareSize - squareSize) < distance) {
1921 distance = abs(szd->squareSize - squareSize);
1922 if (distance == 0) break;
1926 if (i < 2) lineGap = nearest->lineGap;
1927 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1928 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1929 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1930 if (i < 6) smallLayout = nearest->smallLayout;
1931 if (i < 7) tinyLayout = nearest->tinyLayout;
1934 SizeDefaults *szd = sizeDefaults;
1935 if (*appData.boardSize == NULLCHAR) {
1936 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1937 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1940 if (szd->name == NULL) szd--;
1941 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1943 while (szd->name != NULL &&
1944 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1945 if (szd->name == NULL) {
1946 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1947 programName, appData.boardSize);
1951 squareSize = szd->squareSize;
1952 lineGap = szd->lineGap;
1953 clockFontPxlSize = szd->clockFontPxlSize;
1954 coordFontPxlSize = szd->coordFontPxlSize;
1955 fontPxlSize = szd->fontPxlSize;
1956 smallLayout = szd->smallLayout;
1957 tinyLayout = szd->tinyLayout;
1958 // [HGM] font: use defaults from settings file if available and not overruled
1960 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
1961 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
1962 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
1963 appData.font = fontTable[MESSAGE_FONT][squareSize];
1964 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
1965 appData.coordFont = fontTable[COORD_FONT][squareSize];
1967 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1968 if (strlen(appData.pixmapDirectory) > 0) {
1969 p = ExpandPathName(appData.pixmapDirectory);
1971 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1972 appData.pixmapDirectory);
1975 if (appData.debugMode) {
1976 fprintf(stderr, _("\
1977 XBoard square size (hint): %d\n\
1978 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1980 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1981 if (appData.debugMode) {
1982 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1985 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1987 /* [HR] height treated separately (hacked) */
1988 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1989 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1990 if (appData.showJail == 1) {
1991 /* Jail on top and bottom */
1992 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1993 XtSetArg(boardArgs[2], XtNheight,
1994 boardHeight + 2*(lineGap + squareSize));
1995 } else if (appData.showJail == 2) {
1997 XtSetArg(boardArgs[1], XtNwidth,
1998 boardWidth + 2*(lineGap + squareSize));
1999 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2002 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2003 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2007 * Determine what fonts to use.
2009 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2010 clockFontID = XLoadFont(xDisplay, appData.clockFont);
2011 clockFontStruct = XQueryFont(xDisplay, clockFontID);
2012 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2013 coordFontID = XLoadFont(xDisplay, appData.coordFont);
2014 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2015 appData.font = FindFont(appData.font, fontPxlSize);
2016 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
2017 countFontStruct = XQueryFont(xDisplay, countFontID);
2018 // appData.font = FindFont(appData.font, fontPxlSize);
2020 xdb = XtDatabase(xDisplay);
2021 XrmPutStringResource(&xdb, "*font", appData.font);
2024 * Detect if there are not enough colors available and adapt.
2026 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2027 appData.monoMode = True;
2030 if (!appData.monoMode) {
2031 vFrom.addr = (caddr_t) appData.lightSquareColor;
2032 vFrom.size = strlen(appData.lightSquareColor);
2033 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2034 if (vTo.addr == NULL) {
2035 appData.monoMode = True;
2038 lightSquareColor = *(Pixel *) vTo.addr;
2041 if (!appData.monoMode) {
2042 vFrom.addr = (caddr_t) appData.darkSquareColor;
2043 vFrom.size = strlen(appData.darkSquareColor);
2044 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2045 if (vTo.addr == NULL) {
2046 appData.monoMode = True;
2049 darkSquareColor = *(Pixel *) vTo.addr;
2052 if (!appData.monoMode) {
2053 vFrom.addr = (caddr_t) appData.whitePieceColor;
2054 vFrom.size = strlen(appData.whitePieceColor);
2055 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2056 if (vTo.addr == NULL) {
2057 appData.monoMode = True;
2060 whitePieceColor = *(Pixel *) vTo.addr;
2063 if (!appData.monoMode) {
2064 vFrom.addr = (caddr_t) appData.blackPieceColor;
2065 vFrom.size = strlen(appData.blackPieceColor);
2066 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2067 if (vTo.addr == NULL) {
2068 appData.monoMode = True;
2071 blackPieceColor = *(Pixel *) vTo.addr;
2075 if (!appData.monoMode) {
2076 vFrom.addr = (caddr_t) appData.highlightSquareColor;
2077 vFrom.size = strlen(appData.highlightSquareColor);
2078 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2079 if (vTo.addr == NULL) {
2080 appData.monoMode = True;
2083 highlightSquareColor = *(Pixel *) vTo.addr;
2087 if (!appData.monoMode) {
2088 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
2089 vFrom.size = strlen(appData.premoveHighlightColor);
2090 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2091 if (vTo.addr == NULL) {
2092 appData.monoMode = True;
2095 premoveHighlightColor = *(Pixel *) vTo.addr;
2100 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2103 if (appData.bitmapDirectory == NULL ||
2104 appData.bitmapDirectory[0] == NULLCHAR)
2105 appData.bitmapDirectory = DEF_BITMAP_DIR;
2108 if (appData.lowTimeWarning && !appData.monoMode) {
2109 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2110 vFrom.size = strlen(appData.lowTimeWarningColor);
2111 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2112 if (vTo.addr == NULL)
2113 appData.monoMode = True;
2115 lowTimeWarningColor = *(Pixel *) vTo.addr;
2118 if (appData.monoMode && appData.debugMode) {
2119 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2120 (unsigned long) XWhitePixel(xDisplay, xScreen),
2121 (unsigned long) XBlackPixel(xDisplay, xScreen));
2124 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2125 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2126 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2127 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2128 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2129 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2130 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2131 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2132 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2133 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2135 if (appData.colorize) {
2137 _("%s: can't parse color names; disabling colorization\n"),
2140 appData.colorize = FALSE;
2142 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2143 textColors[ColorNone].attr = 0;
2145 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2151 layoutName = "tinyLayout";
2152 } else if (smallLayout) {
2153 layoutName = "smallLayout";
2155 layoutName = "normalLayout";
2157 /* Outer layoutWidget is there only to provide a name for use in
2158 resources that depend on the layout style */
2160 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2161 layoutArgs, XtNumber(layoutArgs));
2163 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2164 formArgs, XtNumber(formArgs));
2165 XtSetArg(args[0], XtNdefaultDistance, &sep);
2166 XtGetValues(formWidget, args, 1);
2169 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2170 XtSetArg(args[0], XtNtop, XtChainTop);
2171 XtSetArg(args[1], XtNbottom, XtChainTop);
2172 XtSetArg(args[2], XtNright, XtChainLeft);
2173 XtSetValues(menuBarWidget, args, 3);
2175 widgetList[j++] = whiteTimerWidget =
2176 XtCreateWidget("whiteTime", labelWidgetClass,
2177 formWidget, timerArgs, XtNumber(timerArgs));
2178 XtSetArg(args[0], XtNfont, clockFontStruct);
2179 XtSetArg(args[1], XtNtop, XtChainTop);
2180 XtSetArg(args[2], XtNbottom, XtChainTop);
2181 XtSetValues(whiteTimerWidget, args, 3);
2183 widgetList[j++] = blackTimerWidget =
2184 XtCreateWidget("blackTime", labelWidgetClass,
2185 formWidget, timerArgs, XtNumber(timerArgs));
2186 XtSetArg(args[0], XtNfont, clockFontStruct);
2187 XtSetArg(args[1], XtNtop, XtChainTop);
2188 XtSetArg(args[2], XtNbottom, XtChainTop);
2189 XtSetValues(blackTimerWidget, args, 3);
2191 if (appData.titleInWindow) {
2192 widgetList[j++] = titleWidget =
2193 XtCreateWidget("title", labelWidgetClass, formWidget,
2194 titleArgs, XtNumber(titleArgs));
2195 XtSetArg(args[0], XtNtop, XtChainTop);
2196 XtSetArg(args[1], XtNbottom, XtChainTop);
2197 XtSetValues(titleWidget, args, 2);
2200 if (appData.showButtonBar) {
2201 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2202 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2203 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2204 XtSetArg(args[2], XtNtop, XtChainTop);
2205 XtSetArg(args[3], XtNbottom, XtChainTop);
2206 XtSetValues(buttonBarWidget, args, 4);
2209 widgetList[j++] = messageWidget =
2210 XtCreateWidget("message", labelWidgetClass, formWidget,
2211 messageArgs, XtNumber(messageArgs));
2212 XtSetArg(args[0], XtNtop, XtChainTop);
2213 XtSetArg(args[1], XtNbottom, XtChainTop);
2214 XtSetValues(messageWidget, args, 2);
2216 widgetList[j++] = boardWidget =
2217 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2218 XtNumber(boardArgs));
2220 XtManageChildren(widgetList, j);
2222 timerWidth = (boardWidth - sep) / 2;
2223 XtSetArg(args[0], XtNwidth, timerWidth);
2224 XtSetValues(whiteTimerWidget, args, 1);
2225 XtSetValues(blackTimerWidget, args, 1);
2227 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2228 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2229 XtGetValues(whiteTimerWidget, args, 2);
2231 if (appData.showButtonBar) {
2232 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2233 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2234 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2238 * formWidget uses these constraints but they are stored
2242 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2243 XtSetValues(menuBarWidget, args, i);
2244 if (appData.titleInWindow) {
2247 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2248 XtSetValues(whiteTimerWidget, args, i);
2250 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2251 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2252 XtSetValues(blackTimerWidget, args, i);
2254 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2255 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2256 XtSetValues(titleWidget, args, i);
2258 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2259 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2260 XtSetValues(messageWidget, args, i);
2261 if (appData.showButtonBar) {
2263 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2264 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2265 XtSetValues(buttonBarWidget, args, i);
2269 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2270 XtSetValues(whiteTimerWidget, args, i);
2272 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2273 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2274 XtSetValues(blackTimerWidget, args, i);
2276 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2277 XtSetValues(titleWidget, args, i);
2279 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2280 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2281 XtSetValues(messageWidget, args, i);
2282 if (appData.showButtonBar) {
2284 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2285 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2286 XtSetValues(buttonBarWidget, args, i);
2291 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2292 XtSetValues(whiteTimerWidget, args, i);
2294 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2295 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2296 XtSetValues(blackTimerWidget, args, i);
2298 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2299 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2300 XtSetValues(messageWidget, args, i);
2301 if (appData.showButtonBar) {
2303 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2304 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2305 XtSetValues(buttonBarWidget, args, i);
2309 XtSetArg(args[0], XtNfromVert, messageWidget);
2310 XtSetArg(args[1], XtNtop, XtChainTop);
2311 XtSetArg(args[2], XtNbottom, XtChainBottom);
2312 XtSetArg(args[3], XtNleft, XtChainLeft);
2313 XtSetArg(args[4], XtNright, XtChainRight);
2314 XtSetValues(boardWidget, args, 5);
2316 XtRealizeWidget(shellWidget);
2319 XtSetArg(args[0], XtNx, wpMain.x);
2320 XtSetArg(args[1], XtNy, wpMain.y);
2321 XtSetValues(shellWidget, args, 2);
2325 * Correct the width of the message and title widgets.
2326 * It is not known why some systems need the extra fudge term.
2327 * The value "2" is probably larger than needed.
2329 XawFormDoLayout(formWidget, False);
2331 #define WIDTH_FUDGE 2
2333 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2334 XtSetArg(args[i], XtNheight, &h); i++;
2335 XtGetValues(messageWidget, args, i);
2336 if (appData.showButtonBar) {
2338 XtSetArg(args[i], XtNwidth, &w); i++;
2339 XtGetValues(buttonBarWidget, args, i);
2340 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2342 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2345 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2346 if (gres != XtGeometryYes && appData.debugMode) {
2347 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2348 programName, gres, w, h, wr, hr);
2351 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2352 /* The size used for the child widget in layout lags one resize behind
2353 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2355 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2356 if (gres != XtGeometryYes && appData.debugMode) {
2357 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2358 programName, gres, w, h, wr, hr);
2361 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2362 XtSetArg(args[1], XtNright, XtChainRight);
2363 XtSetValues(messageWidget, args, 2);
2365 if (appData.titleInWindow) {
2367 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2368 XtSetArg(args[i], XtNheight, &h); i++;
2369 XtGetValues(titleWidget, args, i);
2371 w = boardWidth - 2*bor;
2373 XtSetArg(args[0], XtNwidth, &w);
2374 XtGetValues(menuBarWidget, args, 1);
2375 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2378 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2379 if (gres != XtGeometryYes && appData.debugMode) {
2381 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2382 programName, gres, w, h, wr, hr);
2385 XawFormDoLayout(formWidget, True);
2387 xBoardWindow = XtWindow(boardWidget);
2389 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2390 // not need to go into InitDrawingSizes().
2394 * Create X checkmark bitmap and initialize option menu checks.
2396 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2397 checkmark_bits, checkmark_width, checkmark_height);
2398 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2399 if (appData.alwaysPromoteToQueen) {
2400 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2403 if (appData.animateDragging) {
2404 XtSetValues(XtNameToWidget(menuBarWidget,
2405 "menuOptions.Animate Dragging"),
2408 if (appData.animate) {
2409 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2412 if (appData.autoComment) {
2413 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2416 if (appData.autoCallFlag) {
2417 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2420 if (appData.autoFlipView) {
2421 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2424 if (appData.autoObserve) {
2425 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2428 if (appData.autoRaiseBoard) {
2429 XtSetValues(XtNameToWidget(menuBarWidget,
2430 "menuOptions.Auto Raise Board"), args, 1);
2432 if (appData.autoSaveGames) {
2433 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2436 if (appData.saveGameFile[0] != NULLCHAR) {
2437 /* Can't turn this off from menu */
2438 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2440 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2444 if (appData.blindfold) {
2445 XtSetValues(XtNameToWidget(menuBarWidget,
2446 "menuOptions.Blindfold"), args, 1);
2448 if (appData.flashCount > 0) {
2449 XtSetValues(XtNameToWidget(menuBarWidget,
2450 "menuOptions.Flash Moves"),
2453 if (appData.getMoveList) {
2454 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2458 if (appData.highlightDragging) {
2459 XtSetValues(XtNameToWidget(menuBarWidget,
2460 "menuOptions.Highlight Dragging"),
2464 if (appData.highlightLastMove) {
2465 XtSetValues(XtNameToWidget(menuBarWidget,
2466 "menuOptions.Highlight Last Move"),
2469 if (appData.highlightMoveWithArrow) {
2470 XtSetValues(XtNameToWidget(menuBarWidget,
2471 "menuOptions.Arrow"),
2474 if (appData.icsAlarm) {
2475 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2478 if (appData.ringBellAfterMoves) {
2479 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2482 if (appData.oneClick) {
2483 XtSetValues(XtNameToWidget(menuBarWidget,
2484 "menuOptions.OneClick"), args, 1);
2486 if (appData.periodicUpdates) {
2487 XtSetValues(XtNameToWidget(menuBarWidget,
2488 "menuOptions.Periodic Updates"), args, 1);
2490 if (appData.ponderNextMove) {
2491 XtSetValues(XtNameToWidget(menuBarWidget,
2492 "menuOptions.Ponder Next Move"), args, 1);
2494 if (appData.popupExitMessage) {
2495 XtSetValues(XtNameToWidget(menuBarWidget,
2496 "menuOptions.Popup Exit Message"), args, 1);
2498 if (appData.popupMoveErrors) {
2499 XtSetValues(XtNameToWidget(menuBarWidget,
2500 "menuOptions.Popup Move Errors"), args, 1);
2502 if (appData.premove) {
2503 XtSetValues(XtNameToWidget(menuBarWidget,
2504 "menuOptions.Premove"), args, 1);
2506 if (appData.quietPlay) {
2507 XtSetValues(XtNameToWidget(menuBarWidget,
2508 "menuOptions.Quiet Play"), args, 1);
2510 if (appData.showCoords) {
2511 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2514 if (appData.hideThinkingFromHuman) {
2515 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2518 if (appData.testLegality) {
2519 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2522 if (saveSettingsOnExit) {
2523 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2530 ReadBitmap(&wIconPixmap, "icon_white.bm",
2531 icon_white_bits, icon_white_width, icon_white_height);
2532 ReadBitmap(&bIconPixmap, "icon_black.bm",
2533 icon_black_bits, icon_black_width, icon_black_height);
2534 iconPixmap = wIconPixmap;
2536 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2537 XtSetValues(shellWidget, args, i);
2540 * Create a cursor for the board widget.
2542 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2543 XChangeWindowAttributes(xDisplay, xBoardWindow,
2544 CWCursor, &window_attributes);
2547 * Inhibit shell resizing.
2549 shellArgs[0].value = (XtArgVal) &w;
2550 shellArgs[1].value = (XtArgVal) &h;
2551 XtGetValues(shellWidget, shellArgs, 2);
2552 shellArgs[4].value = shellArgs[2].value = w;
2553 shellArgs[5].value = shellArgs[3].value = h;
2554 XtSetValues(shellWidget, &shellArgs[2], 4);
2555 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2556 marginH = h - boardHeight;
2558 CatchDeleteWindow(shellWidget, "QuitProc");
2563 if (appData.bitmapDirectory[0] != NULLCHAR) {
2567 CreateXPMBoard(appData.liteBackTextureFile, 1);
2568 CreateXPMBoard(appData.darkBackTextureFile, 0);
2572 /* Create regular pieces */
2573 if (!useImages) CreatePieces();
2578 if (appData.animate || appData.animateDragging)
2581 XtAugmentTranslations(formWidget,
2582 XtParseTranslationTable(globalTranslations));
2583 XtAugmentTranslations(boardWidget,
2584 XtParseTranslationTable(boardTranslations));
2585 XtAugmentTranslations(whiteTimerWidget,
2586 XtParseTranslationTable(whiteTranslations));
2587 XtAugmentTranslations(blackTimerWidget,
2588 XtParseTranslationTable(blackTranslations));
2590 /* Why is the following needed on some versions of X instead
2591 * of a translation? */
2592 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2593 (XtEventHandler) EventProc, NULL);
2596 /* [AS] Restore layout */
2597 if( wpMoveHistory.visible ) {
2601 if( wpEvalGraph.visible )
2606 if( wpEngineOutput.visible ) {
2607 EngineOutputPopUp();
2612 if (errorExitStatus == -1) {
2613 if (appData.icsActive) {
2614 /* We now wait until we see "login:" from the ICS before
2615 sending the logon script (problems with timestamp otherwise) */
2616 /*ICSInitScript();*/
2617 if (appData.icsInputBox) ICSInputBoxPopUp();
2621 signal(SIGWINCH, TermSizeSigHandler);
2623 signal(SIGINT, IntSigHandler);
2624 signal(SIGTERM, IntSigHandler);
2625 if (*appData.cmailGameName != NULLCHAR) {
2626 signal(SIGUSR1, CmailSigHandler);
2629 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2631 XtSetKeyboardFocus(shellWidget, formWidget);
2633 XtAppMainLoop(appContext);
2634 if (appData.debugMode) fclose(debugFP); // [DM] debug
2641 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2642 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2644 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2645 unlink(gameCopyFilename);
2646 unlink(gamePasteFilename);
2649 RETSIGTYPE TermSizeSigHandler(int sig)
2662 CmailSigHandler(sig)
2668 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2670 /* Activate call-back function CmailSigHandlerCallBack() */
2671 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2673 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2677 CmailSigHandlerCallBack(isr, closure, message, count, error)
2685 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2687 /**** end signal code ****/
2693 /* try to open the icsLogon script, either in the location given
2694 * or in the users HOME directory
2701 f = fopen(appData.icsLogon, "r");
2704 homedir = getenv("HOME");
2705 if (homedir != NULL)
2707 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2708 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2709 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2710 f = fopen(buf, "r");
2715 ProcessICSInitScript(f);
2717 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2726 EditCommentPopDown();
2741 if (!menuBarWidget) return;
2742 w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2744 DisplayError("menuEdit.Revert", 0);
2746 XtSetSensitive(w, !grey);
2748 w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2750 DisplayError("menuEdit.Annotate", 0);
2752 XtSetSensitive(w, !grey);
2757 SetMenuEnables(enab)
2761 if (!menuBarWidget) return;
2762 while (enab->name != NULL) {
2763 w = XtNameToWidget(menuBarWidget, enab->name);
2765 DisplayError(enab->name, 0);
2767 XtSetSensitive(w, enab->value);
2773 Enables icsEnables[] = {
2774 { "menuFile.Mail Move", False },
2775 { "menuFile.Reload CMail Message", False },
2776 { "menuMode.Machine Black", False },
2777 { "menuMode.Machine White", False },
2778 { "menuMode.Analysis Mode", False },
2779 { "menuMode.Analyze File", False },
2780 { "menuMode.Two Machines", False },
2782 { "menuEngine.Hint", False },
2783 { "menuEngine.Book", False },
2784 { "menuEngine.Move Now", False },
2785 { "menuOptions.Periodic Updates", False },
2786 { "menuOptions.Hide Thinking", False },
2787 { "menuOptions.Ponder Next Move", False },
2788 { "menuEngine.Engine #1 Settings", False },
2790 { "menuEngine.Engine #2 Settings", False },
2791 { "menuEdit.Annotate", False },
2795 Enables ncpEnables[] = {
2796 { "menuFile.Mail Move", False },
2797 { "menuFile.Reload CMail Message", False },
2798 { "menuMode.Machine White", False },
2799 { "menuMode.Machine Black", False },
2800 { "menuMode.Analysis Mode", False },
2801 { "menuMode.Analyze File", False },
2802 { "menuMode.Two Machines", False },
2803 { "menuMode.ICS Client", False },
2804 { "menuView.ICS Input Box", False },
2805 { "Action", False },
2806 { "menuEdit.Revert", False },
2807 { "menuEdit.Annotate", False },
2808 { "menuEngine.Engine #1 Settings", False },
2809 { "menuEngine.Engine #2 Settings", False },
2810 { "menuEngine.Move Now", False },
2811 { "menuEngine.Retract Move", False },
2812 { "menuOptions.Auto Comment", False },
2813 { "menuOptions.Auto Flag", False },
2814 { "menuOptions.Auto Flip View", False },
2815 { "menuOptions.Auto Observe", False },
2816 { "menuOptions.Auto Raise Board", False },
2817 { "menuOptions.Get Move List", False },
2818 { "menuOptions.ICS Alarm", False },
2819 { "menuOptions.Move Sound", False },
2820 { "menuOptions.Quiet Play", False },
2821 { "menuOptions.Hide Thinking", False },
2822 { "menuOptions.Periodic Updates", False },
2823 { "menuOptions.Ponder Next Move", False },
2824 { "menuEngine.Hint", False },
2825 { "menuEngine.Book", False },
2829 Enables gnuEnables[] = {
2830 { "menuMode.ICS Client", False },
2831 { "menuView.ICS Input Box", False },
2832 { "menuAction.Accept", False },
2833 { "menuAction.Decline", False },
2834 { "menuAction.Rematch", False },
2835 { "menuAction.Adjourn", False },
2836 { "menuAction.Stop Examining", False },
2837 { "menuAction.Stop Observing", False },
2838 { "menuAction.Upload to Examine", False },
2839 { "menuEdit.Revert", False },
2840 { "menuEdit.Annotate", False },
2841 { "menuOptions.Auto Comment", False },
2842 { "menuOptions.Auto Observe", False },
2843 { "menuOptions.Auto Raise Board", False },
2844 { "menuOptions.Get Move List", False },
2845 { "menuOptions.Premove", False },
2846 { "menuOptions.Quiet Play", False },
2848 /* The next two options rely on SetCmailMode being called *after* */
2849 /* SetGNUMode so that when GNU is being used to give hints these */
2850 /* menu options are still available */
2852 { "menuFile.Mail Move", False },
2853 { "menuFile.Reload CMail Message", False },
2857 Enables cmailEnables[] = {
2859 { "menuAction.Call Flag", False },
2860 { "menuAction.Draw", True },
2861 { "menuAction.Adjourn", False },
2862 { "menuAction.Abort", False },
2863 { "menuAction.Stop Observing", False },
2864 { "menuAction.Stop Examining", False },
2865 { "menuFile.Mail Move", True },
2866 { "menuFile.Reload CMail Message", True },
2870 Enables trainingOnEnables[] = {
2871 { "menuMode.Edit Comment", False },
2872 { "menuMode.Pause", False },
2873 { "menuEdit.Forward", False },
2874 { "menuEdit.Backward", False },
2875 { "menuEdit.Forward to End", False },
2876 { "menuEdit.Back to Start", False },
2877 { "menuEngine.Move Now", False },
2878 { "menuEdit.Truncate Game", False },
2882 Enables trainingOffEnables[] = {
2883 { "menuMode.Edit Comment", True },
2884 { "menuMode.Pause", True },
2885 { "menuEdit.Forward", True },
2886 { "menuEdit.Backward", True },
2887 { "menuEdit.Forward to End", True },
2888 { "menuEdit.Back to Start", True },
2889 { "menuEngine.Move Now", True },
2890 { "menuEdit.Truncate Game", True },
2894 Enables machineThinkingEnables[] = {
2895 { "menuFile.Load Game", False },
2896 // { "menuFile.Load Next Game", False },
2897 // { "menuFile.Load Previous Game", False },
2898 // { "menuFile.Reload Same Game", False },
2899 { "menuEdit.Paste Game", False },
2900 { "menuFile.Load Position", False },
2901 // { "menuFile.Load Next Position", False },
2902 // { "menuFile.Load Previous Position", False },
2903 // { "menuFile.Reload Same Position", False },
2904 { "menuEdit.Paste Position", False },
2905 { "menuMode.Machine White", False },
2906 { "menuMode.Machine Black", False },
2907 { "menuMode.Two Machines", False },
2908 { "menuEngine.Retract Move", False },
2912 Enables userThinkingEnables[] = {
2913 { "menuFile.Load Game", True },
2914 // { "menuFile.Load Next Game", True },
2915 // { "menuFile.Load Previous Game", True },
2916 // { "menuFile.Reload Same Game", True },
2917 { "menuEdit.Paste Game", True },
2918 { "menuFile.Load Position", True },
2919 // { "menuFile.Load Next Position", True },
2920 // { "menuFile.Load Previous Position", True },
2921 // { "menuFile.Reload Same Position", True },
2922 { "menuEdit.Paste Position", True },
2923 { "menuMode.Machine White", True },
2924 { "menuMode.Machine Black", True },
2925 { "menuMode.Two Machines", True },
2926 { "menuEngine.Retract Move", True },
2932 SetMenuEnables(icsEnables);
2935 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2936 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2943 SetMenuEnables(ncpEnables);
2949 SetMenuEnables(gnuEnables);
2955 SetMenuEnables(cmailEnables);
2961 SetMenuEnables(trainingOnEnables);
2962 if (appData.showButtonBar) {
2963 XtSetSensitive(buttonBarWidget, False);
2969 SetTrainingModeOff()
2971 SetMenuEnables(trainingOffEnables);
2972 if (appData.showButtonBar) {
2973 XtSetSensitive(buttonBarWidget, True);
2978 SetUserThinkingEnables()
2980 if (appData.noChessProgram) return;
2981 SetMenuEnables(userThinkingEnables);
2985 SetMachineThinkingEnables()
2987 if (appData.noChessProgram) return;
2988 SetMenuEnables(machineThinkingEnables);
2990 case MachinePlaysBlack:
2991 case MachinePlaysWhite:
2992 case TwoMachinesPlay:
2993 XtSetSensitive(XtNameToWidget(menuBarWidget,
2994 ModeToWidgetName(gameMode)), True);
3001 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
3002 #define HISTORY_SIZE 64
3003 static char *history[HISTORY_SIZE];
3004 int histIn = 0, histP = 0;
3007 SaveInHistory(char *cmd)
3009 if (history[histIn] != NULL) {
3010 free(history[histIn]);
3011 history[histIn] = NULL;
3013 if (*cmd == NULLCHAR) return;
3014 history[histIn] = StrSave(cmd);
3015 histIn = (histIn + 1) % HISTORY_SIZE;
3016 if (history[histIn] != NULL) {
3017 free(history[histIn]);
3018 history[histIn] = NULL;
3024 PrevInHistory(char *cmd)
3027 if (histP == histIn) {
3028 if (history[histIn] != NULL) free(history[histIn]);
3029 history[histIn] = StrSave(cmd);
3031 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
3032 if (newhp == histIn || history[newhp] == NULL) return NULL;
3034 return history[histP];
3040 if (histP == histIn) return NULL;
3041 histP = (histP + 1) % HISTORY_SIZE;
3042 return history[histP];
3044 // end of borrowed code
3046 #define Abs(n) ((n)<0 ? -(n) : (n))
3049 * Find a font that matches "pattern" that is as close as
3050 * possible to the targetPxlSize. Prefer fonts that are k
3051 * pixels smaller to fonts that are k pixels larger. The
3052 * pattern must be in the X Consortium standard format,
3053 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3054 * The return value should be freed with XtFree when no
3058 FindFont(pattern, targetPxlSize)
3062 char **fonts, *p, *best, *scalable, *scalableTail;
3063 int i, j, nfonts, minerr, err, pxlSize;
3066 char **missing_list;
3068 char *def_string, *base_fnt_lst, strInt[3];
3070 XFontStruct **fnt_list;
3072 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3073 snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize);
3074 p = strstr(pattern, "--");
3075 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3076 strcat(base_fnt_lst, strInt);
3077 strcat(base_fnt_lst, strchr(p + 2, '-'));
3079 if ((fntSet = XCreateFontSet(xDisplay,
3083 &def_string)) == NULL) {
3085 fprintf(stderr, _("Unable to create font set.\n"));
3089 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3091 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3093 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3094 programName, pattern);
3102 for (i=0; i<nfonts; i++) {
3105 if (*p != '-') continue;
3107 if (*p == NULLCHAR) break;
3108 if (*p++ == '-') j++;
3110 if (j < 7) continue;
3113 scalable = fonts[i];
3116 err = pxlSize - targetPxlSize;
3117 if (Abs(err) < Abs(minerr) ||
3118 (minerr > 0 && err < 0 && -err == minerr)) {
3124 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3125 /* If the error is too big and there is a scalable font,
3126 use the scalable font. */
3127 int headlen = scalableTail - scalable;
3128 p = (char *) XtMalloc(strlen(scalable) + 10);
3129 while (isdigit(*scalableTail)) scalableTail++;
3130 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3132 p = (char *) XtMalloc(strlen(best) + 2);
3133 safeStrCpy(p, best, strlen(best)+1 );
3135 if (appData.debugMode) {
3136 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3137 pattern, targetPxlSize, p);
3140 if (missing_count > 0)
3141 XFreeStringList(missing_list);
3142 XFreeFontSet(xDisplay, fntSet);
3144 XFreeFontNames(fonts);
3151 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3152 | GCBackground | GCFunction | GCPlaneMask;
3153 XGCValues gc_values;
3156 gc_values.plane_mask = AllPlanes;
3157 gc_values.line_width = lineGap;
3158 gc_values.line_style = LineSolid;
3159 gc_values.function = GXcopy;
3161 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3162 gc_values.background = XBlackPixel(xDisplay, xScreen);
3163 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3165 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3166 gc_values.background = XWhitePixel(xDisplay, xScreen);
3167 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3168 XSetFont(xDisplay, coordGC, coordFontID);
3170 // [HGM] make font for holdings counts (white on black0
3171 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3172 gc_values.background = XBlackPixel(xDisplay, xScreen);
3173 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3174 XSetFont(xDisplay, countGC, countFontID);
3176 if (appData.monoMode) {
3177 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3178 gc_values.background = XWhitePixel(xDisplay, xScreen);
3179 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3181 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3182 gc_values.background = XBlackPixel(xDisplay, xScreen);
3183 lightSquareGC = wbPieceGC
3184 = XtGetGC(shellWidget, value_mask, &gc_values);
3186 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3187 gc_values.background = XWhitePixel(xDisplay, xScreen);
3188 darkSquareGC = bwPieceGC
3189 = XtGetGC(shellWidget, value_mask, &gc_values);
3191 if (DefaultDepth(xDisplay, xScreen) == 1) {
3192 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3193 gc_values.function = GXcopyInverted;
3194 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3195 gc_values.function = GXcopy;
3196 if (XBlackPixel(xDisplay, xScreen) == 1) {
3197 bwPieceGC = darkSquareGC;
3198 wbPieceGC = copyInvertedGC;
3200 bwPieceGC = copyInvertedGC;
3201 wbPieceGC = lightSquareGC;
3205 gc_values.foreground = highlightSquareColor;
3206 gc_values.background = highlightSquareColor;
3207 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3209 gc_values.foreground = premoveHighlightColor;
3210 gc_values.background = premoveHighlightColor;
3211 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3213 gc_values.foreground = lightSquareColor;
3214 gc_values.background = darkSquareColor;
3215 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3217 gc_values.foreground = darkSquareColor;
3218 gc_values.background = lightSquareColor;
3219 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3221 gc_values.foreground = jailSquareColor;
3222 gc_values.background = jailSquareColor;
3223 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3225 gc_values.foreground = whitePieceColor;
3226 gc_values.background = darkSquareColor;
3227 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3229 gc_values.foreground = whitePieceColor;
3230 gc_values.background = lightSquareColor;
3231 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3233 gc_values.foreground = whitePieceColor;
3234 gc_values.background = jailSquareColor;
3235 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3237 gc_values.foreground = blackPieceColor;
3238 gc_values.background = darkSquareColor;
3239 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3241 gc_values.foreground = blackPieceColor;
3242 gc_values.background = lightSquareColor;
3243 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3245 gc_values.foreground = blackPieceColor;
3246 gc_values.background = jailSquareColor;
3247 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3251 void loadXIM(xim, xmask, filename, dest, mask)
3264 fp = fopen(filename, "rb");
3266 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3273 for (y=0; y<h; ++y) {
3274 for (x=0; x<h; ++x) {
3279 XPutPixel(xim, x, y, blackPieceColor);
3281 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3284 XPutPixel(xim, x, y, darkSquareColor);
3286 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3289 XPutPixel(xim, x, y, whitePieceColor);
3291 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3294 XPutPixel(xim, x, y, lightSquareColor);
3296 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3304 /* create Pixmap of piece */
3305 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3307 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3310 /* create Pixmap of clipmask
3311 Note: We assume the white/black pieces have the same
3312 outline, so we make only 6 masks. This is okay
3313 since the XPM clipmask routines do the same. */
3315 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3317 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3320 /* now create the 1-bit version */
3321 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3324 values.foreground = 1;
3325 values.background = 0;
3327 /* Don't use XtGetGC, not read only */
3328 maskGC = XCreateGC(xDisplay, *mask,
3329 GCForeground | GCBackground, &values);
3330 XCopyPlane(xDisplay, temp, *mask, maskGC,
3331 0, 0, squareSize, squareSize, 0, 0, 1);
3332 XFreePixmap(xDisplay, temp);
3337 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3339 void CreateXIMPieces()
3344 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3349 /* The XSynchronize calls were copied from CreatePieces.
3350 Not sure if needed, but can't hurt */
3351 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3354 /* temp needed by loadXIM() */
3355 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3356 0, 0, ss, ss, AllPlanes, XYPixmap);
3358 if (strlen(appData.pixmapDirectory) == 0) {
3362 if (appData.monoMode) {
3363 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3367 fprintf(stderr, _("\nLoading XIMs...\n"));
3369 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3370 fprintf(stderr, "%d", piece+1);
3371 for (kind=0; kind<4; kind++) {
3372 fprintf(stderr, ".");
3373 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3374 ExpandPathName(appData.pixmapDirectory),
3375 piece <= (int) WhiteKing ? "" : "w",
3376 pieceBitmapNames[piece],
3378 ximPieceBitmap[kind][piece] =
3379 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3380 0, 0, ss, ss, AllPlanes, XYPixmap);
3381 if (appData.debugMode)
3382 fprintf(stderr, _("(File:%s:) "), buf);
3383 loadXIM(ximPieceBitmap[kind][piece],
3385 &(xpmPieceBitmap2[kind][piece]),
3386 &(ximMaskPm2[piece]));
3387 if(piece <= (int)WhiteKing)
3388 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3390 fprintf(stderr," ");
3392 /* Load light and dark squares */
3393 /* If the LSQ and DSQ pieces don't exist, we will
3394 draw them with solid squares. */
3395 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3396 if (access(buf, 0) != 0) {
3400 fprintf(stderr, _("light square "));
3402 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3403 0, 0, ss, ss, AllPlanes, XYPixmap);
3404 if (appData.debugMode)
3405 fprintf(stderr, _("(File:%s:) "), buf);
3407 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3408 fprintf(stderr, _("dark square "));
3409 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3410 ExpandPathName(appData.pixmapDirectory), ss);
3411 if (appData.debugMode)
3412 fprintf(stderr, _("(File:%s:) "), buf);
3414 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3415 0, 0, ss, ss, AllPlanes, XYPixmap);
3416 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3417 xpmJailSquare = xpmLightSquare;
3419 fprintf(stderr, _("Done.\n"));
3421 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3425 void CreateXPMBoard(char *s, int kind)
3429 if(s == NULL || *s == 0 || *s == '*') return;
3430 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3431 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3435 void CreateXPMPieces()
3439 u_int ss = squareSize;
3441 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3442 XpmColorSymbol symbols[4];
3444 /* The XSynchronize calls were copied from CreatePieces.
3445 Not sure if needed, but can't hurt */
3446 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3448 /* Setup translations so piece colors match square colors */
3449 symbols[0].name = "light_piece";
3450 symbols[0].value = appData.whitePieceColor;
3451 symbols[1].name = "dark_piece";
3452 symbols[1].value = appData.blackPieceColor;
3453 symbols[2].name = "light_square";
3454 symbols[2].value = appData.lightSquareColor;
3455 symbols[3].name = "dark_square";
3456 symbols[3].value = appData.darkSquareColor;
3458 attr.valuemask = XpmColorSymbols;
3459 attr.colorsymbols = symbols;
3460 attr.numsymbols = 4;
3462 if (appData.monoMode) {
3463 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3467 if (strlen(appData.pixmapDirectory) == 0) {
3468 XpmPieces* pieces = builtInXpms;
3471 while (pieces->size != squareSize && pieces->size) pieces++;
3472 if (!pieces->size) {
3473 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3476 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3477 for (kind=0; kind<4; kind++) {
3479 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3480 pieces->xpm[piece][kind],
3481 &(xpmPieceBitmap2[kind][piece]),
3482 NULL, &attr)) != 0) {
3483 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3487 if(piece <= (int) WhiteKing)
3488 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3492 xpmJailSquare = xpmLightSquare;
3496 fprintf(stderr, _("\nLoading XPMs...\n"));
3499 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3500 fprintf(stderr, "%d ", piece+1);
3501 for (kind=0; kind<4; kind++) {
3502 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3503 ExpandPathName(appData.pixmapDirectory),
3504 piece > (int) WhiteKing ? "w" : "",
3505 pieceBitmapNames[piece],
3507 if (appData.debugMode) {
3508 fprintf(stderr, _("(File:%s:) "), buf);
3510 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3511 &(xpmPieceBitmap2[kind][piece]),
3512 NULL, &attr)) != 0) {
3513 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3514 // [HGM] missing: read of unorthodox piece failed; substitute King.
3515 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3516 ExpandPathName(appData.pixmapDirectory),
3518 if (appData.debugMode) {
3519 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3521 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3522 &(xpmPieceBitmap2[kind][piece]),
3526 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3531 if(piece <= (int) WhiteKing)
3532 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3535 /* Load light and dark squares */
3536 /* If the LSQ and DSQ pieces don't exist, we will
3537 draw them with solid squares. */
3538 fprintf(stderr, _("light square "));
3539 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3540 if (access(buf, 0) != 0) {
3544 if (appData.debugMode)
3545 fprintf(stderr, _("(File:%s:) "), buf);
3547 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3548 &xpmLightSquare, NULL, &attr)) != 0) {
3549 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3552 fprintf(stderr, _("dark square "));
3553 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3554 ExpandPathName(appData.pixmapDirectory), ss);
3555 if (appData.debugMode) {
3556 fprintf(stderr, _("(File:%s:) "), buf);
3558 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3559 &xpmDarkSquare, NULL, &attr)) != 0) {
3560 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3564 xpmJailSquare = xpmLightSquare;
3565 fprintf(stderr, _("Done.\n"));
3567 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3570 #endif /* HAVE_LIBXPM */
3573 /* No built-in bitmaps */
3578 u_int ss = squareSize;
3580 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3583 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3584 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3585 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3586 pieceBitmapNames[piece],
3587 ss, kind == SOLID ? 's' : 'o');
3588 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3589 if(piece <= (int)WhiteKing)
3590 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3594 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3598 /* With built-in bitmaps */
3601 BuiltInBits* bib = builtInBits;
3604 u_int ss = squareSize;
3606 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3609 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3611 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3612 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3613 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3614 pieceBitmapNames[piece],
3615 ss, kind == SOLID ? 's' : 'o');
3616 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3617 bib->bits[kind][piece], ss, ss);
3618 if(piece <= (int)WhiteKing)
3619 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3623 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3628 void ReadBitmap(pm, name, bits, wreq, hreq)
3631 unsigned char bits[];
3637 char msg[MSG_SIZ], fullname[MSG_SIZ];
3639 if (*appData.bitmapDirectory != NULLCHAR) {
3640 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3641 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3642 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3643 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3644 &w, &h, pm, &x_hot, &y_hot);
3645 fprintf(stderr, "load %s\n", name);
3646 if (errcode != BitmapSuccess) {
3648 case BitmapOpenFailed:
3649 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3651 case BitmapFileInvalid:
3652 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3654 case BitmapNoMemory:
3655 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3659 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3663 fprintf(stderr, _("%s: %s...using built-in\n"),
3665 } else if (w != wreq || h != hreq) {
3667 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3668 programName, fullname, w, h, wreq, hreq);
3674 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3683 if (lineGap == 0) return;
3685 /* [HR] Split this into 2 loops for non-square boards. */
3687 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3688 gridSegments[i].x1 = 0;
3689 gridSegments[i].x2 =
3690 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3691 gridSegments[i].y1 = gridSegments[i].y2
3692 = lineGap / 2 + (i * (squareSize + lineGap));
3695 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3696 gridSegments[j + i].y1 = 0;
3697 gridSegments[j + i].y2 =
3698 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3699 gridSegments[j + i].x1 = gridSegments[j + i].x2
3700 = lineGap / 2 + (j * (squareSize + lineGap));
3704 static void MenuBarSelect(w, addr, index)
3709 XtActionProc proc = (XtActionProc) addr;
3711 (proc)(NULL, NULL, NULL, NULL);
3714 void CreateMenuBarPopup(parent, name, mb)
3724 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3727 XtSetArg(args[j], XtNleftMargin, 20); j++;
3728 XtSetArg(args[j], XtNrightMargin, 20); j++;
3730 while (mi->string != NULL) {
3731 if (strcmp(mi->string, "----") == 0) {
3732 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3735 XtSetArg(args[j], XtNlabel, XtNewString(mi->string));
3736 entry = XtCreateManagedWidget(mi->ref, smeBSBObjectClass,
3738 XtAddCallback(entry, XtNcallback,
3739 (XtCallbackProc) MenuBarSelect,
3740 (caddr_t) mi->proc);
3746 Widget CreateMenuBar(mb)
3750 Widget anchor, menuBar;
3752 char menuName[MSG_SIZ];
3755 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3756 XtSetArg(args[j], XtNvSpace, 0); j++;
3757 XtSetArg(args[j], XtNborderWidth, 0); j++;
3758 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3759 formWidget, args, j);
3761 while (mb->name != NULL) {
3762 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3763 strncat(menuName, mb->ref, MSG_SIZ - strlen(menuName) - 1);
3765 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3768 shortName[0] = mb->name[0];
3769 shortName[1] = NULLCHAR;
3770 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3773 XtSetArg(args[j], XtNlabel, XtNewString(mb->name)); j++;
3776 XtSetArg(args[j], XtNborderWidth, 0); j++;
3777 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3779 CreateMenuBarPopup(menuBar, menuName, mb);
3785 Widget CreateButtonBar(mi)
3789 Widget button, buttonBar;
3793 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3795 XtSetArg(args[j], XtNhSpace, 0); j++;
3797 XtSetArg(args[j], XtNborderWidth, 0); j++;
3798 XtSetArg(args[j], XtNvSpace, 0); j++;
3799 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3800 formWidget, args, j);
3802 while (mi->string != NULL) {
3805 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3806 XtSetArg(args[j], XtNborderWidth, 0); j++;
3808 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3809 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3810 buttonBar, args, j);
3811 XtAddCallback(button, XtNcallback,
3812 (XtCallbackProc) MenuBarSelect,
3813 (caddr_t) mi->proc);
3820 CreatePieceMenu(name, color)
3827 ChessSquare selection;
3829 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3830 boardWidget, args, 0);
3832 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3833 String item = pieceMenuStrings[color][i];
3835 if (strcmp(item, "----") == 0) {
3836 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3839 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3840 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3842 selection = pieceMenuTranslation[color][i];
3843 XtAddCallback(entry, XtNcallback,
3844 (XtCallbackProc) PieceMenuSelect,
3845 (caddr_t) selection);
3846 if (selection == WhitePawn || selection == BlackPawn) {
3847 XtSetArg(args[0], XtNpopupOnEntry, entry);
3848 XtSetValues(menu, args, 1);
3861 ChessSquare selection;
3863 whitePieceMenu = CreatePieceMenu("menuW", 0);
3864 blackPieceMenu = CreatePieceMenu("menuB", 1);
3866 XtRegisterGrabAction(PieceMenuPopup, True,
3867 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3868 GrabModeAsync, GrabModeAsync);
3870 XtSetArg(args[0], XtNlabel, _("Drop"));
3871 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3872 boardWidget, args, 1);
3873 for (i = 0; i < DROP_MENU_SIZE; i++) {
3874 String item = dropMenuStrings[i];
3876 if (strcmp(item, "----") == 0) {
3877 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3880 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3881 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3883 selection = dropMenuTranslation[i];
3884 XtAddCallback(entry, XtNcallback,
3885 (XtCallbackProc) DropMenuSelect,
3886 (caddr_t) selection);
3891 void SetupDropMenu()
3899 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3900 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3901 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3902 dmEnables[i].piece);
3903 XtSetSensitive(entry, p != NULL || !appData.testLegality
3904 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3905 && !appData.icsActive));
3907 while (p && *p++ == dmEnables[i].piece) count++;
3908 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3910 XtSetArg(args[j], XtNlabel, label); j++;
3911 XtSetValues(entry, args, j);
3915 void PieceMenuPopup(w, event, params, num_params)
3919 Cardinal *num_params;
3921 String whichMenu; int menuNr;
3922 if (event->type == ButtonRelease)
3923 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3924 else if (event->type == ButtonPress)
3925 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3927 case 0: whichMenu = params[0]; break;
3928 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3930 case -1: if (errorUp) ErrorPopDown();
3933 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3936 static void PieceMenuSelect(w, piece, junk)
3941 if (pmFromX < 0 || pmFromY < 0) return;
3942 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3945 static void DropMenuSelect(w, piece, junk)
3950 if (pmFromX < 0 || pmFromY < 0) return;
3951 DropMenuEvent(piece, pmFromX, pmFromY);
3954 void WhiteClock(w, event, prms, nprms)
3963 void BlackClock(w, event, prms, nprms)
3974 * If the user selects on a border boundary, return -1; if off the board,
3975 * return -2. Otherwise map the event coordinate to the square.
3977 int EventToSquare(x, limit)
3985 if ((x % (squareSize + lineGap)) >= squareSize)
3987 x /= (squareSize + lineGap);
3993 static void do_flash_delay(msec)
3999 static void drawHighlight(file, rank, gc)
4005 if (lineGap == 0) return;
4008 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
4009 (squareSize + lineGap);
4010 y = lineGap/2 + rank * (squareSize + lineGap);
4012 x = lineGap/2 + file * (squareSize + lineGap);
4013 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
4014 (squareSize + lineGap);
4017 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
4018 squareSize+lineGap, squareSize+lineGap);
4021 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
4022 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4025 SetHighlights(fromX, fromY, toX, toY)
4026 int fromX, fromY, toX, toY;
4028 if (hi1X != fromX || hi1Y != fromY) {
4029 if (hi1X >= 0 && hi1Y >= 0) {
4030 drawHighlight(hi1X, hi1Y, lineGC);
4032 } // [HGM] first erase both, then draw new!
4033 if (hi2X != toX || hi2Y != toY) {
4034 if (hi2X >= 0 && hi2Y >= 0) {
4035 drawHighlight(hi2X, hi2Y, lineGC);
4038 if (hi1X != fromX || hi1Y != fromY) {
4039 if (fromX >= 0 && fromY >= 0) {
4040 drawHighlight(fromX, fromY, highlineGC);
4043 if (hi2X != toX || hi2Y != toY) {
4044 if (toX >= 0 && toY >= 0) {
4045 drawHighlight(toX, toY, highlineGC);
4057 SetHighlights(-1, -1, -1, -1);
4062 SetPremoveHighlights(fromX, fromY, toX, toY)
4063 int fromX, fromY, toX, toY;
4065 if (pm1X != fromX || pm1Y != fromY) {
4066 if (pm1X >= 0 && pm1Y >= 0) {
4067 drawHighlight(pm1X, pm1Y, lineGC);
4069 if (fromX >= 0 && fromY >= 0) {
4070 drawHighlight(fromX, fromY, prelineGC);
4073 if (pm2X != toX || pm2Y != toY) {
4074 if (pm2X >= 0 && pm2Y >= 0) {
4075 drawHighlight(pm2X, pm2Y, lineGC);
4077 if (toX >= 0 && toY >= 0) {
4078 drawHighlight(toX, toY, prelineGC);
4088 ClearPremoveHighlights()
4090 SetPremoveHighlights(-1, -1, -1, -1);
4093 static int CutOutSquare(x, y, x0, y0, kind)
4094 int x, y, *x0, *y0, kind;
4096 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
4097 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
4099 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
4100 if(textureW[kind] < W*squareSize)
4101 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
4103 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
4104 if(textureH[kind] < H*squareSize)
4105 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
4107 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
4111 static void BlankSquare(x, y, color, piece, dest, fac)
4112 int x, y, color, fac;
4115 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
4117 if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
4118 XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
4119 squareSize, squareSize, x*fac, y*fac);
4121 if (useImages && useImageSqs) {
4125 pm = xpmLightSquare;
4130 case 2: /* neutral */
4135 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4136 squareSize, squareSize, x*fac, y*fac);
4146 case 2: /* neutral */
4151 XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
4156 I split out the routines to draw a piece so that I could
4157 make a generic flash routine.
4159 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4161 int square_color, x, y;
4164 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4165 switch (square_color) {
4167 case 2: /* neutral */
4169 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4170 ? *pieceToOutline(piece)
4171 : *pieceToSolid(piece),
4172 dest, bwPieceGC, 0, 0,
4173 squareSize, squareSize, x, y);
4176 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4177 ? *pieceToSolid(piece)
4178 : *pieceToOutline(piece),
4179 dest, wbPieceGC, 0, 0,
4180 squareSize, squareSize, x, y);
4185 static void monoDrawPiece(piece, square_color, x, y, dest)
4187 int square_color, x, y;
4190 switch (square_color) {
4192 case 2: /* neutral */
4194 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4195 ? *pieceToOutline(piece)
4196 : *pieceToSolid(piece),
4197 dest, bwPieceGC, 0, 0,
4198 squareSize, squareSize, x, y, 1);
4201 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4202 ? *pieceToSolid(piece)
4203 : *pieceToOutline(piece),
4204 dest, wbPieceGC, 0, 0,
4205 squareSize, squareSize, x, y, 1);
4210 static void colorDrawPiece(piece, square_color, x, y, dest)
4212 int square_color, x, y;
4215 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4216 switch (square_color) {
4218 XCopyPlane(xDisplay, *pieceToSolid(piece),
4219 dest, (int) piece < (int) BlackPawn
4220 ? wlPieceGC : blPieceGC, 0, 0,
4221 squareSize, squareSize, x, y, 1);
4224 XCopyPlane(xDisplay, *pieceToSolid(piece),
4225 dest, (int) piece < (int) BlackPawn
4226 ? wdPieceGC : bdPieceGC, 0, 0,
4227 squareSize, squareSize, x, y, 1);
4229 case 2: /* neutral */
4231 XCopyPlane(xDisplay, *pieceToSolid(piece),
4232 dest, (int) piece < (int) BlackPawn
4233 ? wjPieceGC : bjPieceGC, 0, 0,
4234 squareSize, squareSize, x, y, 1);
4239 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4241 int square_color, x, y;
4244 int kind, p = piece;
4246 switch (square_color) {
4248 case 2: /* neutral */
4250 if ((int)piece < (int) BlackPawn) {
4258 if ((int)piece < (int) BlackPawn) {
4266 if(appData.upsideDown && flipView) kind ^= 2; // swap white and black pieces
4267 if(useTexture & square_color+1) {
4268 BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background
4269 XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]);
4270 XSetClipOrigin(xDisplay, wlPieceGC, x, y);
4271 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y);
4272 XSetClipMask(xDisplay, wlPieceGC, None);
4273 XSetClipOrigin(xDisplay, wlPieceGC, 0, 0);
4275 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4276 dest, wlPieceGC, 0, 0,
4277 squareSize, squareSize, x, y);
4280 typedef void (*DrawFunc)();
4282 DrawFunc ChooseDrawFunc()
4284 if (appData.monoMode) {
4285 if (DefaultDepth(xDisplay, xScreen) == 1) {
4286 return monoDrawPiece_1bit;
4288 return monoDrawPiece;
4292 return colorDrawPieceImage;
4294 return colorDrawPiece;
4298 /* [HR] determine square color depending on chess variant. */
4299 static int SquareColor(row, column)
4304 if (gameInfo.variant == VariantXiangqi) {
4305 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4307 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4309 } else if (row <= 4) {
4315 square_color = ((column + row) % 2) == 1;
4318 /* [hgm] holdings: next line makes all holdings squares light */
4319 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4321 return square_color;
4324 void DrawSquare(row, column, piece, do_flash)
4325 int row, column, do_flash;
4328 int square_color, x, y, direction, font_ascent, font_descent;
4331 XCharStruct overall;
4335 /* Calculate delay in milliseconds (2-delays per complete flash) */
4336 flash_delay = 500 / appData.flashRate;
4339 x = lineGap + ((BOARD_WIDTH-1)-column) *
4340 (squareSize + lineGap);
4341 y = lineGap + row * (squareSize + lineGap);
4343 x = lineGap + column * (squareSize + lineGap);
4344 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4345 (squareSize + lineGap);
4348 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4350 square_color = SquareColor(row, column);
4352 if ( // [HGM] holdings: blank out area between board and holdings
4353 column == BOARD_LEFT-1 || column == BOARD_RGHT
4354 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4355 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4356 BlankSquare(x, y, 2, EmptySquare, xBoardWindow, 1);
4358 // [HGM] print piece counts next to holdings
4359 string[1] = NULLCHAR;
4360 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4361 string[0] = '0' + piece;
4362 XTextExtents(countFontStruct, string, 1, &direction,
4363 &font_ascent, &font_descent, &overall);
4364 if (appData.monoMode) {
4365 XDrawImageString(xDisplay, xBoardWindow, countGC,
4366 x + squareSize - overall.width - 2,
4367 y + font_ascent + 1, string, 1);
4369 XDrawString(xDisplay, xBoardWindow, countGC,
4370 x + squareSize - overall.width - 2,
4371 y + font_ascent + 1, string, 1);
4374 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4375 string[0] = '0' + piece;
4376 XTextExtents(countFontStruct, string, 1, &direction,
4377 &font_ascent, &font_descent, &overall);
4378 if (appData.monoMode) {
4379 XDrawImageString(xDisplay, xBoardWindow, countGC,
4380 x + 2, y + font_ascent + 1, string, 1);
4382 XDrawString(xDisplay, xBoardWindow, countGC,
4383 x + 2, y + font_ascent + 1, string, 1);
4387 if (piece == EmptySquare || appData.blindfold) {
4388 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4390 drawfunc = ChooseDrawFunc();
4391 if (do_flash && appData.flashCount > 0) {
4392 for (i=0; i<appData.flashCount; ++i) {
4394 drawfunc(piece, square_color, x, y, xBoardWindow);
4395 XSync(xDisplay, False);
4396 do_flash_delay(flash_delay);
4398 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4399 XSync(xDisplay, False);
4400 do_flash_delay(flash_delay);
4403 drawfunc(piece, square_color, x, y, xBoardWindow);
4407 string[1] = NULLCHAR;
4408 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4409 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4410 string[0] = 'a' + column - BOARD_LEFT;
4411 XTextExtents(coordFontStruct, string, 1, &direction,
4412 &font_ascent, &font_descent, &overall);
4413 if (appData.monoMode) {
4414 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4415 x + squareSize - overall.width - 2,
4416 y + squareSize - font_descent - 1, string, 1);
4418 XDrawString(xDisplay, xBoardWindow, coordGC,
4419 x + squareSize - overall.width - 2,
4420 y + squareSize - font_descent - 1, string, 1);
4423 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4424 string[0] = ONE + row;
4425 XTextExtents(coordFontStruct, string, 1, &direction,
4426 &font_ascent, &font_descent, &overall);
4427 if (appData.monoMode) {
4428 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4429 x + 2, y + font_ascent + 1, string, 1);
4431 XDrawString(xDisplay, xBoardWindow, coordGC,
4432 x + 2, y + font_ascent + 1, string, 1);
4435 if(!partnerUp && marker[row][column]) {
4436 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4437 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4442 /* Why is this needed on some versions of X? */
4443 void EventProc(widget, unused, event)
4448 if (!XtIsRealized(widget))
4451 switch (event->type) {
4453 if (event->xexpose.count > 0) return; /* no clipping is done */
4454 XDrawPosition(widget, True, NULL);
4455 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4456 flipView = !flipView; partnerUp = !partnerUp;
4457 XDrawPosition(widget, True, NULL);
4458 flipView = !flipView; partnerUp = !partnerUp;
4462 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
4469 void DrawPosition(fullRedraw, board)
4470 /*Boolean*/int fullRedraw;
4473 XDrawPosition(boardWidget, fullRedraw, board);
4476 /* Returns 1 if there are "too many" differences between b1 and b2
4477 (i.e. more than 1 move was made) */
4478 static int too_many_diffs(b1, b2)
4484 for (i=0; i<BOARD_HEIGHT; ++i) {
4485 for (j=0; j<BOARD_WIDTH; ++j) {
4486 if (b1[i][j] != b2[i][j]) {
4487 if (++c > 4) /* Castling causes 4 diffs */
4496 /* Matrix describing castling maneuvers */
4497 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4498 static int castling_matrix[4][5] = {
4499 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4500 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4501 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4502 { 7, 7, 4, 5, 6 } /* 0-0, black */
4505 /* Checks whether castling occurred. If it did, *rrow and *rcol
4506 are set to the destination (row,col) of the rook that moved.
4508 Returns 1 if castling occurred, 0 if not.
4510 Note: Only handles a max of 1 castling move, so be sure
4511 to call too_many_diffs() first.
4513 static int check_castle_draw(newb, oldb, rrow, rcol)
4520 /* For each type of castling... */
4521 for (i=0; i<4; ++i) {
4522 r = castling_matrix[i];
4524 /* Check the 4 squares involved in the castling move */
4526 for (j=1; j<=4; ++j) {
4527 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4534 /* All 4 changed, so it must be a castling move */
4543 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4544 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4546 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4549 void DrawSeekBackground( int left, int top, int right, int bottom )
4551 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4554 void DrawSeekText(char *buf, int x, int y)
4556 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4559 void DrawSeekDot(int x, int y, int colorNr)
4561 int square = colorNr & 0x80;
4564 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4566 XFillRectangle(xDisplay, xBoardWindow, color,
4567 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4569 XFillArc(xDisplay, xBoardWindow, color,
4570 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4573 static int damage[2][BOARD_RANKS][BOARD_FILES];
4576 * event handler for redrawing the board
4578 void XDrawPosition(w, repaint, board)
4580 /*Boolean*/int repaint;
4584 static int lastFlipView = 0;
4585 static int lastBoardValid[2] = {0, 0};
4586 static Board lastBoard[2];
4589 int nr = twoBoards*partnerUp;
4591 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4593 if (board == NULL) {
4594 if (!lastBoardValid[nr]) return;
4595 board = lastBoard[nr];
4597 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4598 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4599 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Flip View"),
4604 * It would be simpler to clear the window with XClearWindow()
4605 * but this causes a very distracting flicker.
4608 if ( lineGap && IsDrawArrowEnabled()) repaint = True;
4609 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4611 /* If too much changes (begin observing new game, etc.), don't
4613 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4615 /* Special check for castling so we don't flash both the king
4616 and the rook (just flash the king). */
4618 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4619 /* Draw rook with NO flashing. King will be drawn flashing later */
4620 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4621 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4625 /* First pass -- Draw (newly) empty squares and repair damage.
4626 This prevents you from having a piece show up twice while it
4627 is flashing on its new square */
4628 for (i = 0; i < BOARD_HEIGHT; i++)
4629 for (j = 0; j < BOARD_WIDTH; j++)
4630 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4631 || damage[nr][i][j]) {
4632 DrawSquare(i, j, board[i][j], 0);
4633 damage[nr][i][j] = False;
4636 /* Second pass -- Draw piece(s) in new position and flash them */
4637 for (i = 0; i < BOARD_HEIGHT; i++)
4638 for (j = 0; j < BOARD_WIDTH; j++)
4639 if (board[i][j] != lastBoard[nr][i][j]) {
4640 DrawSquare(i, j, board[i][j], do_flash);
4644 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4645 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4646 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4648 for (i = 0; i < BOARD_HEIGHT; i++)
4649 for (j = 0; j < BOARD_WIDTH; j++) {
4650 DrawSquare(i, j, board[i][j], 0);
4651 damage[nr][i][j] = False;
4655 CopyBoard(lastBoard[nr], board);
4656 lastBoardValid[nr] = 1;
4657 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4658 lastFlipView = flipView;
4660 /* Draw highlights */
4661 if (pm1X >= 0 && pm1Y >= 0) {
4662 drawHighlight(pm1X, pm1Y, prelineGC);
4664 if (pm2X >= 0 && pm2Y >= 0) {
4665 drawHighlight(pm2X, pm2Y, prelineGC);
4667 if (hi1X >= 0 && hi1Y >= 0) {
4668 drawHighlight(hi1X, hi1Y, highlineGC);
4670 if (hi2X >= 0 && hi2Y >= 0) {
4671 drawHighlight(hi2X, hi2Y, highlineGC);
4673 DrawArrowHighlight(hi1X, hi1Y, hi2X, hi2Y);
4675 /* If piece being dragged around board, must redraw that too */
4678 XSync(xDisplay, False);
4683 * event handler for redrawing the board
4685 void DrawPositionProc(w, event, prms, nprms)
4691 XDrawPosition(w, True, NULL);
4696 * event handler for parsing user moves
4698 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4699 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4700 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4701 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4702 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4703 // and at the end FinishMove() to perform the move after optional promotion popups.
4704 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4705 void HandleUserMove(w, event, prms, nprms)
4711 if (w != boardWidget || errorExitStatus != -1) return;
4712 if(nprms) shiftKey = !strcmp(prms[0], "1");
4715 if (event->type == ButtonPress) {
4716 XtPopdown(promotionShell);
4717 XtDestroyWidget(promotionShell);
4718 promotionUp = False;
4726 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4727 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4728 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4731 void AnimateUserMove (Widget w, XEvent * event,
4732 String * params, Cardinal * nParams)
4734 DragPieceMove(event->xmotion.x, event->xmotion.y);
4737 void HandlePV (Widget w, XEvent * event,
4738 String * params, Cardinal * nParams)
4739 { // [HGM] pv: walk PV
4740 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4743 Widget CommentCreate(name, text, mutable, callback, lines)
4745 int /*Boolean*/ mutable;
4746 XtCallbackProc callback;
4750 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4755 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4756 XtGetValues(boardWidget, args, j);
4759 XtSetArg(args[j], XtNresizable, True); j++;
4762 XtCreatePopupShell(name, topLevelShellWidgetClass,
4763 shellWidget, args, j);
4766 XtCreatePopupShell(name, transientShellWidgetClass,
4767 shellWidget, args, j);
4770 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4771 layoutArgs, XtNumber(layoutArgs));
4773 XtCreateManagedWidget("form", formWidgetClass, layout,
4774 formArgs, XtNumber(formArgs));
4778 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4779 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4781 XtSetArg(args[j], XtNstring, text); j++;
4782 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4783 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4784 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4785 XtSetArg(args[j], XtNright, XtChainRight); j++;
4786 XtSetArg(args[j], XtNresizable, True); j++;
4787 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4788 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4789 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4790 XtSetArg(args[j], XtNautoFill, True); j++;
4791 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4793 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4794 XtOverrideTranslations(edit, XtParseTranslationTable(commentTranslations));
4798 XtSetArg(args[j], XtNfromVert, edit); j++;
4799 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4800 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4801 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4802 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4804 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4805 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4808 XtSetArg(args[j], XtNfromVert, edit); j++;
4809 XtSetArg(args[j], XtNfromHoriz, b_ok); 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(_("cancel"), commandWidgetClass, form, args, j);
4816 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4819 XtSetArg(args[j], XtNfromVert, edit); j++;
4820 XtSetArg(args[j], XtNfromHoriz, b_cancel); 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(_("clear"), commandWidgetClass, form, args, j);
4827 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4830 XtSetArg(args[j], XtNfromVert, edit); j++;
4831 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4832 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4833 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4834 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4836 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4837 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4840 XtSetArg(args[j], XtNfromVert, edit); j++;
4841 XtSetArg(args[j], XtNfromHoriz, b_close); 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(_("edit"), commandWidgetClass, form, args, j);
4848 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4851 XtRealizeWidget(shell);
4853 if (commentX == -1) {
4856 Dimension pw_height;
4857 Dimension ew_height;
4860 XtSetArg(args[j], XtNheight, &ew_height); j++;
4861 XtGetValues(edit, args, j);
4864 XtSetArg(args[j], XtNheight, &pw_height); j++;
4865 XtGetValues(shell, args, j);
4866 commentH = pw_height + (lines - 1) * ew_height;
4867 commentW = bw_width - 16;
4869 XSync(xDisplay, False);
4871 /* This code seems to tickle an X bug if it is executed too soon
4872 after xboard starts up. The coordinates get transformed as if
4873 the main window was positioned at (0, 0).
4875 XtTranslateCoords(shellWidget,
4876 (bw_width - commentW) / 2, 0 - commentH / 2,
4877 &commentX, &commentY);
4879 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4880 RootWindowOfScreen(XtScreen(shellWidget)),
4881 (bw_width - commentW) / 2, 0 - commentH / 2,
4886 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4889 if(wpComment.width > 0) {
4890 commentX = wpComment.x;
4891 commentY = wpComment.y;
4892 commentW = wpComment.width;
4893 commentH = wpComment.height;
4897 XtSetArg(args[j], XtNheight, commentH); j++;
4898 XtSetArg(args[j], XtNwidth, commentW); j++;
4899 XtSetArg(args[j], XtNx, commentX); j++;
4900 XtSetArg(args[j], XtNy, commentY); j++;
4901 XtSetValues(shell, args, j);
4902 XtSetKeyboardFocus(shell, edit);
4907 /* Used for analysis window and ICS input window */
4908 Widget MiscCreate(name, text, mutable, callback, lines)
4910 int /*Boolean*/ mutable;
4911 XtCallbackProc callback;
4915 Widget shell, layout, form, edit;
4917 Dimension bw_width, pw_height, ew_height, w, h;
4923 XtSetArg(args[j], XtNresizable, True); j++;
4926 XtCreatePopupShell(name, topLevelShellWidgetClass,
4927 shellWidget, args, j);
4930 XtCreatePopupShell(name, transientShellWidgetClass,
4931 shellWidget, args, j);
4934 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4935 layoutArgs, XtNumber(layoutArgs));
4937 XtCreateManagedWidget("form", formWidgetClass, layout,
4938 formArgs, XtNumber(formArgs));
4942 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4943 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4945 XtSetArg(args[j], XtNstring, text); j++;
4946 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4947 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4948 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4949 XtSetArg(args[j], XtNright, XtChainRight); j++;
4950 XtSetArg(args[j], XtNresizable, True); j++;
4951 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4952 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4953 XtSetArg(args[j], XtNautoFill, True); j++;
4954 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4956 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4958 XtRealizeWidget(shell);
4961 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4962 XtGetValues(boardWidget, args, j);
4965 XtSetArg(args[j], XtNheight, &ew_height); j++;
4966 XtGetValues(edit, args, j);
4969 XtSetArg(args[j], XtNheight, &pw_height); j++;
4970 XtGetValues(shell, args, j);
4971 h = pw_height + (lines - 1) * ew_height;
4974 XSync(xDisplay, False);
4976 /* This code seems to tickle an X bug if it is executed too soon
4977 after xboard starts up. The coordinates get transformed as if
4978 the main window was positioned at (0, 0).
4980 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4982 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4983 RootWindowOfScreen(XtScreen(shellWidget)),
4984 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4988 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4991 XtSetArg(args[j], XtNheight, h); j++;
4992 XtSetArg(args[j], XtNwidth, w); j++;
4993 XtSetArg(args[j], XtNx, x); j++;
4994 XtSetArg(args[j], XtNy, y); j++;
4995 XtSetValues(shell, args, j);
5001 static int savedIndex; /* gross that this is global */
5003 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
5006 XawTextPosition index, dummy;
5009 XawTextGetSelectionPos(w, &index, &dummy);
5010 XtSetArg(arg, XtNstring, &val);
5011 XtGetValues(w, &arg, 1);
5012 ReplaceComment(savedIndex, val);
5013 if(savedIndex != currentMove) ToNrEvent(savedIndex);
5014 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
5017 void EditCommentPopUp(index, title, text)
5026 if (text == NULL) text = "";
5028 if (editShell == NULL) {
5030 CommentCreate(title, text, True, EditCommentCallback, 4);
5031 XtRealizeWidget(editShell);
5032 CatchDeleteWindow(editShell, "EditCommentPopDown");
5034 edit = XtNameToWidget(editShell, "*form.text");
5036 XtSetArg(args[j], XtNstring, text); j++;
5037 XtSetValues(edit, args, j);
5039 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5040 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5041 XtSetValues(editShell, args, j);
5044 XtPopup(editShell, XtGrabNone);
5048 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5049 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"),
5051 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"),
5055 void EditCommentCallback(w, client_data, call_data)
5057 XtPointer client_data, call_data;
5065 XtSetArg(args[j], XtNlabel, &name); j++;
5066 XtGetValues(w, args, j);
5068 if (strcmp(name, _("ok")) == 0) {
5069 edit = XtNameToWidget(editShell, "*form.text");
5071 XtSetArg(args[j], XtNstring, &val); j++;
5072 XtGetValues(edit, args, j);
5073 ReplaceComment(savedIndex, val);
5074 EditCommentPopDown();
5075 } else if (strcmp(name, _("cancel")) == 0) {
5076 EditCommentPopDown();
5077 } else if (strcmp(name, _("clear")) == 0) {
5078 edit = XtNameToWidget(editShell, "*form.text");
5079 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5080 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5084 void EditCommentPopDown()
5089 if (!editUp) return;
5091 XtSetArg(args[j], XtNx, &commentX); j++;
5092 XtSetArg(args[j], XtNy, &commentY); j++;
5093 XtSetArg(args[j], XtNheight, &commentH); j++;
5094 XtSetArg(args[j], XtNwidth, &commentW); j++;
5095 XtGetValues(editShell, args, j);
5096 XtPopdown(editShell);
5099 XtSetArg(args[j], XtNleftBitmap, None); j++;
5100 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"),
5102 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"),
5106 void ICSInputBoxPopUp()
5111 char *title = _("ICS Input");
5114 if (ICSInputShell == NULL) {
5115 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
5116 tr = XtParseTranslationTable(ICSInputTranslations);
5117 edit = XtNameToWidget(ICSInputShell, "*form.text");
5118 XtOverrideTranslations(edit, tr);
5119 XtRealizeWidget(ICSInputShell);
5120 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
5123 edit = XtNameToWidget(ICSInputShell, "*form.text");
5125 XtSetArg(args[j], XtNstring, ""); j++;
5126 XtSetValues(edit, args, j);
5128 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5129 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5130 XtSetValues(ICSInputShell, args, j);
5133 XtPopup(ICSInputShell, XtGrabNone);
5134 XtSetKeyboardFocus(ICSInputShell, edit);
5136 ICSInputBoxUp = True;
5138 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5139 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.ICS Input Box"),
5143 void ICSInputSendText()
5150 edit = XtNameToWidget(ICSInputShell, "*form.text");
5152 XtSetArg(args[j], XtNstring, &val); j++;
5153 XtGetValues(edit, args, j);
5155 SendMultiLineToICS(val);
5156 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5157 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5160 void ICSInputBoxPopDown()
5165 if (!ICSInputBoxUp) return;
5167 XtPopdown(ICSInputShell);
5168 ICSInputBoxUp = False;
5170 XtSetArg(args[j], XtNleftBitmap, None); j++;
5171 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.ICS Input Box"),
5175 void CommentPopUp(title, text)
5182 savedIndex = currentMove; // [HGM] vari
5183 if (commentShell == NULL) {
5185 CommentCreate(title, text, False, CommentCallback, 4);
5186 XtRealizeWidget(commentShell);
5187 CatchDeleteWindow(commentShell, "CommentPopDown");
5189 edit = XtNameToWidget(commentShell, "*form.text");
5191 XtSetArg(args[j], XtNstring, text); j++;
5192 XtSetValues(edit, args, j);
5194 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5195 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5196 XtSetValues(commentShell, args, j);
5199 XtPopup(commentShell, XtGrabNone);
5200 XSync(xDisplay, False);
5205 void CommentCallback(w, client_data, call_data)
5207 XtPointer client_data, call_data;
5214 XtSetArg(args[j], XtNlabel, &name); j++;
5215 XtGetValues(w, args, j);
5217 if (strcmp(name, _("close")) == 0) {
5219 } else if (strcmp(name, _("edit")) == 0) {
5226 void CommentPopDown()
5231 if (!commentUp) return;
5233 XtSetArg(args[j], XtNx, &commentX); j++;
5234 XtSetArg(args[j], XtNy, &commentY); j++;
5235 XtSetArg(args[j], XtNwidth, &commentW); j++;
5236 XtSetArg(args[j], XtNheight, &commentH); j++;
5237 XtGetValues(commentShell, args, j);
5238 XtPopdown(commentShell);
5239 XSync(xDisplay, False);
5243 void FileNamePopUp(label, def, proc, openMode)
5249 fileProc = proc; /* I can't see a way not */
5250 fileOpenMode = openMode; /* to use globals here */
5251 { // [HGM] use file-selector dialog stolen from Ghostview
5253 int index; // this is not supported yet
5255 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5256 def, openMode, NULL, &name))
5257 (void) (*fileProc)(f, index=0, name);
5261 void FileNamePopDown()
5263 if (!filenameUp) return;
5264 XtPopdown(fileNameShell);
5265 XtDestroyWidget(fileNameShell);
5270 void FileNameCallback(w, client_data, call_data)
5272 XtPointer client_data, call_data;
5277 XtSetArg(args[0], XtNlabel, &name);
5278 XtGetValues(w, args, 1);
5280 if (strcmp(name, _("cancel")) == 0) {
5285 FileNameAction(w, NULL, NULL, NULL);
5288 void FileNameAction(w, event, prms, nprms)
5300 name = XawDialogGetValueString(w = XtParent(w));
5302 if ((name != NULL) && (*name != NULLCHAR)) {
5303 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
5304 XtPopdown(w = XtParent(XtParent(w)));
5308 p = strrchr(buf, ' ');
5315 fullname = ExpandPathName(buf);
5317 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5320 f = fopen(fullname, fileOpenMode);
5322 DisplayError(_("Failed to open file"), errno);
5324 (void) (*fileProc)(f, index, buf);
5331 XtPopdown(w = XtParent(XtParent(w)));
5337 void PromotionPopUp()
5340 Widget dialog, layout;
5342 Dimension bw_width, pw_width;
5346 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5347 XtGetValues(boardWidget, args, j);
5350 XtSetArg(args[j], XtNresizable, True); j++;
5351 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5353 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5354 shellWidget, args, j);
5356 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5357 layoutArgs, XtNumber(layoutArgs));
5360 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5361 XtSetArg(args[j], XtNborderWidth, 0); j++;
5362 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5365 if(gameInfo.variant != VariantShogi) {
5366 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) {
5367 XawDialogAddButton(dialog, _("Warlord"), PromotionCallback,
5368 (XtPointer) dialog);
5369 XawDialogAddButton(dialog, _("General"), PromotionCallback,
5370 (XtPointer) dialog);
5371 XawDialogAddButton(dialog, _("Lieutenant"), PromotionCallback,
5372 (XtPointer) dialog);
5373 XawDialogAddButton(dialog, _("Captain"), PromotionCallback,
5374 (XtPointer) dialog);
5376 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5377 (XtPointer) dialog);
5378 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5379 (XtPointer) dialog);
5380 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5381 (XtPointer) dialog);
5382 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5383 (XtPointer) dialog);
5385 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5386 gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
\r
5387 gameInfo.variant == VariantGiveaway) {
5388 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5389 (XtPointer) dialog);
5391 if(gameInfo.variant == VariantCapablanca ||
5392 gameInfo.variant == VariantGothic ||
5393 gameInfo.variant == VariantCapaRandom) {
5394 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5395 (XtPointer) dialog);
5396 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5397 (XtPointer) dialog);
5399 } else // [HGM] shogi
5401 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5402 (XtPointer) dialog);
5403 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5404 (XtPointer) dialog);
5406 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5407 (XtPointer) dialog);
5409 XtRealizeWidget(promotionShell);
5410 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5413 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5414 XtGetValues(promotionShell, args, j);
5416 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5417 lineGap + squareSize/3 +
5418 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5419 0 : 6*(squareSize + lineGap)), &x, &y);
5422 XtSetArg(args[j], XtNx, x); j++;
5423 XtSetArg(args[j], XtNy, y); j++;
5424 XtSetValues(promotionShell, args, j);
5426 XtPopup(promotionShell, XtGrabNone);
5431 void PromotionPopDown()
5433 if (!promotionUp) return;
5434 XtPopdown(promotionShell);
5435 XtDestroyWidget(promotionShell);
5436 promotionUp = False;
5439 void PromotionCallback(w, client_data, call_data)
5441 XtPointer client_data, call_data;
5447 XtSetArg(args[0], XtNlabel, &name);
5448 XtGetValues(w, args, 1);
5452 if (fromX == -1) return;
5454 if (strcmp(name, _("cancel")) == 0) {
5458 } else if (strcmp(name, _("Knight")) == 0) {
5460 } else if (strcmp(name, _("Promote")) == 0) {
5462 } else if (strcmp(name, _("Defer")) == 0) {
5465 promoChar = ToLower(name[0]);
5468 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5470 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5471 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5476 void ErrorCallback(w, client_data, call_data)
5478 XtPointer client_data, call_data;
5481 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5483 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5489 if (!errorUp) return;
5491 XtPopdown(errorShell);
5492 XtDestroyWidget(errorShell);
5493 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5496 void ErrorPopUp(title, label, modal)
5497 char *title, *label;
5501 Widget dialog, layout;
5505 Dimension bw_width, pw_width;
5506 Dimension pw_height;
5510 XtSetArg(args[i], XtNresizable, True); i++;
5511 XtSetArg(args[i], XtNtitle, title); i++;
5513 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5514 shellWidget, args, i);
5516 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5517 layoutArgs, XtNumber(layoutArgs));
5520 XtSetArg(args[i], XtNlabel, label); i++;
5521 XtSetArg(args[i], XtNborderWidth, 0); i++;
5522 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5525 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5527 XtRealizeWidget(errorShell);
5528 CatchDeleteWindow(errorShell, "ErrorPopDown");
5531 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5532 XtGetValues(boardWidget, args, i);
5534 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5535 XtSetArg(args[i], XtNheight, &pw_height); i++;
5536 XtGetValues(errorShell, args, i);
5539 /* This code seems to tickle an X bug if it is executed too soon
5540 after xboard starts up. The coordinates get transformed as if
5541 the main window was positioned at (0, 0).
5543 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5544 0 - pw_height + squareSize / 3, &x, &y);
5546 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5547 RootWindowOfScreen(XtScreen(boardWidget)),
5548 (bw_width - pw_width) / 2,
5549 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5553 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5556 XtSetArg(args[i], XtNx, x); i++;
5557 XtSetArg(args[i], XtNy, y); i++;
5558 XtSetValues(errorShell, args, i);
5561 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5564 /* Disable all user input other than deleting the window */
5565 static int frozen = 0;
5569 /* Grab by a widget that doesn't accept input */
5570 XtAddGrab(messageWidget, TRUE, FALSE);
5574 /* Undo a FreezeUI */
5577 if (!frozen) return;
5578 XtRemoveGrab(messageWidget);
5582 char *ModeToWidgetName(mode)
5586 case BeginningOfGame:
5587 if (appData.icsActive)
5588 return "menuMode.ICS Client";
5589 else if (appData.noChessProgram ||
5590 *appData.cmailGameName != NULLCHAR)
5591 return "menuMode.Edit Game";
5593 return "menuMode.Machine Black";
5594 case MachinePlaysBlack:
5595 return "menuMode.Machine Black";
5596 case MachinePlaysWhite:
5597 return "menuMode.Machine White";
5599 return "menuMode.Analysis Mode";
5601 return "menuMode.Analyze File";
5602 case TwoMachinesPlay:
5603 return "menuMode.Two Machines";
5605 return "menuMode.Edit Game";
5606 case PlayFromGameFile:
5607 return "menuFile.Load Game";
5609 return "menuMode.Edit Position";
5611 return "menuMode.Training";
5612 case IcsPlayingWhite:
5613 case IcsPlayingBlack:
5617 return "menuMode.ICS Client";
5624 void ModeHighlight()
5627 static int oldPausing = FALSE;
5628 static GameMode oldmode = (GameMode) -1;
5631 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5633 if (pausing != oldPausing) {
5634 oldPausing = pausing;
5636 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5638 XtSetArg(args[0], XtNleftBitmap, None);
5640 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5643 if (appData.showButtonBar) {
5644 /* Always toggle, don't set. Previous code messes up when
5645 invoked while the button is pressed, as releasing it
5646 toggles the state again. */
5649 XtSetArg(args[0], XtNbackground, &oldbg);
5650 XtSetArg(args[1], XtNforeground, &oldfg);
5651 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5653 XtSetArg(args[0], XtNbackground, oldfg);
5654 XtSetArg(args[1], XtNforeground, oldbg);
5656 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5660 wname = ModeToWidgetName(oldmode);
5661 if (wname != NULL) {
5662 XtSetArg(args[0], XtNleftBitmap, None);
5663 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5665 wname = ModeToWidgetName(gameMode);
5666 if (wname != NULL) {
5667 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5668 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5672 /* Maybe all the enables should be handled here, not just this one */
5673 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5674 gameMode == Training || gameMode == PlayFromGameFile);
5679 * Button/menu procedures
5681 void ResetProc(w, event, prms, nprms)
5690 int LoadGamePopUp(f, gameNumber, title)
5695 cmailMsgLoaded = FALSE;
5696 if (gameNumber == 0) {
5697 int error = GameListBuild(f);
5699 DisplayError(_("Cannot build game list"), error);
5700 } else if (!ListEmpty(&gameList) &&
5701 ((ListGame *) gameList.tailPred)->number > 1) {
5702 GameListPopUp(f, title);
5708 return LoadGame(f, gameNumber, title, FALSE);
5711 void LoadGameProc(w, event, prms, nprms)
5717 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5720 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5723 void LoadNextGameProc(w, event, prms, nprms)
5732 void LoadPrevGameProc(w, event, prms, nprms)
5741 void ReloadGameProc(w, event, prms, nprms)
5750 void LoadNextPositionProc(w, event, prms, nprms)
5759 void LoadPrevPositionProc(w, event, prms, nprms)
5768 void ReloadPositionProc(w, event, prms, nprms)
5777 void LoadPositionProc(w, event, prms, nprms)
5783 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5786 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5789 void SaveGameProc(w, event, prms, nprms)
5795 FileNamePopUp(_("Save game file name?"),
5796 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5800 void SavePositionProc(w, event, prms, nprms)
5806 FileNamePopUp(_("Save position file name?"),
5807 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5811 void ReloadCmailMsgProc(w, event, prms, nprms)
5817 ReloadCmailMsgEvent(FALSE);
5820 void MailMoveProc(w, event, prms, nprms)
5829 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5830 char *selected_fen_position=NULL;
5833 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5834 Atom *type_return, XtPointer *value_return,
5835 unsigned long *length_return, int *format_return)
5837 char *selection_tmp;
5839 if (!selected_fen_position) return False; /* should never happen */
5840 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5841 /* note: since no XtSelectionDoneProc was registered, Xt will
5842 * automatically call XtFree on the value returned. So have to
5843 * make a copy of it allocated with XtMalloc */
5844 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5845 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
5847 *value_return=selection_tmp;
5848 *length_return=strlen(selection_tmp);
5849 *type_return=*target;
5850 *format_return = 8; /* bits per byte */
5852 } else if (*target == XA_TARGETS(xDisplay)) {
5853 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5854 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5855 targets_tmp[1] = XA_STRING;
5856 *value_return = targets_tmp;
5857 *type_return = XA_ATOM;
5859 *format_return = 8 * sizeof(Atom);
5860 if (*format_return > 32) {
5861 *length_return *= *format_return / 32;
5862 *format_return = 32;
5870 /* note: when called from menu all parameters are NULL, so no clue what the
5871 * Widget which was clicked on was, or what the click event was
5873 void CopyPositionProc(w, event, prms, nprms)
5880 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5881 * have a notion of a position that is selected but not copied.
5882 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5884 if(gameMode == EditPosition) EditPositionDone(TRUE);
5885 if (selected_fen_position) free(selected_fen_position);
5886 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5887 if (!selected_fen_position) return;
5888 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5890 SendPositionSelection,
5891 NULL/* lose_ownership_proc */ ,
5892 NULL/* transfer_done_proc */);
5893 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5895 SendPositionSelection,
5896 NULL/* lose_ownership_proc */ ,
5897 NULL/* transfer_done_proc */);
5900 /* function called when the data to Paste is ready */
5902 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5903 Atom *type, XtPointer value, unsigned long *len, int *format)
5906 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5907 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5908 EditPositionPasteFEN(fenstr);
5912 /* called when Paste Position button is pressed,
5913 * all parameters will be NULL */
5914 void PastePositionProc(w, event, prms, nprms)
5920 XtGetSelectionValue(menuBarWidget,
5921 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5922 /* (XtSelectionCallbackProc) */ PastePositionCB,
5923 NULL, /* client_data passed to PastePositionCB */
5925 /* better to use the time field from the event that triggered the
5926 * call to this function, but that isn't trivial to get
5934 SendGameSelection(Widget w, Atom *selection, Atom *target,
5935 Atom *type_return, XtPointer *value_return,
5936 unsigned long *length_return, int *format_return)
5938 char *selection_tmp;
5940 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5941 FILE* f = fopen(gameCopyFilename, "r");
5944 if (f == NULL) return False;
5948 selection_tmp = XtMalloc(len + 1);
5949 count = fread(selection_tmp, 1, len, f);
5952 XtFree(selection_tmp);
5955 selection_tmp[len] = NULLCHAR;
5956 *value_return = selection_tmp;
5957 *length_return = len;
5958 *type_return = *target;
5959 *format_return = 8; /* bits per byte */
5961 } else if (*target == XA_TARGETS(xDisplay)) {
5962 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5963 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5964 targets_tmp[1] = XA_STRING;
5965 *value_return = targets_tmp;
5966 *type_return = XA_ATOM;
5968 *format_return = 8 * sizeof(Atom);
5969 if (*format_return > 32) {
5970 *length_return *= *format_return / 32;
5971 *format_return = 32;
5979 /* note: when called from menu all parameters are NULL, so no clue what the
5980 * Widget which was clicked on was, or what the click event was
5982 void CopyGameProc(w, event, prms, nprms)
5990 ret = SaveGameToFile(gameCopyFilename, FALSE);
5994 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5995 * have a notion of a game that is selected but not copied.
5996 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5998 XtOwnSelection(menuBarWidget, XA_PRIMARY,
6001 NULL/* lose_ownership_proc */ ,
6002 NULL/* transfer_done_proc */);
6003 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
6006 NULL/* lose_ownership_proc */ ,
6007 NULL/* transfer_done_proc */);
6010 /* function called when the data to Paste is ready */
6012 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
6013 Atom *type, XtPointer value, unsigned long *len, int *format)
6016 if (value == NULL || *len == 0) {
6017 return; /* nothing had been selected to copy */
6019 f = fopen(gamePasteFilename, "w");
6021 DisplayError(_("Can't open temp file"), errno);
6024 fwrite(value, 1, *len, f);
6027 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
6030 /* called when Paste Game button is pressed,
6031 * all parameters will be NULL */
6032 void PasteGameProc(w, event, prms, nprms)
6038 XtGetSelectionValue(menuBarWidget,
6039 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
6040 /* (XtSelectionCallbackProc) */ PasteGameCB,
6041 NULL, /* client_data passed to PasteGameCB */
6043 /* better to use the time field from the event that triggered the
6044 * call to this function, but that isn't trivial to get
6054 SaveGameProc(NULL, NULL, NULL, NULL);
6058 void QuitProc(w, event, prms, nprms)
6067 void PauseProc(w, event, prms, nprms)
6077 void MachineBlackProc(w, event, prms, nprms)
6083 MachineBlackEvent();
6086 void MachineWhiteProc(w, event, prms, nprms)
6092 MachineWhiteEvent();
6095 void AnalyzeModeProc(w, event, prms, nprms)
6103 if (!first.analysisSupport) {
6104 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6105 DisplayError(buf, 0);
6108 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
6109 if (appData.icsActive) {
6110 if (gameMode != IcsObserving) {
6111 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
6112 DisplayError(buf, 0);
6114 if (appData.icsEngineAnalyze) {
6115 if (appData.debugMode)
6116 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
6122 /* if enable, use want disable icsEngineAnalyze */
6123 if (appData.icsEngineAnalyze) {
6128 appData.icsEngineAnalyze = TRUE;
6129 if (appData.debugMode)
6130 fprintf(debugFP, _("ICS engine analyze starting... \n"));
6132 if (!appData.showThinking)
6133 ShowThinkingProc(w,event,prms,nprms);
6138 void AnalyzeFileProc(w, event, prms, nprms)
6144 if (!first.analysisSupport) {
6146 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6147 DisplayError(buf, 0);
6152 if (!appData.showThinking)
6153 ShowThinkingProc(w,event,prms,nprms);
6156 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
6157 AnalysisPeriodicEvent(1);
6160 void TwoMachinesProc(w, event, prms, nprms)
6169 void IcsClientProc(w, event, prms, nprms)
6178 void EditGameProc(w, event, prms, nprms)
6187 void EditPositionProc(w, event, prms, nprms)
6193 EditPositionEvent();
6196 void TrainingProc(w, event, prms, nprms)
6205 void EditCommentProc(w, event, prms, nprms)
6212 EditCommentPopDown();
6218 void IcsInputBoxProc(w, event, prms, nprms)
6224 if (ICSInputBoxUp) {
6225 ICSInputBoxPopDown();
6231 void AcceptProc(w, event, prms, nprms)
6240 void DeclineProc(w, event, prms, nprms)
6249 void RematchProc(w, event, prms, nprms)
6258 void CallFlagProc(w, event, prms, nprms)
6267 void DrawProc(w, event, prms, nprms)
6276 void AbortProc(w, event, prms, nprms)
6285 void AdjournProc(w, event, prms, nprms)
6294 void ResignProc(w, event, prms, nprms)
6303 void AdjuWhiteProc(w, event, prms, nprms)
6309 UserAdjudicationEvent(+1);
6312 void AdjuBlackProc(w, event, prms, nprms)
6318 UserAdjudicationEvent(-1);
6321 void AdjuDrawProc(w, event, prms, nprms)
6327 UserAdjudicationEvent(0);
6330 void EnterKeyProc(w, event, prms, nprms)
6336 if (ICSInputBoxUp == True)
6340 void UpKeyProc(w, event, prms, nprms)
6345 { // [HGM] input: let up-arrow recall previous line from history
6352 if (!ICSInputBoxUp) return;
6353 edit = XtNameToWidget(ICSInputShell, "*form.text");
6355 XtSetArg(args[j], XtNstring, &val); j++;
6356 XtGetValues(edit, args, j);
6357 val = PrevInHistory(val);
6358 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6359 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6361 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6362 XawTextReplace(edit, 0, 0, &t);
6363 XawTextSetInsertionPoint(edit, 9999);
6367 void DownKeyProc(w, event, prms, nprms)
6372 { // [HGM] input: let down-arrow recall next line from history
6377 if (!ICSInputBoxUp) return;
6378 edit = XtNameToWidget(ICSInputShell, "*form.text");
6379 val = NextInHistory();
6380 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6381 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6383 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6384 XawTextReplace(edit, 0, 0, &t);
6385 XawTextSetInsertionPoint(edit, 9999);
6389 void StopObservingProc(w, event, prms, nprms)
6395 StopObservingEvent();
6398 void StopExaminingProc(w, event, prms, nprms)
6404 StopExaminingEvent();
6407 void UploadProc(w, event, prms, nprms)
6417 void ForwardProc(w, event, prms, nprms)
6427 void BackwardProc(w, event, prms, nprms)
6436 void ToStartProc(w, event, prms, nprms)
6445 void ToEndProc(w, event, prms, nprms)
6454 void RevertProc(w, event, prms, nprms)
6463 void AnnotateProc(w, event, prms, nprms)
6472 void TruncateGameProc(w, event, prms, nprms)
6478 TruncateGameEvent();
6480 void RetractMoveProc(w, event, prms, nprms)
6489 void MoveNowProc(w, event, prms, nprms)
6499 void AlwaysQueenProc(w, event, prms, nprms)
6507 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6509 if (appData.alwaysPromoteToQueen) {
6510 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6512 XtSetArg(args[0], XtNleftBitmap, None);
6514 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6518 void AnimateDraggingProc(w, event, prms, nprms)
6526 appData.animateDragging = !appData.animateDragging;
6528 if (appData.animateDragging) {
6529 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6532 XtSetArg(args[0], XtNleftBitmap, None);
6534 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6538 void AnimateMovingProc(w, event, prms, nprms)
6546 appData.animate = !appData.animate;
6548 if (appData.animate) {
6549 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6552 XtSetArg(args[0], XtNleftBitmap, None);
6554 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6558 void AutocommProc(w, event, prms, nprms)
6566 appData.autoComment = !appData.autoComment;
6568 if (appData.autoComment) {
6569 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6571 XtSetArg(args[0], XtNleftBitmap, None);
6573 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6578 void AutoflagProc(w, event, prms, nprms)
6586 appData.autoCallFlag = !appData.autoCallFlag;
6588 if (appData.autoCallFlag) {
6589 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6591 XtSetArg(args[0], XtNleftBitmap, None);
6593 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6597 void AutoflipProc(w, event, prms, nprms)
6605 appData.autoFlipView = !appData.autoFlipView;
6607 if (appData.autoFlipView) {
6608 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6610 XtSetArg(args[0], XtNleftBitmap, None);
6612 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6616 void AutobsProc(w, event, prms, nprms)
6624 appData.autoObserve = !appData.autoObserve;
6626 if (appData.autoObserve) {
6627 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6629 XtSetArg(args[0], XtNleftBitmap, None);
6631 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6635 void AutoraiseProc(w, event, prms, nprms)
6643 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6645 if (appData.autoRaiseBoard) {
6646 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6648 XtSetArg(args[0], XtNleftBitmap, None);
6650 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6654 void AutosaveProc(w, event, prms, nprms)
6662 appData.autoSaveGames = !appData.autoSaveGames;
6664 if (appData.autoSaveGames) {
6665 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6667 XtSetArg(args[0], XtNleftBitmap, None);
6669 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6673 void BlindfoldProc(w, event, prms, nprms)
6681 appData.blindfold = !appData.blindfold;
6683 if (appData.blindfold) {
6684 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6686 XtSetArg(args[0], XtNleftBitmap, None);
6688 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6691 DrawPosition(True, NULL);
6694 void TestLegalityProc(w, event, prms, nprms)
6702 appData.testLegality = !appData.testLegality;
6704 if (appData.testLegality) {
6705 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6707 XtSetArg(args[0], XtNleftBitmap, None);
6709 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6714 void FlashMovesProc(w, event, prms, nprms)
6722 if (appData.flashCount == 0) {
6723 appData.flashCount = 3;
6725 appData.flashCount = -appData.flashCount;
6728 if (appData.flashCount > 0) {
6729 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6731 XtSetArg(args[0], XtNleftBitmap, None);
6733 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6737 void FlipViewProc(w, event, prms, nprms)
6743 flipView = !flipView;
6744 DrawPosition(True, NULL);
6747 void GetMoveListProc(w, event, prms, nprms)
6755 appData.getMoveList = !appData.getMoveList;
6757 if (appData.getMoveList) {
6758 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6761 XtSetArg(args[0], XtNleftBitmap, None);
6763 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6768 void HighlightDraggingProc(w, event, prms, nprms)
6776 appData.highlightDragging = !appData.highlightDragging;
6778 if (appData.highlightDragging) {
6779 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6781 XtSetArg(args[0], XtNleftBitmap, None);
6783 XtSetValues(XtNameToWidget(menuBarWidget,
6784 "menuOptions.Highlight Dragging"), args, 1);
6788 void HighlightLastMoveProc(w, event, prms, nprms)
6796 appData.highlightLastMove = !appData.highlightLastMove;
6798 if (appData.highlightLastMove) {
6799 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6801 XtSetArg(args[0], XtNleftBitmap, None);
6803 XtSetValues(XtNameToWidget(menuBarWidget,
6804 "menuOptions.Highlight Last Move"), args, 1);
6807 void HighlightArrowProc(w, event, prms, nprms)
6815 appData.highlightMoveWithArrow = !appData.highlightMoveWithArrow;
6817 if (appData.highlightMoveWithArrow) {
6818 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6820 XtSetArg(args[0], XtNleftBitmap, None);
6822 XtSetValues(XtNameToWidget(menuBarWidget,
6823 "menuOptions.Arrow"), args, 1);
6826 void IcsAlarmProc(w, event, prms, nprms)
6834 appData.icsAlarm = !appData.icsAlarm;
6836 if (appData.icsAlarm) {
6837 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6839 XtSetArg(args[0], XtNleftBitmap, None);
6841 XtSetValues(XtNameToWidget(menuBarWidget,
6842 "menuOptions.ICS Alarm"), args, 1);
6845 void MoveSoundProc(w, event, prms, nprms)
6853 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6855 if (appData.ringBellAfterMoves) {
6856 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6858 XtSetArg(args[0], XtNleftBitmap, None);
6860 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6864 void OneClickProc(w, event, prms, nprms)
6872 appData.oneClick = !appData.oneClick;
6874 if (appData.oneClick) {
6875 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6877 XtSetArg(args[0], XtNleftBitmap, None);
6879 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.OneClick"),
6883 void PeriodicUpdatesProc(w, event, prms, nprms)
6891 PeriodicUpdatesEvent(!appData.periodicUpdates);
6893 if (appData.periodicUpdates) {
6894 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6896 XtSetArg(args[0], XtNleftBitmap, None);
6898 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6902 void PonderNextMoveProc(w, event, prms, nprms)
6910 PonderNextMoveEvent(!appData.ponderNextMove);
6912 if (appData.ponderNextMove) {
6913 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6915 XtSetArg(args[0], XtNleftBitmap, None);
6917 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6921 void PopupExitMessageProc(w, event, prms, nprms)
6929 appData.popupExitMessage = !appData.popupExitMessage;
6931 if (appData.popupExitMessage) {
6932 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6934 XtSetArg(args[0], XtNleftBitmap, None);
6936 XtSetValues(XtNameToWidget(menuBarWidget,
6937 "menuOptions.Popup Exit Message"), args, 1);
6940 void PopupMoveErrorsProc(w, event, prms, nprms)
6948 appData.popupMoveErrors = !appData.popupMoveErrors;
6950 if (appData.popupMoveErrors) {
6951 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6953 XtSetArg(args[0], XtNleftBitmap, None);
6955 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6959 void PremoveProc(w, event, prms, nprms)
6967 appData.premove = !appData.premove;
6969 if (appData.premove) {
6970 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6972 XtSetArg(args[0], XtNleftBitmap, None);
6974 XtSetValues(XtNameToWidget(menuBarWidget,
6975 "menuOptions.Premove"), args, 1);
6978 void QuietPlayProc(w, event, prms, nprms)
6986 appData.quietPlay = !appData.quietPlay;
6988 if (appData.quietPlay) {
6989 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6991 XtSetArg(args[0], XtNleftBitmap, None);
6993 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6997 void ShowCoordsProc(w, event, prms, nprms)
7005 appData.showCoords = !appData.showCoords;
7007 if (appData.showCoords) {
7008 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
7010 XtSetArg(args[0], XtNleftBitmap, None);
7012 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
7015 DrawPosition(True, NULL);
7018 void ShowThinkingProc(w, event, prms, nprms)
7024 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
7025 ShowThinkingEvent();
7028 void HideThinkingProc(w, event, prms, nprms)
7036 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
7037 ShowThinkingEvent();
7039 if (appData.hideThinkingFromHuman) {
7040 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
7042 XtSetArg(args[0], XtNleftBitmap, None);
7044 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
7048 void SaveOnExitProc(w, event, prms, nprms)
7056 saveSettingsOnExit = !saveSettingsOnExit;
7058 if (saveSettingsOnExit) {
7059 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
7061 XtSetArg(args[0], XtNleftBitmap, None);
7063 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
7067 void SaveSettingsProc(w, event, prms, nprms)
7073 SaveSettings(settingsFileName);
7076 void InfoProc(w, event, prms, nprms)
7083 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
7088 void ManProc(w, event, prms, nprms)
7096 if (nprms && *nprms > 0)
7100 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
7104 void HintProc(w, event, prms, nprms)
7113 void BookProc(w, event, prms, nprms)
7122 void AboutProc(w, event, prms, nprms)
7130 char *zippy = " (with Zippy code)";
7134 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
7135 programVersion, zippy,
7136 "Copyright 1991 Digital Equipment Corporation",
7137 "Enhancements Copyright 1992-2009 Free Software Foundation",
7138 "Enhancements Copyright 2005 Alessandro Scotti",
7139 PACKAGE, " is free software and carries NO WARRANTY;",
7140 "see the file COPYING for more information.");
7141 ErrorPopUp(_("About XBoard"), buf, FALSE);
7144 void DebugProc(w, event, prms, nprms)
7150 appData.debugMode = !appData.debugMode;
7153 void AboutGameProc(w, event, prms, nprms)
7162 void NothingProc(w, event, prms, nprms)
7171 void Iconify(w, event, prms, nprms)
7180 XtSetArg(args[0], XtNiconic, True);
7181 XtSetValues(shellWidget, args, 1);
7184 void DisplayMessage(message, extMessage)
7185 char *message, *extMessage;
7187 /* display a message in the message widget */
7196 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
7201 message = extMessage;
7205 /* need to test if messageWidget already exists, since this function
7206 can also be called during the startup, if for example a Xresource
7207 is not set up correctly */
7210 XtSetArg(arg, XtNlabel, message);
7211 XtSetValues(messageWidget, &arg, 1);
7217 void DisplayTitle(text)
7222 char title[MSG_SIZ];
7225 if (text == NULL) text = "";
7227 if (appData.titleInWindow) {
7229 XtSetArg(args[i], XtNlabel, text); i++;
7230 XtSetValues(titleWidget, args, i);
7233 if (*text != NULLCHAR) {
7234 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
7235 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
7236 } else if (appData.icsActive) {
7237 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7238 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7239 } else if (appData.cmailGameName[0] != NULLCHAR) {
7240 snprintf(icon, sizeof(icon), "%s", "CMail");
7241 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7243 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7244 } else if (gameInfo.variant == VariantGothic) {
7245 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7246 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
7249 } else if (gameInfo.variant == VariantFalcon) {
7250 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7251 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
7253 } else if (appData.noChessProgram) {
7254 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7255 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
7257 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
7258 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7261 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7262 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7263 XtSetValues(shellWidget, args, i);
7268 DisplayError(message, error)
7275 if (appData.debugMode || appData.matchMode) {
7276 fprintf(stderr, "%s: %s\n", programName, message);
7279 if (appData.debugMode || appData.matchMode) {
7280 fprintf(stderr, "%s: %s: %s\n",
7281 programName, message, strerror(error));
7283 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7286 ErrorPopUp(_("Error"), message, FALSE);
7290 void DisplayMoveError(message)
7295 DrawPosition(FALSE, NULL);
7296 if (appData.debugMode || appData.matchMode) {
7297 fprintf(stderr, "%s: %s\n", programName, message);
7299 if (appData.popupMoveErrors) {
7300 ErrorPopUp(_("Error"), message, FALSE);
7302 DisplayMessage(message, "");
7307 void DisplayFatalError(message, error, status)
7313 errorExitStatus = status;
7315 fprintf(stderr, "%s: %s\n", programName, message);
7317 fprintf(stderr, "%s: %s: %s\n",
7318 programName, message, strerror(error));
7319 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7322 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7323 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7329 void DisplayInformation(message)
7333 ErrorPopUp(_("Information"), message, TRUE);
7336 void DisplayNote(message)
7340 ErrorPopUp(_("Note"), message, FALSE);
7344 NullXErrorCheck(dpy, error_event)
7346 XErrorEvent *error_event;
7351 void DisplayIcsInteractionTitle(message)
7354 if (oldICSInteractionTitle == NULL) {
7355 /* Magic to find the old window title, adapted from vim */
7356 char *wina = getenv("WINDOWID");
7358 Window win = (Window) atoi(wina);
7359 Window root, parent, *children;
7360 unsigned int nchildren;
7361 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7363 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7364 if (!XQueryTree(xDisplay, win, &root, &parent,
7365 &children, &nchildren)) break;
7366 if (children) XFree((void *)children);
7367 if (parent == root || parent == 0) break;
7370 XSetErrorHandler(oldHandler);
7372 if (oldICSInteractionTitle == NULL) {
7373 oldICSInteractionTitle = "xterm";
7376 printf("\033]0;%s\007", message);
7380 char pendingReplyPrefix[MSG_SIZ];
7381 ProcRef pendingReplyPR;
7383 void AskQuestionProc(w, event, prms, nprms)
7390 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7394 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7397 void AskQuestionPopDown()
7399 if (!askQuestionUp) return;
7400 XtPopdown(askQuestionShell);
7401 XtDestroyWidget(askQuestionShell);
7402 askQuestionUp = False;
7405 void AskQuestionReplyAction(w, event, prms, nprms)
7415 reply = XawDialogGetValueString(w = XtParent(w));
7416 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
7417 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
7418 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
7419 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
7420 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7421 AskQuestionPopDown();
7423 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7426 void AskQuestionCallback(w, client_data, call_data)
7428 XtPointer client_data, call_data;
7433 XtSetArg(args[0], XtNlabel, &name);
7434 XtGetValues(w, args, 1);
7436 if (strcmp(name, _("cancel")) == 0) {
7437 AskQuestionPopDown();
7439 AskQuestionReplyAction(w, NULL, NULL, NULL);
7443 void AskQuestion(title, question, replyPrefix, pr)
7444 char *title, *question, *replyPrefix;
7448 Widget popup, layout, dialog, edit;
7454 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
7455 pendingReplyPR = pr;
7458 XtSetArg(args[i], XtNresizable, True); i++;
7459 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7460 askQuestionShell = popup =
7461 XtCreatePopupShell(title, transientShellWidgetClass,
7462 shellWidget, args, i);
7465 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7466 layoutArgs, XtNumber(layoutArgs));
7469 XtSetArg(args[i], XtNlabel, question); i++;
7470 XtSetArg(args[i], XtNvalue, ""); i++;
7471 XtSetArg(args[i], XtNborderWidth, 0); i++;
7472 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7475 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7476 (XtPointer) dialog);
7477 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7478 (XtPointer) dialog);
7480 XtRealizeWidget(popup);
7481 CatchDeleteWindow(popup, "AskQuestionPopDown");
7483 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7484 &x, &y, &win_x, &win_y, &mask);
7486 XtSetArg(args[0], XtNx, x - 10);
7487 XtSetArg(args[1], XtNy, y - 30);
7488 XtSetValues(popup, args, 2);
7490 XtPopup(popup, XtGrabExclusive);
7491 askQuestionUp = True;
7493 edit = XtNameToWidget(dialog, "*value");
7494 XtSetKeyboardFocus(popup, edit);
7502 if (*name == NULLCHAR) {
7504 } else if (strcmp(name, "$") == 0) {
7505 putc(BELLCHAR, stderr);
7508 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7516 PlaySound(appData.soundMove);
7522 PlaySound(appData.soundIcsWin);
7528 PlaySound(appData.soundIcsLoss);
7534 PlaySound(appData.soundIcsDraw);
7538 PlayIcsUnfinishedSound()
7540 PlaySound(appData.soundIcsUnfinished);
7546 PlaySound(appData.soundIcsAlarm);
7552 system("stty echo");
7558 system("stty -echo");
7562 Colorize(cc, continuation)
7567 int count, outCount, error;
7569 if (textColors[(int)cc].bg > 0) {
7570 if (textColors[(int)cc].fg > 0) {
7571 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7572 textColors[(int)cc].fg, textColors[(int)cc].bg);
7574 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7575 textColors[(int)cc].bg);
7578 if (textColors[(int)cc].fg > 0) {
7579 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7580 textColors[(int)cc].fg);
7582 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7585 count = strlen(buf);
7586 outCount = OutputToProcess(NoProc, buf, count, &error);
7587 if (outCount < count) {
7588 DisplayFatalError(_("Error writing to display"), error, 1);
7591 if (continuation) return;
7594 PlaySound(appData.soundShout);
7597 PlaySound(appData.soundSShout);
7600 PlaySound(appData.soundChannel1);
7603 PlaySound(appData.soundChannel);
7606 PlaySound(appData.soundKibitz);
7609 PlaySound(appData.soundTell);
7611 case ColorChallenge:
7612 PlaySound(appData.soundChallenge);
7615 PlaySound(appData.soundRequest);
7618 PlaySound(appData.soundSeek);
7629 return getpwuid(getuid())->pw_name;
7633 ExpandPathName(path)
7636 static char static_buf[4*MSG_SIZ];
7637 char *d, *s, buf[4*MSG_SIZ];
7643 while (*s && isspace(*s))
7652 if (*(s+1) == '/') {
7653 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7657 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7658 { char *p; if(p = strchr(buf, '/')) *p = 0; }
7659 pwd = getpwnam(buf);
7662 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7666 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7667 strcat(d, strchr(s+1, '/'));
7671 safeStrCpy(d, s, 4*MSG_SIZ );
7678 static char host_name[MSG_SIZ];
7680 #if HAVE_GETHOSTNAME
7681 gethostname(host_name, MSG_SIZ);
7683 #else /* not HAVE_GETHOSTNAME */
7684 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7685 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7687 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7689 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7690 #endif /* not HAVE_GETHOSTNAME */
7693 XtIntervalId delayedEventTimerXID = 0;
7694 DelayedEventCallback delayedEventCallback = 0;
7699 delayedEventTimerXID = 0;
7700 delayedEventCallback();
7704 ScheduleDelayedEvent(cb, millisec)
7705 DelayedEventCallback cb; long millisec;
7707 if(delayedEventTimerXID && delayedEventCallback == cb)
7708 // [HGM] alive: replace, rather than add or flush identical event
7709 XtRemoveTimeOut(delayedEventTimerXID);
7710 delayedEventCallback = cb;
7711 delayedEventTimerXID =
7712 XtAppAddTimeOut(appContext, millisec,
7713 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7716 DelayedEventCallback
7719 if (delayedEventTimerXID) {
7720 return delayedEventCallback;
7727 CancelDelayedEvent()
7729 if (delayedEventTimerXID) {
7730 XtRemoveTimeOut(delayedEventTimerXID);
7731 delayedEventTimerXID = 0;
7735 XtIntervalId loadGameTimerXID = 0;
7737 int LoadGameTimerRunning()
7739 return loadGameTimerXID != 0;
7742 int StopLoadGameTimer()
7744 if (loadGameTimerXID != 0) {
7745 XtRemoveTimeOut(loadGameTimerXID);
7746 loadGameTimerXID = 0;
7754 LoadGameTimerCallback(arg, id)
7758 loadGameTimerXID = 0;
7763 StartLoadGameTimer(millisec)
7767 XtAppAddTimeOut(appContext, millisec,
7768 (XtTimerCallbackProc) LoadGameTimerCallback,
7772 XtIntervalId analysisClockXID = 0;
7775 AnalysisClockCallback(arg, id)
7779 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7780 || appData.icsEngineAnalyze) { // [DM]
7781 AnalysisPeriodicEvent(0);
7782 StartAnalysisClock();
7787 StartAnalysisClock()
7790 XtAppAddTimeOut(appContext, 2000,
7791 (XtTimerCallbackProc) AnalysisClockCallback,
7795 XtIntervalId clockTimerXID = 0;
7797 int ClockTimerRunning()
7799 return clockTimerXID != 0;
7802 int StopClockTimer()
7804 if (clockTimerXID != 0) {
7805 XtRemoveTimeOut(clockTimerXID);
7814 ClockTimerCallback(arg, id)
7823 StartClockTimer(millisec)
7827 XtAppAddTimeOut(appContext, millisec,
7828 (XtTimerCallbackProc) ClockTimerCallback,
7833 DisplayTimerLabel(w, color, timer, highlight)
7842 /* check for low time warning */
7843 Pixel foregroundOrWarningColor = timerForegroundPixel;
7846 appData.lowTimeWarning &&
7847 (timer / 1000) < appData.icsAlarmTime)
7848 foregroundOrWarningColor = lowTimeWarningColor;
7850 if (appData.clockMode) {
7851 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7852 XtSetArg(args[0], XtNlabel, buf);
7854 snprintf(buf, MSG_SIZ, "%s ", color);
7855 XtSetArg(args[0], XtNlabel, buf);
7860 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7861 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7863 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7864 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7867 XtSetValues(w, args, 3);
7871 DisplayWhiteClock(timeRemaining, highlight)
7877 if(appData.noGUI) return;
7878 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7879 if (highlight && iconPixmap == bIconPixmap) {
7880 iconPixmap = wIconPixmap;
7881 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7882 XtSetValues(shellWidget, args, 1);
7887 DisplayBlackClock(timeRemaining, highlight)
7893 if(appData.noGUI) return;
7894 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7895 if (highlight && iconPixmap == wIconPixmap) {
7896 iconPixmap = bIconPixmap;
7897 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7898 XtSetValues(shellWidget, args, 1);
7916 int StartChildProcess(cmdLine, dir, pr)
7923 int to_prog[2], from_prog[2];
7927 if (appData.debugMode) {
7928 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7931 /* We do NOT feed the cmdLine to the shell; we just
7932 parse it into blank-separated arguments in the
7933 most simple-minded way possible.
7936 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7939 while(*p == ' ') p++;
7941 if(*p == '"' || *p == '\'')
7942 p = strchr(++argv[i-1], *p);
7943 else p = strchr(p, ' ');
7944 if (p == NULL) break;
7949 SetUpChildIO(to_prog, from_prog);
7951 if ((pid = fork()) == 0) {
7953 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7954 close(to_prog[1]); // first close the unused pipe ends
7955 close(from_prog[0]);
7956 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7957 dup2(from_prog[1], 1);
7958 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7959 close(from_prog[1]); // and closing again loses one of the pipes!
7960 if(fileno(stderr) >= 2) // better safe than sorry...
7961 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7963 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7968 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7970 execvp(argv[0], argv);
7972 /* If we get here, exec failed */
7977 /* Parent process */
7979 close(from_prog[1]);
7981 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7984 cp->fdFrom = from_prog[0];
7985 cp->fdTo = to_prog[1];
7990 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7991 static RETSIGTYPE AlarmCallBack(int n)
7997 DestroyChildProcess(pr, signalType)
8001 ChildProc *cp = (ChildProc *) pr;
8003 if (cp->kind != CPReal) return;
8005 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
8006 signal(SIGALRM, AlarmCallBack);
8008 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
8009 kill(cp->pid, SIGKILL); // kill it forcefully
8010 wait((int *) 0); // and wait again
8014 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
8016 /* Process is exiting either because of the kill or because of
8017 a quit command sent by the backend; either way, wait for it to die.
8026 InterruptChildProcess(pr)
8029 ChildProc *cp = (ChildProc *) pr;
8031 if (cp->kind != CPReal) return;
8032 (void) kill(cp->pid, SIGINT); /* stop it thinking */
8035 int OpenTelnet(host, port, pr)
8040 char cmdLine[MSG_SIZ];
8042 if (port[0] == NULLCHAR) {
8043 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
8045 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
8047 return StartChildProcess(cmdLine, "", pr);
8050 int OpenTCP(host, port, pr)
8056 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
8057 #else /* !OMIT_SOCKETS */
8059 struct sockaddr_in sa;
8061 unsigned short uport;
8064 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
8068 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
8069 sa.sin_family = AF_INET;
8070 sa.sin_addr.s_addr = INADDR_ANY;
8071 uport = (unsigned short) 0;
8072 sa.sin_port = htons(uport);
8073 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
8077 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
8078 if (!(hp = gethostbyname(host))) {
8080 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
8081 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
8082 hp->h_addrtype = AF_INET;
8084 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
8085 hp->h_addr_list[0] = (char *) malloc(4);
8086 hp->h_addr_list[0][0] = b0;
8087 hp->h_addr_list[0][1] = b1;
8088 hp->h_addr_list[0][2] = b2;
8089 hp->h_addr_list[0][3] = b3;
8094 sa.sin_family = hp->h_addrtype;
8095 uport = (unsigned short) atoi(port);
8096 sa.sin_port = htons(uport);
8097 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
8099 if (connect(s, (struct sockaddr *) &sa,
8100 sizeof(struct sockaddr_in)) < 0) {
8104 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8111 #endif /* !OMIT_SOCKETS */
8116 int OpenCommPort(name, pr)
8123 fd = open(name, 2, 0);
8124 if (fd < 0) return errno;
8126 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8136 int OpenLoopback(pr)
8142 SetUpChildIO(to, from);
8144 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8147 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
8154 int OpenRcmd(host, user, cmd, pr)
8155 char *host, *user, *cmd;
8158 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
8162 #define INPUT_SOURCE_BUF_SIZE 8192
8171 char buf[INPUT_SOURCE_BUF_SIZE];
8176 DoInputCallback(closure, source, xid)
8181 InputSource *is = (InputSource *) closure;
8186 if (is->lineByLine) {
8187 count = read(is->fd, is->unused,
8188 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
8190 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
8193 is->unused += count;
8195 while (p < is->unused) {
8196 q = memchr(p, '\n', is->unused - p);
8197 if (q == NULL) break;
8199 (is->func)(is, is->closure, p, q - p, 0);
8203 while (p < is->unused) {
8208 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8213 (is->func)(is, is->closure, is->buf, count, error);
8217 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8224 ChildProc *cp = (ChildProc *) pr;
8226 is = (InputSource *) calloc(1, sizeof(InputSource));
8227 is->lineByLine = lineByLine;
8231 is->fd = fileno(stdin);
8233 is->kind = cp->kind;
8234 is->fd = cp->fdFrom;
8237 is->unused = is->buf;
8240 is->xid = XtAppAddInput(appContext, is->fd,
8241 (XtPointer) (XtInputReadMask),
8242 (XtInputCallbackProc) DoInputCallback,
8244 is->closure = closure;
8245 return (InputSourceRef) is;
8249 RemoveInputSource(isr)
8252 InputSource *is = (InputSource *) isr;
8254 if (is->xid == 0) return;
8255 XtRemoveInput(is->xid);
8259 int OutputToProcess(pr, message, count, outError)
8265 static int line = 0;
8266 ChildProc *cp = (ChildProc *) pr;
8271 if (appData.noJoin || !appData.useInternalWrap)
8272 outCount = fwrite(message, 1, count, stdout);
8275 int width = get_term_width();
8276 int len = wrap(NULL, message, count, width, &line);
8277 char *msg = malloc(len);
8281 outCount = fwrite(message, 1, count, stdout);
8284 dbgchk = wrap(msg, message, count, width, &line);
8285 if (dbgchk != len && appData.debugMode)
8286 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8287 outCount = fwrite(msg, 1, dbgchk, stdout);
8293 outCount = write(cp->fdTo, message, count);
8303 /* Output message to process, with "ms" milliseconds of delay
8304 between each character. This is needed when sending the logon
8305 script to ICC, which for some reason doesn't like the
8306 instantaneous send. */
8307 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8314 ChildProc *cp = (ChildProc *) pr;
8319 r = write(cp->fdTo, message++, 1);
8332 /**** Animation code by Hugh Fisher, DCS, ANU.
8334 Known problem: if a window overlapping the board is
8335 moved away while a piece is being animated underneath,
8336 the newly exposed area won't be updated properly.
8337 I can live with this.
8339 Known problem: if you look carefully at the animation
8340 of pieces in mono mode, they are being drawn as solid
8341 shapes without interior detail while moving. Fixing
8342 this would be a major complication for minimal return.
8345 /* Masks for XPM pieces. Black and white pieces can have
8346 different shapes, but in the interest of retaining my
8347 sanity pieces must have the same outline on both light
8348 and dark squares, and all pieces must use the same
8349 background square colors/images. */
8351 static int xpmDone = 0;
8354 CreateAnimMasks (pieceDepth)
8361 unsigned long plane;
8364 /* Need a bitmap just to get a GC with right depth */
8365 buf = XCreatePixmap(xDisplay, xBoardWindow,
8367 values.foreground = 1;
8368 values.background = 0;
8369 /* Don't use XtGetGC, not read only */
8370 maskGC = XCreateGC(xDisplay, buf,
8371 GCForeground | GCBackground, &values);
8372 XFreePixmap(xDisplay, buf);
8374 buf = XCreatePixmap(xDisplay, xBoardWindow,
8375 squareSize, squareSize, pieceDepth);
8376 values.foreground = XBlackPixel(xDisplay, xScreen);
8377 values.background = XWhitePixel(xDisplay, xScreen);
8378 bufGC = XCreateGC(xDisplay, buf,
8379 GCForeground | GCBackground, &values);
8381 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8382 /* Begin with empty mask */
8383 if(!xpmDone) // [HGM] pieces: keep using existing
8384 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8385 squareSize, squareSize, 1);
8386 XSetFunction(xDisplay, maskGC, GXclear);
8387 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8388 0, 0, squareSize, squareSize);
8390 /* Take a copy of the piece */
8395 XSetFunction(xDisplay, bufGC, GXcopy);
8396 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8398 0, 0, squareSize, squareSize, 0, 0);
8400 /* XOR the background (light) over the piece */
8401 XSetFunction(xDisplay, bufGC, GXxor);
8403 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8404 0, 0, squareSize, squareSize, 0, 0);
8406 XSetForeground(xDisplay, bufGC, lightSquareColor);
8407 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8410 /* We now have an inverted piece image with the background
8411 erased. Construct mask by just selecting all the non-zero
8412 pixels - no need to reconstruct the original image. */
8413 XSetFunction(xDisplay, maskGC, GXor);
8415 /* Might be quicker to download an XImage and create bitmap
8416 data from it rather than this N copies per piece, but it
8417 only takes a fraction of a second and there is a much
8418 longer delay for loading the pieces. */
8419 for (n = 0; n < pieceDepth; n ++) {
8420 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8421 0, 0, squareSize, squareSize,
8427 XFreePixmap(xDisplay, buf);
8428 XFreeGC(xDisplay, bufGC);
8429 XFreeGC(xDisplay, maskGC);
8433 InitAnimState (anim, info)
8435 XWindowAttributes * info;
8440 /* Each buffer is square size, same depth as window */
8441 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8442 squareSize, squareSize, info->depth);
8443 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8444 squareSize, squareSize, info->depth);
8446 /* Create a plain GC for blitting */
8447 mask = GCForeground | GCBackground | GCFunction |
8448 GCPlaneMask | GCGraphicsExposures;
8449 values.foreground = XBlackPixel(xDisplay, xScreen);
8450 values.background = XWhitePixel(xDisplay, xScreen);
8451 values.function = GXcopy;
8452 values.plane_mask = AllPlanes;
8453 values.graphics_exposures = False;
8454 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8456 /* Piece will be copied from an existing context at
8457 the start of each new animation/drag. */
8458 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8460 /* Outline will be a read-only copy of an existing */
8461 anim->outlineGC = None;
8467 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8468 XWindowAttributes info;
8470 if (xpmDone && gameInfo.variant == old) return;
8471 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8472 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8474 InitAnimState(&game, &info);
8475 InitAnimState(&player, &info);
8477 /* For XPM pieces, we need bitmaps to use as masks. */
8479 CreateAnimMasks(info.depth);
8485 static Boolean frameWaiting;
8487 static RETSIGTYPE FrameAlarm (sig)
8490 frameWaiting = False;
8491 /* In case System-V style signals. Needed?? */
8492 signal(SIGALRM, FrameAlarm);
8499 struct itimerval delay;
8501 XSync(xDisplay, False);
8504 frameWaiting = True;
8505 signal(SIGALRM, FrameAlarm);
8506 delay.it_interval.tv_sec =
8507 delay.it_value.tv_sec = time / 1000;
8508 delay.it_interval.tv_usec =
8509 delay.it_value.tv_usec = (time % 1000) * 1000;
8510 setitimer(ITIMER_REAL, &delay, NULL);
8511 while (frameWaiting) pause();
8512 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8513 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8514 setitimer(ITIMER_REAL, &delay, NULL);
8524 XSync(xDisplay, False);
8526 usleep(time * 1000);
8531 /* Convert board position to corner of screen rect and color */
8534 ScreenSquare(column, row, pt, color)
8535 int column; int row; XPoint * pt; int * color;
8538 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8539 pt->y = lineGap + row * (squareSize + lineGap);
8541 pt->x = lineGap + column * (squareSize + lineGap);
8542 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8544 *color = SquareColor(row, column);
8547 /* Convert window coords to square */
8550 BoardSquare(x, y, column, row)
8551 int x; int y; int * column; int * row;
8553 *column = EventToSquare(x, BOARD_WIDTH);
8554 if (flipView && *column >= 0)
8555 *column = BOARD_WIDTH - 1 - *column;
8556 *row = EventToSquare(y, BOARD_HEIGHT);
8557 if (!flipView && *row >= 0)
8558 *row = BOARD_HEIGHT - 1 - *row;
8563 #undef Max /* just in case */
8565 #define Max(a, b) ((a) > (b) ? (a) : (b))
8566 #define Min(a, b) ((a) < (b) ? (a) : (b))
8569 SetRect(rect, x, y, width, height)
8570 XRectangle * rect; int x; int y; int width; int height;
8574 rect->width = width;
8575 rect->height = height;
8578 /* Test if two frames overlap. If they do, return
8579 intersection rect within old and location of
8580 that rect within new. */
8583 Intersect(old, new, size, area, pt)
8584 XPoint * old; XPoint * new;
8585 int size; XRectangle * area; XPoint * pt;
8587 if (old->x > new->x + size || new->x > old->x + size ||
8588 old->y > new->y + size || new->y > old->y + size) {
8591 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8592 size - abs(old->x - new->x), size - abs(old->y - new->y));
8593 pt->x = Max(old->x - new->x, 0);
8594 pt->y = Max(old->y - new->y, 0);
8599 /* For two overlapping frames, return the rect(s)
8600 in the old that do not intersect with the new. */
8603 CalcUpdateRects(old, new, size, update, nUpdates)
8604 XPoint * old; XPoint * new; int size;
8605 XRectangle update[]; int * nUpdates;
8609 /* If old = new (shouldn't happen) then nothing to draw */
8610 if (old->x == new->x && old->y == new->y) {
8614 /* Work out what bits overlap. Since we know the rects
8615 are the same size we don't need a full intersect calc. */
8617 /* Top or bottom edge? */
8618 if (new->y > old->y) {
8619 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8621 } else if (old->y > new->y) {
8622 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8623 size, old->y - new->y);
8626 /* Left or right edge - don't overlap any update calculated above. */
8627 if (new->x > old->x) {
8628 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8629 new->x - old->x, size - abs(new->y - old->y));
8631 } else if (old->x > new->x) {
8632 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8633 old->x - new->x, size - abs(new->y - old->y));
8640 /* Generate a series of frame coords from start->mid->finish.
8641 The movement rate doubles until the half way point is
8642 reached, then halves back down to the final destination,
8643 which gives a nice slow in/out effect. The algorithmn
8644 may seem to generate too many intermediates for short
8645 moves, but remember that the purpose is to attract the
8646 viewers attention to the piece about to be moved and
8647 then to where it ends up. Too few frames would be less
8651 Tween(start, mid, finish, factor, frames, nFrames)
8652 XPoint * start; XPoint * mid;
8653 XPoint * finish; int factor;
8654 XPoint frames[]; int * nFrames;
8656 int fraction, n, count;
8660 /* Slow in, stepping 1/16th, then 1/8th, ... */
8662 for (n = 0; n < factor; n++)
8664 for (n = 0; n < factor; n++) {
8665 frames[count].x = start->x + (mid->x - start->x) / fraction;
8666 frames[count].y = start->y + (mid->y - start->y) / fraction;
8668 fraction = fraction / 2;
8672 frames[count] = *mid;
8675 /* Slow out, stepping 1/2, then 1/4, ... */
8677 for (n = 0; n < factor; n++) {
8678 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8679 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8681 fraction = fraction * 2;
8686 /* Draw a piece on the screen without disturbing what's there */
8689 SelectGCMask(piece, clip, outline, mask)
8690 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8694 /* Bitmap for piece being moved. */
8695 if (appData.monoMode) {
8696 *mask = *pieceToSolid(piece);
8697 } else if (useImages) {
8699 *mask = xpmMask[piece];
8701 *mask = ximMaskPm[piece];
8704 *mask = *pieceToSolid(piece);
8707 /* GC for piece being moved. Square color doesn't matter, but
8708 since it gets modified we make a copy of the original. */
8710 if (appData.monoMode)
8715 if (appData.monoMode)
8720 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8722 /* Outline only used in mono mode and is not modified */
8724 *outline = bwPieceGC;
8726 *outline = wbPieceGC;
8730 OverlayPiece(piece, clip, outline, dest)
8731 ChessSquare piece; GC clip; GC outline; Drawable dest;
8736 /* Draw solid rectangle which will be clipped to shape of piece */
8737 XFillRectangle(xDisplay, dest, clip,
8738 0, 0, squareSize, squareSize);
8739 if (appData.monoMode)
8740 /* Also draw outline in contrasting color for black
8741 on black / white on white cases */
8742 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8743 0, 0, squareSize, squareSize, 0, 0, 1);
8745 /* Copy the piece */
8750 if(appData.upsideDown && flipView) kind ^= 2;
8751 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8753 0, 0, squareSize, squareSize,
8758 /* Animate the movement of a single piece */
8761 BeginAnimation(anim, piece, startColor, start)
8769 /* The old buffer is initialised with the start square (empty) */
8770 BlankSquare(start->x, start->y, startColor, EmptySquare, anim->saveBuf, 0);
8771 anim->prevFrame = *start;
8773 /* The piece will be drawn using its own bitmap as a matte */
8774 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8775 XSetClipMask(xDisplay, anim->pieceGC, mask);
8779 AnimationFrame(anim, frame, piece)
8784 XRectangle updates[4];
8789 /* Save what we are about to draw into the new buffer */
8790 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8791 frame->x, frame->y, squareSize, squareSize,
8794 /* Erase bits of the previous frame */
8795 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8796 /* Where the new frame overlapped the previous,
8797 the contents in newBuf are wrong. */
8798 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8799 overlap.x, overlap.y,
8800 overlap.width, overlap.height,
8802 /* Repaint the areas in the old that don't overlap new */
8803 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8804 for (i = 0; i < count; i++)
8805 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8806 updates[i].x - anim->prevFrame.x,
8807 updates[i].y - anim->prevFrame.y,
8808 updates[i].width, updates[i].height,
8809 updates[i].x, updates[i].y);
8811 /* Easy when no overlap */
8812 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8813 0, 0, squareSize, squareSize,
8814 anim->prevFrame.x, anim->prevFrame.y);
8817 /* Save this frame for next time round */
8818 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8819 0, 0, squareSize, squareSize,
8821 anim->prevFrame = *frame;
8823 /* Draw piece over original screen contents, not current,
8824 and copy entire rect. Wipes out overlapping piece images. */
8825 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8826 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8827 0, 0, squareSize, squareSize,
8828 frame->x, frame->y);
8832 EndAnimation (anim, finish)
8836 XRectangle updates[4];
8841 /* The main code will redraw the final square, so we
8842 only need to erase the bits that don't overlap. */
8843 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8844 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8845 for (i = 0; i < count; i++)
8846 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8847 updates[i].x - anim->prevFrame.x,
8848 updates[i].y - anim->prevFrame.y,
8849 updates[i].width, updates[i].height,
8850 updates[i].x, updates[i].y);
8852 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8853 0, 0, squareSize, squareSize,
8854 anim->prevFrame.x, anim->prevFrame.y);
8859 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8861 ChessSquare piece; int startColor;
8862 XPoint * start; XPoint * finish;
8863 XPoint frames[]; int nFrames;
8867 BeginAnimation(anim, piece, startColor, start);
8868 for (n = 0; n < nFrames; n++) {
8869 AnimationFrame(anim, &(frames[n]), piece);
8870 FrameDelay(appData.animSpeed);
8872 EndAnimation(anim, finish);
8876 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
8879 ChessSquare piece = board[fromY][toY];
8880 board[fromY][toY] = EmptySquare;
8881 DrawPosition(FALSE, board);
8883 x = lineGap + ((BOARD_WIDTH-1)-toX) * (squareSize + lineGap);
8884 y = lineGap + toY * (squareSize + lineGap);
8886 x = lineGap + toX * (squareSize + lineGap);
8887 y = lineGap + ((BOARD_HEIGHT-1)-toY) * (squareSize + lineGap);
8889 for(i=1; i<4*kFactor; i++) {
8890 int r = squareSize * 9 * i/(20*kFactor - 5);
8891 XFillArc(xDisplay, xBoardWindow, highlineGC,
8892 x + squareSize/2 - r, y+squareSize/2 - r, 2*r, 2*r, 0, 64*360);
8893 FrameDelay(appData.animSpeed);
8895 board[fromY][toY] = piece;
8898 /* Main control logic for deciding what to animate and how */
8901 AnimateMove(board, fromX, fromY, toX, toY)
8910 XPoint start, finish, mid;
8911 XPoint frames[kFactor * 2 + 1];
8912 int nFrames, startColor, endColor;
8914 /* Are we animating? */
8915 if (!appData.animate || appData.blindfold)
8918 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8919 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8920 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8922 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8923 piece = board[fromY][fromX];
8924 if (piece >= EmptySquare) return;
8929 hop = abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1;
8932 if (appData.debugMode) {
8933 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8934 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8935 piece, fromX, fromY, toX, toY); }
8937 ScreenSquare(fromX, fromY, &start, &startColor);
8938 ScreenSquare(toX, toY, &finish, &endColor);
8941 /* Knight: make straight movement then diagonal */
8942 if (abs(toY - fromY) < abs(toX - fromX)) {
8943 mid.x = start.x + (finish.x - start.x) / 2;
8947 mid.y = start.y + (finish.y - start.y) / 2;
8950 mid.x = start.x + (finish.x - start.x) / 2;
8951 mid.y = start.y + (finish.y - start.y) / 2;
8954 /* Don't use as many frames for very short moves */
8955 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8956 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8958 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8959 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8960 if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged
8962 for(i=0; i<BOARD_WIDTH; i++) for(j=0; j<BOARD_HEIGHT; j++)
8963 if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] = True;
8966 /* Be sure end square is redrawn */
8967 damage[0][toY][toX] = True;
8971 DragPieceBegin(x, y)
8974 int boardX, boardY, color;
8977 /* Are we animating? */
8978 if (!appData.animateDragging || appData.blindfold)
8981 /* Figure out which square we start in and the
8982 mouse position relative to top left corner. */
8983 BoardSquare(x, y, &boardX, &boardY);
8984 player.startBoardX = boardX;
8985 player.startBoardY = boardY;
8986 ScreenSquare(boardX, boardY, &corner, &color);
8987 player.startSquare = corner;
8988 player.startColor = color;
8989 /* As soon as we start dragging, the piece will jump slightly to
8990 be centered over the mouse pointer. */
8991 player.mouseDelta.x = squareSize/2;
8992 player.mouseDelta.y = squareSize/2;
8993 /* Initialise animation */
8994 player.dragPiece = PieceForSquare(boardX, boardY);
8996 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8997 player.dragActive = True;
8998 BeginAnimation(&player, player.dragPiece, color, &corner);
8999 /* Mark this square as needing to be redrawn. Note that
9000 we don't remove the piece though, since logically (ie
9001 as seen by opponent) the move hasn't been made yet. */
9002 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
9003 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
9004 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
9005 corner.x, corner.y, squareSize, squareSize,
9006 0, 0); // [HGM] zh: unstack in stead of grab
9007 if(gatingPiece != EmptySquare) {
9008 /* Kludge alert: When gating we want the introduced
9009 piece to appear on the from square. To generate an
9010 image of it, we draw it on the board, copy the image,
9011 and draw the original piece again. */
9012 ChessSquare piece = boards[currentMove][boardY][boardX];
9013 DrawSquare(boardY, boardX, gatingPiece, 0);
9014 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
9015 corner.x, corner.y, squareSize, squareSize, 0, 0);
9016 DrawSquare(boardY, boardX, piece, 0);
9018 damage[0][boardY][boardX] = True;
9020 player.dragActive = False;
9030 /* Are we animating? */
9031 if (!appData.animateDragging || appData.blindfold)
9035 if (! player.dragActive)
9037 /* Move piece, maintaining same relative position
9038 of mouse within square */
9039 corner.x = x - player.mouseDelta.x;
9040 corner.y = y - player.mouseDelta.y;
9041 AnimationFrame(&player, &corner, player.dragPiece);
9043 if (appData.highlightDragging) {
9045 BoardSquare(x, y, &boardX, &boardY);
9046 SetHighlights(fromX, fromY, boardX, boardY);
9055 int boardX, boardY, color;
9058 /* Are we animating? */
9059 if (!appData.animateDragging || appData.blindfold)
9063 if (! player.dragActive)
9065 /* Last frame in sequence is square piece is
9066 placed on, which may not match mouse exactly. */
9067 BoardSquare(x, y, &boardX, &boardY);
9068 ScreenSquare(boardX, boardY, &corner, &color);
9069 EndAnimation(&player, &corner);
9071 /* Be sure end square is redrawn */
9072 damage[0][boardY][boardX] = True;
9074 /* This prevents weird things happening with fast successive
9075 clicks which on my Sun at least can cause motion events
9076 without corresponding press/release. */
9077 player.dragActive = False;
9080 /* Handle expose event while piece being dragged */
9085 if (!player.dragActive || appData.blindfold)
9088 /* What we're doing: logically, the move hasn't been made yet,
9089 so the piece is still in it's original square. But visually
9090 it's being dragged around the board. So we erase the square
9091 that the piece is on and draw it at the last known drag point. */
9092 BlankSquare(player.startSquare.x, player.startSquare.y,
9093 player.startColor, EmptySquare, xBoardWindow, 1);
9094 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
9095 damage[0][player.startBoardY][player.startBoardX] = TRUE;
9098 #include <sys/ioctl.h>
9099 int get_term_width()
9101 int fd, default_width;
9104 default_width = 79; // this is FICS default anyway...
9106 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
9108 if (!ioctl(fd, TIOCGSIZE, &win))
9109 default_width = win.ts_cols;
9110 #elif defined(TIOCGWINSZ)
9112 if (!ioctl(fd, TIOCGWINSZ, &win))
9113 default_width = win.ws_col;
9115 return default_width;
9121 static int old_width = 0;
9122 int new_width = get_term_width();
9124 if (old_width != new_width)
9125 ics_printf("set width %d\n", new_width);
9126 old_width = new_width;
9129 void NotifyFrontendLogin()
9134 /* [AS] Arrow highlighting support */
9136 static double A_WIDTH = 5; /* Width of arrow body */
9138 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
9139 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
9141 static double Sqr( double x )
9146 static int Round( double x )
9148 return (int) (x + 0.5);
9151 void SquareToPos(int rank, int file, int *x, int *y)
9154 *x = lineGap + ((BOARD_WIDTH-1)-file) * (squareSize + lineGap);
9155 *y = lineGap + rank * (squareSize + lineGap);
9157 *x = lineGap + file * (squareSize + lineGap);
9158 *y = lineGap + ((BOARD_HEIGHT-1)-rank) * (squareSize + lineGap);
9162 /* Draw an arrow between two points using current settings */
9163 void DrawArrowBetweenPoints( int s_x, int s_y, int d_x, int d_y )
9166 double dx, dy, j, k, x, y;
9169 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
9171 arrow[0].x = s_x + A_WIDTH + 0.5;
9174 arrow[1].x = s_x + A_WIDTH + 0.5;
9175 arrow[1].y = d_y - h;
9177 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9178 arrow[2].y = d_y - h;
9183 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
9184 arrow[5].y = d_y - h;
9186 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9187 arrow[4].y = d_y - h;
9189 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
9192 else if( d_y == s_y ) {
9193 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
9196 arrow[0].y = s_y + A_WIDTH + 0.5;
9198 arrow[1].x = d_x - w;
9199 arrow[1].y = s_y + A_WIDTH + 0.5;
9201 arrow[2].x = d_x - w;
9202 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9207 arrow[5].x = d_x - w;
9208 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
9210 arrow[4].x = d_x - w;
9211 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9214 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
9217 /* [AS] Needed a lot of paper for this! :-) */
9218 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
9219 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
9221 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
9223 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
9228 arrow[0].x = Round(x - j);
9229 arrow[0].y = Round(y + j*dx);
9231 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
9232 arrow[1].y = Round(arrow[0].y - 2*j*dx);
9235 x = (double) d_x - k;
9236 y = (double) d_y - k*dy;
9239 x = (double) d_x + k;
9240 y = (double) d_y + k*dy;
9243 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
9245 arrow[6].x = Round(x - j);
9246 arrow[6].y = Round(y + j*dx);
9248 arrow[2].x = Round(arrow[6].x + 2*j);
9249 arrow[2].y = Round(arrow[6].y - 2*j*dx);
9251 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
9252 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
9257 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
9258 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
9261 XFillPolygon(xDisplay, xBoardWindow, highlineGC, arrow, 7, Nonconvex, CoordModeOrigin);
9262 // Polygon( hdc, arrow, 7 );
9265 /* [AS] Draw an arrow between two squares */
9266 void DrawArrowBetweenSquares( int s_col, int s_row, int d_col, int d_row )
9268 int s_x, s_y, d_x, d_y, hor, vert, i;
9270 if( s_col == d_col && s_row == d_row ) {
9274 /* Get source and destination points */
9275 SquareToPos( s_row, s_col, &s_x, &s_y);
9276 SquareToPos( d_row, d_col, &d_x, &d_y);
9279 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
9281 else if( d_y < s_y ) {
9282 d_y += squareSize / 2 + squareSize / 4;
9285 d_y += squareSize / 2;
9289 d_x += squareSize / 2 - squareSize / 4;
9291 else if( d_x < s_x ) {
9292 d_x += squareSize / 2 + squareSize / 4;
9295 d_x += squareSize / 2;
9298 s_x += squareSize / 2;
9299 s_y += squareSize / 2;
9302 A_WIDTH = squareSize / 14.; //[HGM] make float
9304 DrawArrowBetweenPoints( s_x, s_y, d_x, d_y );
9307 // this is a good idea, but it only works when lineGap == 0, because 'damage' on grid lines is not repaired
9308 hor = 64*s_col + 32; vert = 64*s_row + 32;
9309 for(i=0; i<= 64; i++) {
9310 damage[0][vert+6>>6][hor+6>>6] = True;
9311 damage[0][vert-6>>6][hor+6>>6] = True;
9312 damage[0][vert+6>>6][hor-6>>6] = True;
9313 damage[0][vert-6>>6][hor-6>>6] = True;
9314 hor += d_col - s_col; vert += d_row - s_row;
9319 Boolean IsDrawArrowEnabled()
9321 return appData.highlightMoveWithArrow && squareSize >= 32;
9324 void DrawArrowHighlight(int fromX, int fromY, int toX,int toY)
9326 if( IsDrawArrowEnabled() && fromX >= 0 && fromY >= 0 && toX >= 0 && toY >= 0)
9327 DrawArrowBetweenSquares(fromX, fromY, toX, toY);