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 (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4610 if ( lineGap && IsDrawArrowEnabled())
4611 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4612 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4614 /* If too much changes (begin observing new game, etc.), don't
4616 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4618 /* Special check for castling so we don't flash both the king
4619 and the rook (just flash the king). */
4621 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4622 /* Draw rook with NO flashing. King will be drawn flashing later */
4623 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4624 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4628 /* First pass -- Draw (newly) empty squares and repair damage.
4629 This prevents you from having a piece show up twice while it
4630 is flashing on its new square */
4631 for (i = 0; i < BOARD_HEIGHT; i++)
4632 for (j = 0; j < BOARD_WIDTH; j++)
4633 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4634 || damage[nr][i][j]) {
4635 DrawSquare(i, j, board[i][j], 0);
4636 damage[nr][i][j] = False;
4639 /* Second pass -- Draw piece(s) in new position and flash them */
4640 for (i = 0; i < BOARD_HEIGHT; i++)
4641 for (j = 0; j < BOARD_WIDTH; j++)
4642 if (board[i][j] != lastBoard[nr][i][j]) {
4643 DrawSquare(i, j, board[i][j], do_flash);
4647 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4648 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4649 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4651 for (i = 0; i < BOARD_HEIGHT; i++)
4652 for (j = 0; j < BOARD_WIDTH; j++) {
4653 DrawSquare(i, j, board[i][j], 0);
4654 damage[nr][i][j] = False;
4658 CopyBoard(lastBoard[nr], board);
4659 lastBoardValid[nr] = 1;
4660 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4661 lastFlipView = flipView;
4663 /* Draw highlights */
4664 if (pm1X >= 0 && pm1Y >= 0) {
4665 drawHighlight(pm1X, pm1Y, prelineGC);
4667 if (pm2X >= 0 && pm2Y >= 0) {
4668 drawHighlight(pm2X, pm2Y, prelineGC);
4670 if (hi1X >= 0 && hi1Y >= 0) {
4671 drawHighlight(hi1X, hi1Y, highlineGC);
4673 if (hi2X >= 0 && hi2Y >= 0) {
4674 drawHighlight(hi2X, hi2Y, highlineGC);
4676 DrawArrowHighlight(hi1X, hi1Y, hi2X, hi2Y);
4678 /* If piece being dragged around board, must redraw that too */
4681 XSync(xDisplay, False);
4686 * event handler for redrawing the board
4688 void DrawPositionProc(w, event, prms, nprms)
4694 XDrawPosition(w, True, NULL);
4699 * event handler for parsing user moves
4701 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4702 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4703 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4704 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4705 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4706 // and at the end FinishMove() to perform the move after optional promotion popups.
4707 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4708 void HandleUserMove(w, event, prms, nprms)
4714 if (w != boardWidget || errorExitStatus != -1) return;
4715 if(nprms) shiftKey = !strcmp(prms[0], "1");
4718 if (event->type == ButtonPress) {
4719 XtPopdown(promotionShell);
4720 XtDestroyWidget(promotionShell);
4721 promotionUp = False;
4729 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4730 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4731 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4734 void AnimateUserMove (Widget w, XEvent * event,
4735 String * params, Cardinal * nParams)
4737 DragPieceMove(event->xmotion.x, event->xmotion.y);
4740 void HandlePV (Widget w, XEvent * event,
4741 String * params, Cardinal * nParams)
4742 { // [HGM] pv: walk PV
4743 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4746 Widget CommentCreate(name, text, mutable, callback, lines)
4748 int /*Boolean*/ mutable;
4749 XtCallbackProc callback;
4753 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4758 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4759 XtGetValues(boardWidget, args, j);
4762 XtSetArg(args[j], XtNresizable, True); j++;
4765 XtCreatePopupShell(name, topLevelShellWidgetClass,
4766 shellWidget, args, j);
4769 XtCreatePopupShell(name, transientShellWidgetClass,
4770 shellWidget, args, j);
4773 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4774 layoutArgs, XtNumber(layoutArgs));
4776 XtCreateManagedWidget("form", formWidgetClass, layout,
4777 formArgs, XtNumber(formArgs));
4781 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4782 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4784 XtSetArg(args[j], XtNstring, text); j++;
4785 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4786 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4787 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4788 XtSetArg(args[j], XtNright, XtChainRight); j++;
4789 XtSetArg(args[j], XtNresizable, True); j++;
4790 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4791 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4792 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4793 XtSetArg(args[j], XtNautoFill, True); j++;
4794 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4796 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4797 XtOverrideTranslations(edit, XtParseTranslationTable(commentTranslations));
4801 XtSetArg(args[j], XtNfromVert, edit); j++;
4802 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4803 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4804 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4805 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4807 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4808 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4811 XtSetArg(args[j], XtNfromVert, edit); j++;
4812 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4813 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4814 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4815 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4816 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4818 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4819 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4822 XtSetArg(args[j], XtNfromVert, edit); j++;
4823 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4824 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4825 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4826 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4827 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4829 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4830 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4833 XtSetArg(args[j], XtNfromVert, edit); j++;
4834 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4835 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4836 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4837 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4839 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4840 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4843 XtSetArg(args[j], XtNfromVert, edit); j++;
4844 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4845 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4846 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4847 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4848 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4850 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4851 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4854 XtRealizeWidget(shell);
4856 if (commentX == -1) {
4859 Dimension pw_height;
4860 Dimension ew_height;
4863 XtSetArg(args[j], XtNheight, &ew_height); j++;
4864 XtGetValues(edit, args, j);
4867 XtSetArg(args[j], XtNheight, &pw_height); j++;
4868 XtGetValues(shell, args, j);
4869 commentH = pw_height + (lines - 1) * ew_height;
4870 commentW = bw_width - 16;
4872 XSync(xDisplay, False);
4874 /* This code seems to tickle an X bug if it is executed too soon
4875 after xboard starts up. The coordinates get transformed as if
4876 the main window was positioned at (0, 0).
4878 XtTranslateCoords(shellWidget,
4879 (bw_width - commentW) / 2, 0 - commentH / 2,
4880 &commentX, &commentY);
4882 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4883 RootWindowOfScreen(XtScreen(shellWidget)),
4884 (bw_width - commentW) / 2, 0 - commentH / 2,
4889 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4892 if(wpComment.width > 0) {
4893 commentX = wpComment.x;
4894 commentY = wpComment.y;
4895 commentW = wpComment.width;
4896 commentH = wpComment.height;
4900 XtSetArg(args[j], XtNheight, commentH); j++;
4901 XtSetArg(args[j], XtNwidth, commentW); j++;
4902 XtSetArg(args[j], XtNx, commentX); j++;
4903 XtSetArg(args[j], XtNy, commentY); j++;
4904 XtSetValues(shell, args, j);
4905 XtSetKeyboardFocus(shell, edit);
4910 /* Used for analysis window and ICS input window */
4911 Widget MiscCreate(name, text, mutable, callback, lines)
4913 int /*Boolean*/ mutable;
4914 XtCallbackProc callback;
4918 Widget shell, layout, form, edit;
4920 Dimension bw_width, pw_height, ew_height, w, h;
4926 XtSetArg(args[j], XtNresizable, True); j++;
4929 XtCreatePopupShell(name, topLevelShellWidgetClass,
4930 shellWidget, args, j);
4933 XtCreatePopupShell(name, transientShellWidgetClass,
4934 shellWidget, args, j);
4937 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4938 layoutArgs, XtNumber(layoutArgs));
4940 XtCreateManagedWidget("form", formWidgetClass, layout,
4941 formArgs, XtNumber(formArgs));
4945 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4946 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4948 XtSetArg(args[j], XtNstring, text); j++;
4949 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4950 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4951 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4952 XtSetArg(args[j], XtNright, XtChainRight); j++;
4953 XtSetArg(args[j], XtNresizable, True); j++;
4954 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4955 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4956 XtSetArg(args[j], XtNautoFill, True); j++;
4957 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4959 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4961 XtRealizeWidget(shell);
4964 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4965 XtGetValues(boardWidget, args, j);
4968 XtSetArg(args[j], XtNheight, &ew_height); j++;
4969 XtGetValues(edit, args, j);
4972 XtSetArg(args[j], XtNheight, &pw_height); j++;
4973 XtGetValues(shell, args, j);
4974 h = pw_height + (lines - 1) * ew_height;
4977 XSync(xDisplay, False);
4979 /* This code seems to tickle an X bug if it is executed too soon
4980 after xboard starts up. The coordinates get transformed as if
4981 the main window was positioned at (0, 0).
4983 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4985 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4986 RootWindowOfScreen(XtScreen(shellWidget)),
4987 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4991 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4994 XtSetArg(args[j], XtNheight, h); j++;
4995 XtSetArg(args[j], XtNwidth, w); j++;
4996 XtSetArg(args[j], XtNx, x); j++;
4997 XtSetArg(args[j], XtNy, y); j++;
4998 XtSetValues(shell, args, j);
5004 static int savedIndex; /* gross that this is global */
5006 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
5009 XawTextPosition index, dummy;
5012 XawTextGetSelectionPos(w, &index, &dummy);
5013 XtSetArg(arg, XtNstring, &val);
5014 XtGetValues(w, &arg, 1);
5015 ReplaceComment(savedIndex, val);
5016 if(savedIndex != currentMove) ToNrEvent(savedIndex);
5017 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
5020 void EditCommentPopUp(index, title, text)
5029 if (text == NULL) text = "";
5031 if (editShell == NULL) {
5033 CommentCreate(title, text, True, EditCommentCallback, 4);
5034 XtRealizeWidget(editShell);
5035 CatchDeleteWindow(editShell, "EditCommentPopDown");
5037 edit = XtNameToWidget(editShell, "*form.text");
5039 XtSetArg(args[j], XtNstring, text); j++;
5040 XtSetValues(edit, args, j);
5042 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5043 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5044 XtSetValues(editShell, args, j);
5047 XtPopup(editShell, XtGrabNone);
5051 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5052 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"),
5054 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"),
5058 void EditCommentCallback(w, client_data, call_data)
5060 XtPointer client_data, call_data;
5068 XtSetArg(args[j], XtNlabel, &name); j++;
5069 XtGetValues(w, args, j);
5071 if (strcmp(name, _("ok")) == 0) {
5072 edit = XtNameToWidget(editShell, "*form.text");
5074 XtSetArg(args[j], XtNstring, &val); j++;
5075 XtGetValues(edit, args, j);
5076 ReplaceComment(savedIndex, val);
5077 EditCommentPopDown();
5078 } else if (strcmp(name, _("cancel")) == 0) {
5079 EditCommentPopDown();
5080 } else if (strcmp(name, _("clear")) == 0) {
5081 edit = XtNameToWidget(editShell, "*form.text");
5082 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5083 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5087 void EditCommentPopDown()
5092 if (!editUp) return;
5094 XtSetArg(args[j], XtNx, &commentX); j++;
5095 XtSetArg(args[j], XtNy, &commentY); j++;
5096 XtSetArg(args[j], XtNheight, &commentH); j++;
5097 XtSetArg(args[j], XtNwidth, &commentW); j++;
5098 XtGetValues(editShell, args, j);
5099 XtPopdown(editShell);
5102 XtSetArg(args[j], XtNleftBitmap, None); j++;
5103 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"),
5105 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"),
5109 void ICSInputBoxPopUp()
5114 char *title = _("ICS Input");
5117 if (ICSInputShell == NULL) {
5118 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
5119 tr = XtParseTranslationTable(ICSInputTranslations);
5120 edit = XtNameToWidget(ICSInputShell, "*form.text");
5121 XtOverrideTranslations(edit, tr);
5122 XtRealizeWidget(ICSInputShell);
5123 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
5126 edit = XtNameToWidget(ICSInputShell, "*form.text");
5128 XtSetArg(args[j], XtNstring, ""); j++;
5129 XtSetValues(edit, args, j);
5131 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5132 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5133 XtSetValues(ICSInputShell, args, j);
5136 XtPopup(ICSInputShell, XtGrabNone);
5137 XtSetKeyboardFocus(ICSInputShell, edit);
5139 ICSInputBoxUp = True;
5141 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5142 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.ICS Input Box"),
5146 void ICSInputSendText()
5153 edit = XtNameToWidget(ICSInputShell, "*form.text");
5155 XtSetArg(args[j], XtNstring, &val); j++;
5156 XtGetValues(edit, args, j);
5158 SendMultiLineToICS(val);
5159 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5160 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5163 void ICSInputBoxPopDown()
5168 if (!ICSInputBoxUp) return;
5170 XtPopdown(ICSInputShell);
5171 ICSInputBoxUp = False;
5173 XtSetArg(args[j], XtNleftBitmap, None); j++;
5174 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.ICS Input Box"),
5178 void CommentPopUp(title, text)
5185 savedIndex = currentMove; // [HGM] vari
5186 if (commentShell == NULL) {
5188 CommentCreate(title, text, False, CommentCallback, 4);
5189 XtRealizeWidget(commentShell);
5190 CatchDeleteWindow(commentShell, "CommentPopDown");
5192 edit = XtNameToWidget(commentShell, "*form.text");
5194 XtSetArg(args[j], XtNstring, text); j++;
5195 XtSetValues(edit, args, j);
5197 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5198 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5199 XtSetValues(commentShell, args, j);
5202 XtPopup(commentShell, XtGrabNone);
5203 XSync(xDisplay, False);
5208 void CommentCallback(w, client_data, call_data)
5210 XtPointer client_data, call_data;
5217 XtSetArg(args[j], XtNlabel, &name); j++;
5218 XtGetValues(w, args, j);
5220 if (strcmp(name, _("close")) == 0) {
5222 } else if (strcmp(name, _("edit")) == 0) {
5229 void CommentPopDown()
5234 if (!commentUp) return;
5236 XtSetArg(args[j], XtNx, &commentX); j++;
5237 XtSetArg(args[j], XtNy, &commentY); j++;
5238 XtSetArg(args[j], XtNwidth, &commentW); j++;
5239 XtSetArg(args[j], XtNheight, &commentH); j++;
5240 XtGetValues(commentShell, args, j);
5241 XtPopdown(commentShell);
5242 XSync(xDisplay, False);
5246 void FileNamePopUp(label, def, proc, openMode)
5252 fileProc = proc; /* I can't see a way not */
5253 fileOpenMode = openMode; /* to use globals here */
5254 { // [HGM] use file-selector dialog stolen from Ghostview
5256 int index; // this is not supported yet
5258 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5259 def, openMode, NULL, &name))
5260 (void) (*fileProc)(f, index=0, name);
5264 void FileNamePopDown()
5266 if (!filenameUp) return;
5267 XtPopdown(fileNameShell);
5268 XtDestroyWidget(fileNameShell);
5273 void FileNameCallback(w, client_data, call_data)
5275 XtPointer client_data, call_data;
5280 XtSetArg(args[0], XtNlabel, &name);
5281 XtGetValues(w, args, 1);
5283 if (strcmp(name, _("cancel")) == 0) {
5288 FileNameAction(w, NULL, NULL, NULL);
5291 void FileNameAction(w, event, prms, nprms)
5303 name = XawDialogGetValueString(w = XtParent(w));
5305 if ((name != NULL) && (*name != NULLCHAR)) {
5306 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
5307 XtPopdown(w = XtParent(XtParent(w)));
5311 p = strrchr(buf, ' ');
5318 fullname = ExpandPathName(buf);
5320 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5323 f = fopen(fullname, fileOpenMode);
5325 DisplayError(_("Failed to open file"), errno);
5327 (void) (*fileProc)(f, index, buf);
5334 XtPopdown(w = XtParent(XtParent(w)));
5340 void PromotionPopUp()
5343 Widget dialog, layout;
5345 Dimension bw_width, pw_width;
5349 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5350 XtGetValues(boardWidget, args, j);
5353 XtSetArg(args[j], XtNresizable, True); j++;
5354 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5356 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5357 shellWidget, args, j);
5359 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5360 layoutArgs, XtNumber(layoutArgs));
5363 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5364 XtSetArg(args[j], XtNborderWidth, 0); j++;
5365 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5368 if(gameInfo.variant != VariantShogi) {
5369 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) {
5370 XawDialogAddButton(dialog, _("Warlord"), PromotionCallback,
5371 (XtPointer) dialog);
5372 XawDialogAddButton(dialog, _("General"), PromotionCallback,
5373 (XtPointer) dialog);
5374 XawDialogAddButton(dialog, _("Lieutenant"), PromotionCallback,
5375 (XtPointer) dialog);
5376 XawDialogAddButton(dialog, _("Captain"), PromotionCallback,
5377 (XtPointer) dialog);
5379 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5380 (XtPointer) dialog);
5381 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5382 (XtPointer) dialog);
5383 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5384 (XtPointer) dialog);
5385 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5386 (XtPointer) dialog);
5388 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5389 gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
\r
5390 gameInfo.variant == VariantGiveaway) {
5391 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5392 (XtPointer) dialog);
5394 if(gameInfo.variant == VariantCapablanca ||
5395 gameInfo.variant == VariantGothic ||
5396 gameInfo.variant == VariantCapaRandom) {
5397 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5398 (XtPointer) dialog);
5399 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5400 (XtPointer) dialog);
5402 } else // [HGM] shogi
5404 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5405 (XtPointer) dialog);
5406 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5407 (XtPointer) dialog);
5409 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5410 (XtPointer) dialog);
5412 XtRealizeWidget(promotionShell);
5413 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5416 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5417 XtGetValues(promotionShell, args, j);
5419 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5420 lineGap + squareSize/3 +
5421 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5422 0 : 6*(squareSize + lineGap)), &x, &y);
5425 XtSetArg(args[j], XtNx, x); j++;
5426 XtSetArg(args[j], XtNy, y); j++;
5427 XtSetValues(promotionShell, args, j);
5429 XtPopup(promotionShell, XtGrabNone);
5434 void PromotionPopDown()
5436 if (!promotionUp) return;
5437 XtPopdown(promotionShell);
5438 XtDestroyWidget(promotionShell);
5439 promotionUp = False;
5442 void PromotionCallback(w, client_data, call_data)
5444 XtPointer client_data, call_data;
5450 XtSetArg(args[0], XtNlabel, &name);
5451 XtGetValues(w, args, 1);
5455 if (fromX == -1) return;
5457 if (strcmp(name, _("cancel")) == 0) {
5461 } else if (strcmp(name, _("Knight")) == 0) {
5463 } else if (strcmp(name, _("Promote")) == 0) {
5465 } else if (strcmp(name, _("Defer")) == 0) {
5468 promoChar = ToLower(name[0]);
5471 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5473 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5474 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5479 void ErrorCallback(w, client_data, call_data)
5481 XtPointer client_data, call_data;
5484 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5486 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5492 if (!errorUp) return;
5494 XtPopdown(errorShell);
5495 XtDestroyWidget(errorShell);
5496 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5499 void ErrorPopUp(title, label, modal)
5500 char *title, *label;
5504 Widget dialog, layout;
5508 Dimension bw_width, pw_width;
5509 Dimension pw_height;
5513 XtSetArg(args[i], XtNresizable, True); i++;
5514 XtSetArg(args[i], XtNtitle, title); i++;
5516 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5517 shellWidget, args, i);
5519 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5520 layoutArgs, XtNumber(layoutArgs));
5523 XtSetArg(args[i], XtNlabel, label); i++;
5524 XtSetArg(args[i], XtNborderWidth, 0); i++;
5525 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5528 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5530 XtRealizeWidget(errorShell);
5531 CatchDeleteWindow(errorShell, "ErrorPopDown");
5534 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5535 XtGetValues(boardWidget, args, i);
5537 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5538 XtSetArg(args[i], XtNheight, &pw_height); i++;
5539 XtGetValues(errorShell, args, i);
5542 /* This code seems to tickle an X bug if it is executed too soon
5543 after xboard starts up. The coordinates get transformed as if
5544 the main window was positioned at (0, 0).
5546 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5547 0 - pw_height + squareSize / 3, &x, &y);
5549 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5550 RootWindowOfScreen(XtScreen(boardWidget)),
5551 (bw_width - pw_width) / 2,
5552 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5556 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5559 XtSetArg(args[i], XtNx, x); i++;
5560 XtSetArg(args[i], XtNy, y); i++;
5561 XtSetValues(errorShell, args, i);
5564 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5567 /* Disable all user input other than deleting the window */
5568 static int frozen = 0;
5572 /* Grab by a widget that doesn't accept input */
5573 XtAddGrab(messageWidget, TRUE, FALSE);
5577 /* Undo a FreezeUI */
5580 if (!frozen) return;
5581 XtRemoveGrab(messageWidget);
5585 char *ModeToWidgetName(mode)
5589 case BeginningOfGame:
5590 if (appData.icsActive)
5591 return "menuMode.ICS Client";
5592 else if (appData.noChessProgram ||
5593 *appData.cmailGameName != NULLCHAR)
5594 return "menuMode.Edit Game";
5596 return "menuMode.Machine Black";
5597 case MachinePlaysBlack:
5598 return "menuMode.Machine Black";
5599 case MachinePlaysWhite:
5600 return "menuMode.Machine White";
5602 return "menuMode.Analysis Mode";
5604 return "menuMode.Analyze File";
5605 case TwoMachinesPlay:
5606 return "menuMode.Two Machines";
5608 return "menuMode.Edit Game";
5609 case PlayFromGameFile:
5610 return "menuFile.Load Game";
5612 return "menuMode.Edit Position";
5614 return "menuMode.Training";
5615 case IcsPlayingWhite:
5616 case IcsPlayingBlack:
5620 return "menuMode.ICS Client";
5627 void ModeHighlight()
5630 static int oldPausing = FALSE;
5631 static GameMode oldmode = (GameMode) -1;
5634 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5636 if (pausing != oldPausing) {
5637 oldPausing = pausing;
5639 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5641 XtSetArg(args[0], XtNleftBitmap, None);
5643 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5646 if (appData.showButtonBar) {
5647 /* Always toggle, don't set. Previous code messes up when
5648 invoked while the button is pressed, as releasing it
5649 toggles the state again. */
5652 XtSetArg(args[0], XtNbackground, &oldbg);
5653 XtSetArg(args[1], XtNforeground, &oldfg);
5654 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5656 XtSetArg(args[0], XtNbackground, oldfg);
5657 XtSetArg(args[1], XtNforeground, oldbg);
5659 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5663 wname = ModeToWidgetName(oldmode);
5664 if (wname != NULL) {
5665 XtSetArg(args[0], XtNleftBitmap, None);
5666 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5668 wname = ModeToWidgetName(gameMode);
5669 if (wname != NULL) {
5670 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5671 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5675 /* Maybe all the enables should be handled here, not just this one */
5676 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5677 gameMode == Training || gameMode == PlayFromGameFile);
5682 * Button/menu procedures
5684 void ResetProc(w, event, prms, nprms)
5693 int LoadGamePopUp(f, gameNumber, title)
5698 cmailMsgLoaded = FALSE;
5699 if (gameNumber == 0) {
5700 int error = GameListBuild(f);
5702 DisplayError(_("Cannot build game list"), error);
5703 } else if (!ListEmpty(&gameList) &&
5704 ((ListGame *) gameList.tailPred)->number > 1) {
5705 GameListPopUp(f, title);
5711 return LoadGame(f, gameNumber, title, FALSE);
5714 void LoadGameProc(w, event, prms, nprms)
5720 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5723 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5726 void LoadNextGameProc(w, event, prms, nprms)
5735 void LoadPrevGameProc(w, event, prms, nprms)
5744 void ReloadGameProc(w, event, prms, nprms)
5753 void LoadNextPositionProc(w, event, prms, nprms)
5762 void LoadPrevPositionProc(w, event, prms, nprms)
5771 void ReloadPositionProc(w, event, prms, nprms)
5780 void LoadPositionProc(w, event, prms, nprms)
5786 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5789 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5792 void SaveGameProc(w, event, prms, nprms)
5798 FileNamePopUp(_("Save game file name?"),
5799 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5803 void SavePositionProc(w, event, prms, nprms)
5809 FileNamePopUp(_("Save position file name?"),
5810 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5814 void ReloadCmailMsgProc(w, event, prms, nprms)
5820 ReloadCmailMsgEvent(FALSE);
5823 void MailMoveProc(w, event, prms, nprms)
5832 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5833 char *selected_fen_position=NULL;
5836 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5837 Atom *type_return, XtPointer *value_return,
5838 unsigned long *length_return, int *format_return)
5840 char *selection_tmp;
5842 if (!selected_fen_position) return False; /* should never happen */
5843 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5844 /* note: since no XtSelectionDoneProc was registered, Xt will
5845 * automatically call XtFree on the value returned. So have to
5846 * make a copy of it allocated with XtMalloc */
5847 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5848 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
5850 *value_return=selection_tmp;
5851 *length_return=strlen(selection_tmp);
5852 *type_return=*target;
5853 *format_return = 8; /* bits per byte */
5855 } else if (*target == XA_TARGETS(xDisplay)) {
5856 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5857 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5858 targets_tmp[1] = XA_STRING;
5859 *value_return = targets_tmp;
5860 *type_return = XA_ATOM;
5862 *format_return = 8 * sizeof(Atom);
5863 if (*format_return > 32) {
5864 *length_return *= *format_return / 32;
5865 *format_return = 32;
5873 /* note: when called from menu all parameters are NULL, so no clue what the
5874 * Widget which was clicked on was, or what the click event was
5876 void CopyPositionProc(w, event, prms, nprms)
5883 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5884 * have a notion of a position that is selected but not copied.
5885 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5887 if(gameMode == EditPosition) EditPositionDone(TRUE);
5888 if (selected_fen_position) free(selected_fen_position);
5889 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5890 if (!selected_fen_position) return;
5891 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5893 SendPositionSelection,
5894 NULL/* lose_ownership_proc */ ,
5895 NULL/* transfer_done_proc */);
5896 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5898 SendPositionSelection,
5899 NULL/* lose_ownership_proc */ ,
5900 NULL/* transfer_done_proc */);
5903 /* function called when the data to Paste is ready */
5905 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5906 Atom *type, XtPointer value, unsigned long *len, int *format)
5909 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5910 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5911 EditPositionPasteFEN(fenstr);
5915 /* called when Paste Position button is pressed,
5916 * all parameters will be NULL */
5917 void PastePositionProc(w, event, prms, nprms)
5923 XtGetSelectionValue(menuBarWidget,
5924 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5925 /* (XtSelectionCallbackProc) */ PastePositionCB,
5926 NULL, /* client_data passed to PastePositionCB */
5928 /* better to use the time field from the event that triggered the
5929 * call to this function, but that isn't trivial to get
5937 SendGameSelection(Widget w, Atom *selection, Atom *target,
5938 Atom *type_return, XtPointer *value_return,
5939 unsigned long *length_return, int *format_return)
5941 char *selection_tmp;
5943 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5944 FILE* f = fopen(gameCopyFilename, "r");
5947 if (f == NULL) return False;
5951 selection_tmp = XtMalloc(len + 1);
5952 count = fread(selection_tmp, 1, len, f);
5955 XtFree(selection_tmp);
5958 selection_tmp[len] = NULLCHAR;
5959 *value_return = selection_tmp;
5960 *length_return = len;
5961 *type_return = *target;
5962 *format_return = 8; /* bits per byte */
5964 } else if (*target == XA_TARGETS(xDisplay)) {
5965 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5966 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5967 targets_tmp[1] = XA_STRING;
5968 *value_return = targets_tmp;
5969 *type_return = XA_ATOM;
5971 *format_return = 8 * sizeof(Atom);
5972 if (*format_return > 32) {
5973 *length_return *= *format_return / 32;
5974 *format_return = 32;
5982 /* note: when called from menu all parameters are NULL, so no clue what the
5983 * Widget which was clicked on was, or what the click event was
5985 void CopyGameProc(w, event, prms, nprms)
5993 ret = SaveGameToFile(gameCopyFilename, FALSE);
5997 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5998 * have a notion of a game that is selected but not copied.
5999 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
6001 XtOwnSelection(menuBarWidget, XA_PRIMARY,
6004 NULL/* lose_ownership_proc */ ,
6005 NULL/* transfer_done_proc */);
6006 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
6009 NULL/* lose_ownership_proc */ ,
6010 NULL/* transfer_done_proc */);
6013 /* function called when the data to Paste is ready */
6015 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
6016 Atom *type, XtPointer value, unsigned long *len, int *format)
6019 if (value == NULL || *len == 0) {
6020 return; /* nothing had been selected to copy */
6022 f = fopen(gamePasteFilename, "w");
6024 DisplayError(_("Can't open temp file"), errno);
6027 fwrite(value, 1, *len, f);
6030 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
6033 /* called when Paste Game button is pressed,
6034 * all parameters will be NULL */
6035 void PasteGameProc(w, event, prms, nprms)
6041 XtGetSelectionValue(menuBarWidget,
6042 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
6043 /* (XtSelectionCallbackProc) */ PasteGameCB,
6044 NULL, /* client_data passed to PasteGameCB */
6046 /* better to use the time field from the event that triggered the
6047 * call to this function, but that isn't trivial to get
6057 SaveGameProc(NULL, NULL, NULL, NULL);
6061 void QuitProc(w, event, prms, nprms)
6070 void PauseProc(w, event, prms, nprms)
6080 void MachineBlackProc(w, event, prms, nprms)
6086 MachineBlackEvent();
6089 void MachineWhiteProc(w, event, prms, nprms)
6095 MachineWhiteEvent();
6098 void AnalyzeModeProc(w, event, prms, nprms)
6106 if (!first.analysisSupport) {
6107 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6108 DisplayError(buf, 0);
6111 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
6112 if (appData.icsActive) {
6113 if (gameMode != IcsObserving) {
6114 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
6115 DisplayError(buf, 0);
6117 if (appData.icsEngineAnalyze) {
6118 if (appData.debugMode)
6119 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
6125 /* if enable, use want disable icsEngineAnalyze */
6126 if (appData.icsEngineAnalyze) {
6131 appData.icsEngineAnalyze = TRUE;
6132 if (appData.debugMode)
6133 fprintf(debugFP, _("ICS engine analyze starting... \n"));
6135 if (!appData.showThinking)
6136 ShowThinkingProc(w,event,prms,nprms);
6141 void AnalyzeFileProc(w, event, prms, nprms)
6147 if (!first.analysisSupport) {
6149 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6150 DisplayError(buf, 0);
6155 if (!appData.showThinking)
6156 ShowThinkingProc(w,event,prms,nprms);
6159 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
6160 AnalysisPeriodicEvent(1);
6163 void TwoMachinesProc(w, event, prms, nprms)
6172 void IcsClientProc(w, event, prms, nprms)
6181 void EditGameProc(w, event, prms, nprms)
6190 void EditPositionProc(w, event, prms, nprms)
6196 EditPositionEvent();
6199 void TrainingProc(w, event, prms, nprms)
6208 void EditCommentProc(w, event, prms, nprms)
6215 EditCommentPopDown();
6221 void IcsInputBoxProc(w, event, prms, nprms)
6227 if (ICSInputBoxUp) {
6228 ICSInputBoxPopDown();
6234 void AcceptProc(w, event, prms, nprms)
6243 void DeclineProc(w, event, prms, nprms)
6252 void RematchProc(w, event, prms, nprms)
6261 void CallFlagProc(w, event, prms, nprms)
6270 void DrawProc(w, event, prms, nprms)
6279 void AbortProc(w, event, prms, nprms)
6288 void AdjournProc(w, event, prms, nprms)
6297 void ResignProc(w, event, prms, nprms)
6306 void AdjuWhiteProc(w, event, prms, nprms)
6312 UserAdjudicationEvent(+1);
6315 void AdjuBlackProc(w, event, prms, nprms)
6321 UserAdjudicationEvent(-1);
6324 void AdjuDrawProc(w, event, prms, nprms)
6330 UserAdjudicationEvent(0);
6333 void EnterKeyProc(w, event, prms, nprms)
6339 if (ICSInputBoxUp == True)
6343 void UpKeyProc(w, event, prms, nprms)
6348 { // [HGM] input: let up-arrow recall previous line from history
6355 if (!ICSInputBoxUp) return;
6356 edit = XtNameToWidget(ICSInputShell, "*form.text");
6358 XtSetArg(args[j], XtNstring, &val); j++;
6359 XtGetValues(edit, args, j);
6360 val = PrevInHistory(val);
6361 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6362 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6364 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6365 XawTextReplace(edit, 0, 0, &t);
6366 XawTextSetInsertionPoint(edit, 9999);
6370 void DownKeyProc(w, event, prms, nprms)
6375 { // [HGM] input: let down-arrow recall next line from history
6380 if (!ICSInputBoxUp) return;
6381 edit = XtNameToWidget(ICSInputShell, "*form.text");
6382 val = NextInHistory();
6383 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6384 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6386 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6387 XawTextReplace(edit, 0, 0, &t);
6388 XawTextSetInsertionPoint(edit, 9999);
6392 void StopObservingProc(w, event, prms, nprms)
6398 StopObservingEvent();
6401 void StopExaminingProc(w, event, prms, nprms)
6407 StopExaminingEvent();
6410 void UploadProc(w, event, prms, nprms)
6420 void ForwardProc(w, event, prms, nprms)
6430 void BackwardProc(w, event, prms, nprms)
6439 void ToStartProc(w, event, prms, nprms)
6448 void ToEndProc(w, event, prms, nprms)
6457 void RevertProc(w, event, prms, nprms)
6466 void AnnotateProc(w, event, prms, nprms)
6475 void TruncateGameProc(w, event, prms, nprms)
6481 TruncateGameEvent();
6483 void RetractMoveProc(w, event, prms, nprms)
6492 void MoveNowProc(w, event, prms, nprms)
6502 void AlwaysQueenProc(w, event, prms, nprms)
6510 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6512 if (appData.alwaysPromoteToQueen) {
6513 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6515 XtSetArg(args[0], XtNleftBitmap, None);
6517 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6521 void AnimateDraggingProc(w, event, prms, nprms)
6529 appData.animateDragging = !appData.animateDragging;
6531 if (appData.animateDragging) {
6532 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6535 XtSetArg(args[0], XtNleftBitmap, None);
6537 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6541 void AnimateMovingProc(w, event, prms, nprms)
6549 appData.animate = !appData.animate;
6551 if (appData.animate) {
6552 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6555 XtSetArg(args[0], XtNleftBitmap, None);
6557 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6561 void AutocommProc(w, event, prms, nprms)
6569 appData.autoComment = !appData.autoComment;
6571 if (appData.autoComment) {
6572 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6574 XtSetArg(args[0], XtNleftBitmap, None);
6576 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6581 void AutoflagProc(w, event, prms, nprms)
6589 appData.autoCallFlag = !appData.autoCallFlag;
6591 if (appData.autoCallFlag) {
6592 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6594 XtSetArg(args[0], XtNleftBitmap, None);
6596 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6600 void AutoflipProc(w, event, prms, nprms)
6608 appData.autoFlipView = !appData.autoFlipView;
6610 if (appData.autoFlipView) {
6611 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6613 XtSetArg(args[0], XtNleftBitmap, None);
6615 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6619 void AutobsProc(w, event, prms, nprms)
6627 appData.autoObserve = !appData.autoObserve;
6629 if (appData.autoObserve) {
6630 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6632 XtSetArg(args[0], XtNleftBitmap, None);
6634 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6638 void AutoraiseProc(w, event, prms, nprms)
6646 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6648 if (appData.autoRaiseBoard) {
6649 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6651 XtSetArg(args[0], XtNleftBitmap, None);
6653 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6657 void AutosaveProc(w, event, prms, nprms)
6665 appData.autoSaveGames = !appData.autoSaveGames;
6667 if (appData.autoSaveGames) {
6668 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6670 XtSetArg(args[0], XtNleftBitmap, None);
6672 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6676 void BlindfoldProc(w, event, prms, nprms)
6684 appData.blindfold = !appData.blindfold;
6686 if (appData.blindfold) {
6687 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6689 XtSetArg(args[0], XtNleftBitmap, None);
6691 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6694 DrawPosition(True, NULL);
6697 void TestLegalityProc(w, event, prms, nprms)
6705 appData.testLegality = !appData.testLegality;
6707 if (appData.testLegality) {
6708 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6710 XtSetArg(args[0], XtNleftBitmap, None);
6712 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6717 void FlashMovesProc(w, event, prms, nprms)
6725 if (appData.flashCount == 0) {
6726 appData.flashCount = 3;
6728 appData.flashCount = -appData.flashCount;
6731 if (appData.flashCount > 0) {
6732 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6734 XtSetArg(args[0], XtNleftBitmap, None);
6736 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6740 void FlipViewProc(w, event, prms, nprms)
6746 flipView = !flipView;
6747 DrawPosition(True, NULL);
6750 void GetMoveListProc(w, event, prms, nprms)
6758 appData.getMoveList = !appData.getMoveList;
6760 if (appData.getMoveList) {
6761 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6764 XtSetArg(args[0], XtNleftBitmap, None);
6766 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6771 void HighlightDraggingProc(w, event, prms, nprms)
6779 appData.highlightDragging = !appData.highlightDragging;
6781 if (appData.highlightDragging) {
6782 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6784 XtSetArg(args[0], XtNleftBitmap, None);
6786 XtSetValues(XtNameToWidget(menuBarWidget,
6787 "menuOptions.Highlight Dragging"), args, 1);
6791 void HighlightLastMoveProc(w, event, prms, nprms)
6799 appData.highlightLastMove = !appData.highlightLastMove;
6801 if (appData.highlightLastMove) {
6802 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6804 XtSetArg(args[0], XtNleftBitmap, None);
6806 XtSetValues(XtNameToWidget(menuBarWidget,
6807 "menuOptions.Highlight Last Move"), args, 1);
6810 void HighlightArrowProc(w, event, prms, nprms)
6818 appData.highlightMoveWithArrow = !appData.highlightMoveWithArrow;
6820 if (appData.highlightMoveWithArrow) {
6821 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6823 XtSetArg(args[0], XtNleftBitmap, None);
6825 XtSetValues(XtNameToWidget(menuBarWidget,
6826 "menuOptions.Arrow"), args, 1);
6829 void IcsAlarmProc(w, event, prms, nprms)
6837 appData.icsAlarm = !appData.icsAlarm;
6839 if (appData.icsAlarm) {
6840 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6842 XtSetArg(args[0], XtNleftBitmap, None);
6844 XtSetValues(XtNameToWidget(menuBarWidget,
6845 "menuOptions.ICS Alarm"), args, 1);
6848 void MoveSoundProc(w, event, prms, nprms)
6856 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6858 if (appData.ringBellAfterMoves) {
6859 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6861 XtSetArg(args[0], XtNleftBitmap, None);
6863 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6867 void OneClickProc(w, event, prms, nprms)
6875 appData.oneClick = !appData.oneClick;
6877 if (appData.oneClick) {
6878 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6880 XtSetArg(args[0], XtNleftBitmap, None);
6882 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.OneClick"),
6886 void PeriodicUpdatesProc(w, event, prms, nprms)
6894 PeriodicUpdatesEvent(!appData.periodicUpdates);
6896 if (appData.periodicUpdates) {
6897 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6899 XtSetArg(args[0], XtNleftBitmap, None);
6901 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6905 void PonderNextMoveProc(w, event, prms, nprms)
6913 PonderNextMoveEvent(!appData.ponderNextMove);
6915 if (appData.ponderNextMove) {
6916 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6918 XtSetArg(args[0], XtNleftBitmap, None);
6920 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6924 void PopupExitMessageProc(w, event, prms, nprms)
6932 appData.popupExitMessage = !appData.popupExitMessage;
6934 if (appData.popupExitMessage) {
6935 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6937 XtSetArg(args[0], XtNleftBitmap, None);
6939 XtSetValues(XtNameToWidget(menuBarWidget,
6940 "menuOptions.Popup Exit Message"), args, 1);
6943 void PopupMoveErrorsProc(w, event, prms, nprms)
6951 appData.popupMoveErrors = !appData.popupMoveErrors;
6953 if (appData.popupMoveErrors) {
6954 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6956 XtSetArg(args[0], XtNleftBitmap, None);
6958 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6962 void PremoveProc(w, event, prms, nprms)
6970 appData.premove = !appData.premove;
6972 if (appData.premove) {
6973 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6975 XtSetArg(args[0], XtNleftBitmap, None);
6977 XtSetValues(XtNameToWidget(menuBarWidget,
6978 "menuOptions.Premove"), args, 1);
6981 void QuietPlayProc(w, event, prms, nprms)
6989 appData.quietPlay = !appData.quietPlay;
6991 if (appData.quietPlay) {
6992 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6994 XtSetArg(args[0], XtNleftBitmap, None);
6996 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
7000 void ShowCoordsProc(w, event, prms, nprms)
7008 appData.showCoords = !appData.showCoords;
7010 if (appData.showCoords) {
7011 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
7013 XtSetArg(args[0], XtNleftBitmap, None);
7015 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
7018 DrawPosition(True, NULL);
7021 void ShowThinkingProc(w, event, prms, nprms)
7027 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
7028 ShowThinkingEvent();
7031 void HideThinkingProc(w, event, prms, nprms)
7039 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
7040 ShowThinkingEvent();
7042 if (appData.hideThinkingFromHuman) {
7043 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
7045 XtSetArg(args[0], XtNleftBitmap, None);
7047 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
7051 void SaveOnExitProc(w, event, prms, nprms)
7059 saveSettingsOnExit = !saveSettingsOnExit;
7061 if (saveSettingsOnExit) {
7062 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
7064 XtSetArg(args[0], XtNleftBitmap, None);
7066 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
7070 void SaveSettingsProc(w, event, prms, nprms)
7076 SaveSettings(settingsFileName);
7079 void InfoProc(w, event, prms, nprms)
7086 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
7091 void ManProc(w, event, prms, nprms)
7099 if (nprms && *nprms > 0)
7103 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
7107 void HintProc(w, event, prms, nprms)
7116 void BookProc(w, event, prms, nprms)
7125 void AboutProc(w, event, prms, nprms)
7133 char *zippy = " (with Zippy code)";
7137 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
7138 programVersion, zippy,
7139 "Copyright 1991 Digital Equipment Corporation",
7140 "Enhancements Copyright 1992-2009 Free Software Foundation",
7141 "Enhancements Copyright 2005 Alessandro Scotti",
7142 PACKAGE, " is free software and carries NO WARRANTY;",
7143 "see the file COPYING for more information.");
7144 ErrorPopUp(_("About XBoard"), buf, FALSE);
7147 void DebugProc(w, event, prms, nprms)
7153 appData.debugMode = !appData.debugMode;
7156 void AboutGameProc(w, event, prms, nprms)
7165 void NothingProc(w, event, prms, nprms)
7174 void Iconify(w, event, prms, nprms)
7183 XtSetArg(args[0], XtNiconic, True);
7184 XtSetValues(shellWidget, args, 1);
7187 void DisplayMessage(message, extMessage)
7188 char *message, *extMessage;
7190 /* display a message in the message widget */
7199 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
7204 message = extMessage;
7208 /* need to test if messageWidget already exists, since this function
7209 can also be called during the startup, if for example a Xresource
7210 is not set up correctly */
7213 XtSetArg(arg, XtNlabel, message);
7214 XtSetValues(messageWidget, &arg, 1);
7220 void DisplayTitle(text)
7225 char title[MSG_SIZ];
7228 if (text == NULL) text = "";
7230 if (appData.titleInWindow) {
7232 XtSetArg(args[i], XtNlabel, text); i++;
7233 XtSetValues(titleWidget, args, i);
7236 if (*text != NULLCHAR) {
7237 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
7238 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
7239 } else if (appData.icsActive) {
7240 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7241 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7242 } else if (appData.cmailGameName[0] != NULLCHAR) {
7243 snprintf(icon, sizeof(icon), "%s", "CMail");
7244 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7246 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7247 } else if (gameInfo.variant == VariantGothic) {
7248 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7249 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
7252 } else if (gameInfo.variant == VariantFalcon) {
7253 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7254 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
7256 } else if (appData.noChessProgram) {
7257 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7258 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
7260 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
7261 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7264 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7265 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7266 XtSetValues(shellWidget, args, i);
7271 DisplayError(message, error)
7278 if (appData.debugMode || appData.matchMode) {
7279 fprintf(stderr, "%s: %s\n", programName, message);
7282 if (appData.debugMode || appData.matchMode) {
7283 fprintf(stderr, "%s: %s: %s\n",
7284 programName, message, strerror(error));
7286 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7289 ErrorPopUp(_("Error"), message, FALSE);
7293 void DisplayMoveError(message)
7298 DrawPosition(FALSE, NULL);
7299 if (appData.debugMode || appData.matchMode) {
7300 fprintf(stderr, "%s: %s\n", programName, message);
7302 if (appData.popupMoveErrors) {
7303 ErrorPopUp(_("Error"), message, FALSE);
7305 DisplayMessage(message, "");
7310 void DisplayFatalError(message, error, status)
7316 errorExitStatus = status;
7318 fprintf(stderr, "%s: %s\n", programName, message);
7320 fprintf(stderr, "%s: %s: %s\n",
7321 programName, message, strerror(error));
7322 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7325 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7326 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7332 void DisplayInformation(message)
7336 ErrorPopUp(_("Information"), message, TRUE);
7339 void DisplayNote(message)
7343 ErrorPopUp(_("Note"), message, FALSE);
7347 NullXErrorCheck(dpy, error_event)
7349 XErrorEvent *error_event;
7354 void DisplayIcsInteractionTitle(message)
7357 if (oldICSInteractionTitle == NULL) {
7358 /* Magic to find the old window title, adapted from vim */
7359 char *wina = getenv("WINDOWID");
7361 Window win = (Window) atoi(wina);
7362 Window root, parent, *children;
7363 unsigned int nchildren;
7364 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7366 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7367 if (!XQueryTree(xDisplay, win, &root, &parent,
7368 &children, &nchildren)) break;
7369 if (children) XFree((void *)children);
7370 if (parent == root || parent == 0) break;
7373 XSetErrorHandler(oldHandler);
7375 if (oldICSInteractionTitle == NULL) {
7376 oldICSInteractionTitle = "xterm";
7379 printf("\033]0;%s\007", message);
7383 char pendingReplyPrefix[MSG_SIZ];
7384 ProcRef pendingReplyPR;
7386 void AskQuestionProc(w, event, prms, nprms)
7393 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7397 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7400 void AskQuestionPopDown()
7402 if (!askQuestionUp) return;
7403 XtPopdown(askQuestionShell);
7404 XtDestroyWidget(askQuestionShell);
7405 askQuestionUp = False;
7408 void AskQuestionReplyAction(w, event, prms, nprms)
7418 reply = XawDialogGetValueString(w = XtParent(w));
7419 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
7420 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
7421 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
7422 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
7423 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7424 AskQuestionPopDown();
7426 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7429 void AskQuestionCallback(w, client_data, call_data)
7431 XtPointer client_data, call_data;
7436 XtSetArg(args[0], XtNlabel, &name);
7437 XtGetValues(w, args, 1);
7439 if (strcmp(name, _("cancel")) == 0) {
7440 AskQuestionPopDown();
7442 AskQuestionReplyAction(w, NULL, NULL, NULL);
7446 void AskQuestion(title, question, replyPrefix, pr)
7447 char *title, *question, *replyPrefix;
7451 Widget popup, layout, dialog, edit;
7457 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
7458 pendingReplyPR = pr;
7461 XtSetArg(args[i], XtNresizable, True); i++;
7462 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7463 askQuestionShell = popup =
7464 XtCreatePopupShell(title, transientShellWidgetClass,
7465 shellWidget, args, i);
7468 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7469 layoutArgs, XtNumber(layoutArgs));
7472 XtSetArg(args[i], XtNlabel, question); i++;
7473 XtSetArg(args[i], XtNvalue, ""); i++;
7474 XtSetArg(args[i], XtNborderWidth, 0); i++;
7475 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7478 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7479 (XtPointer) dialog);
7480 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7481 (XtPointer) dialog);
7483 XtRealizeWidget(popup);
7484 CatchDeleteWindow(popup, "AskQuestionPopDown");
7486 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7487 &x, &y, &win_x, &win_y, &mask);
7489 XtSetArg(args[0], XtNx, x - 10);
7490 XtSetArg(args[1], XtNy, y - 30);
7491 XtSetValues(popup, args, 2);
7493 XtPopup(popup, XtGrabExclusive);
7494 askQuestionUp = True;
7496 edit = XtNameToWidget(dialog, "*value");
7497 XtSetKeyboardFocus(popup, edit);
7505 if (*name == NULLCHAR) {
7507 } else if (strcmp(name, "$") == 0) {
7508 putc(BELLCHAR, stderr);
7511 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7519 PlaySound(appData.soundMove);
7525 PlaySound(appData.soundIcsWin);
7531 PlaySound(appData.soundIcsLoss);
7537 PlaySound(appData.soundIcsDraw);
7541 PlayIcsUnfinishedSound()
7543 PlaySound(appData.soundIcsUnfinished);
7549 PlaySound(appData.soundIcsAlarm);
7555 system("stty echo");
7561 system("stty -echo");
7565 Colorize(cc, continuation)
7570 int count, outCount, error;
7572 if (textColors[(int)cc].bg > 0) {
7573 if (textColors[(int)cc].fg > 0) {
7574 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7575 textColors[(int)cc].fg, textColors[(int)cc].bg);
7577 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7578 textColors[(int)cc].bg);
7581 if (textColors[(int)cc].fg > 0) {
7582 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7583 textColors[(int)cc].fg);
7585 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7588 count = strlen(buf);
7589 outCount = OutputToProcess(NoProc, buf, count, &error);
7590 if (outCount < count) {
7591 DisplayFatalError(_("Error writing to display"), error, 1);
7594 if (continuation) return;
7597 PlaySound(appData.soundShout);
7600 PlaySound(appData.soundSShout);
7603 PlaySound(appData.soundChannel1);
7606 PlaySound(appData.soundChannel);
7609 PlaySound(appData.soundKibitz);
7612 PlaySound(appData.soundTell);
7614 case ColorChallenge:
7615 PlaySound(appData.soundChallenge);
7618 PlaySound(appData.soundRequest);
7621 PlaySound(appData.soundSeek);
7632 return getpwuid(getuid())->pw_name;
7636 ExpandPathName(path)
7639 static char static_buf[4*MSG_SIZ];
7640 char *d, *s, buf[4*MSG_SIZ];
7646 while (*s && isspace(*s))
7655 if (*(s+1) == '/') {
7656 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7660 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7661 { char *p; if(p = strchr(buf, '/')) *p = 0; }
7662 pwd = getpwnam(buf);
7665 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7669 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7670 strcat(d, strchr(s+1, '/'));
7674 safeStrCpy(d, s, 4*MSG_SIZ );
7681 static char host_name[MSG_SIZ];
7683 #if HAVE_GETHOSTNAME
7684 gethostname(host_name, MSG_SIZ);
7686 #else /* not HAVE_GETHOSTNAME */
7687 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7688 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7690 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7692 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7693 #endif /* not HAVE_GETHOSTNAME */
7696 XtIntervalId delayedEventTimerXID = 0;
7697 DelayedEventCallback delayedEventCallback = 0;
7702 delayedEventTimerXID = 0;
7703 delayedEventCallback();
7707 ScheduleDelayedEvent(cb, millisec)
7708 DelayedEventCallback cb; long millisec;
7710 if(delayedEventTimerXID && delayedEventCallback == cb)
7711 // [HGM] alive: replace, rather than add or flush identical event
7712 XtRemoveTimeOut(delayedEventTimerXID);
7713 delayedEventCallback = cb;
7714 delayedEventTimerXID =
7715 XtAppAddTimeOut(appContext, millisec,
7716 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7719 DelayedEventCallback
7722 if (delayedEventTimerXID) {
7723 return delayedEventCallback;
7730 CancelDelayedEvent()
7732 if (delayedEventTimerXID) {
7733 XtRemoveTimeOut(delayedEventTimerXID);
7734 delayedEventTimerXID = 0;
7738 XtIntervalId loadGameTimerXID = 0;
7740 int LoadGameTimerRunning()
7742 return loadGameTimerXID != 0;
7745 int StopLoadGameTimer()
7747 if (loadGameTimerXID != 0) {
7748 XtRemoveTimeOut(loadGameTimerXID);
7749 loadGameTimerXID = 0;
7757 LoadGameTimerCallback(arg, id)
7761 loadGameTimerXID = 0;
7766 StartLoadGameTimer(millisec)
7770 XtAppAddTimeOut(appContext, millisec,
7771 (XtTimerCallbackProc) LoadGameTimerCallback,
7775 XtIntervalId analysisClockXID = 0;
7778 AnalysisClockCallback(arg, id)
7782 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7783 || appData.icsEngineAnalyze) { // [DM]
7784 AnalysisPeriodicEvent(0);
7785 StartAnalysisClock();
7790 StartAnalysisClock()
7793 XtAppAddTimeOut(appContext, 2000,
7794 (XtTimerCallbackProc) AnalysisClockCallback,
7798 XtIntervalId clockTimerXID = 0;
7800 int ClockTimerRunning()
7802 return clockTimerXID != 0;
7805 int StopClockTimer()
7807 if (clockTimerXID != 0) {
7808 XtRemoveTimeOut(clockTimerXID);
7817 ClockTimerCallback(arg, id)
7826 StartClockTimer(millisec)
7830 XtAppAddTimeOut(appContext, millisec,
7831 (XtTimerCallbackProc) ClockTimerCallback,
7836 DisplayTimerLabel(w, color, timer, highlight)
7845 /* check for low time warning */
7846 Pixel foregroundOrWarningColor = timerForegroundPixel;
7849 appData.lowTimeWarning &&
7850 (timer / 1000) < appData.icsAlarmTime)
7851 foregroundOrWarningColor = lowTimeWarningColor;
7853 if (appData.clockMode) {
7854 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7855 XtSetArg(args[0], XtNlabel, buf);
7857 snprintf(buf, MSG_SIZ, "%s ", color);
7858 XtSetArg(args[0], XtNlabel, buf);
7863 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7864 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7866 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7867 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7870 XtSetValues(w, args, 3);
7874 DisplayWhiteClock(timeRemaining, highlight)
7880 if(appData.noGUI) return;
7881 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7882 if (highlight && iconPixmap == bIconPixmap) {
7883 iconPixmap = wIconPixmap;
7884 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7885 XtSetValues(shellWidget, args, 1);
7890 DisplayBlackClock(timeRemaining, highlight)
7896 if(appData.noGUI) return;
7897 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7898 if (highlight && iconPixmap == wIconPixmap) {
7899 iconPixmap = bIconPixmap;
7900 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7901 XtSetValues(shellWidget, args, 1);
7919 int StartChildProcess(cmdLine, dir, pr)
7926 int to_prog[2], from_prog[2];
7930 if (appData.debugMode) {
7931 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7934 /* We do NOT feed the cmdLine to the shell; we just
7935 parse it into blank-separated arguments in the
7936 most simple-minded way possible.
7939 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7942 while(*p == ' ') p++;
7944 if(*p == '"' || *p == '\'')
7945 p = strchr(++argv[i-1], *p);
7946 else p = strchr(p, ' ');
7947 if (p == NULL) break;
7952 SetUpChildIO(to_prog, from_prog);
7954 if ((pid = fork()) == 0) {
7956 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7957 close(to_prog[1]); // first close the unused pipe ends
7958 close(from_prog[0]);
7959 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7960 dup2(from_prog[1], 1);
7961 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7962 close(from_prog[1]); // and closing again loses one of the pipes!
7963 if(fileno(stderr) >= 2) // better safe than sorry...
7964 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7966 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7971 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7973 execvp(argv[0], argv);
7975 /* If we get here, exec failed */
7980 /* Parent process */
7982 close(from_prog[1]);
7984 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7987 cp->fdFrom = from_prog[0];
7988 cp->fdTo = to_prog[1];
7993 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7994 static RETSIGTYPE AlarmCallBack(int n)
8000 DestroyChildProcess(pr, signalType)
8004 ChildProc *cp = (ChildProc *) pr;
8006 if (cp->kind != CPReal) return;
8008 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
8009 signal(SIGALRM, AlarmCallBack);
8011 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
8012 kill(cp->pid, SIGKILL); // kill it forcefully
8013 wait((int *) 0); // and wait again
8017 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
8019 /* Process is exiting either because of the kill or because of
8020 a quit command sent by the backend; either way, wait for it to die.
8029 InterruptChildProcess(pr)
8032 ChildProc *cp = (ChildProc *) pr;
8034 if (cp->kind != CPReal) return;
8035 (void) kill(cp->pid, SIGINT); /* stop it thinking */
8038 int OpenTelnet(host, port, pr)
8043 char cmdLine[MSG_SIZ];
8045 if (port[0] == NULLCHAR) {
8046 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
8048 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
8050 return StartChildProcess(cmdLine, "", pr);
8053 int OpenTCP(host, port, pr)
8059 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
8060 #else /* !OMIT_SOCKETS */
8062 struct sockaddr_in sa;
8064 unsigned short uport;
8067 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
8071 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
8072 sa.sin_family = AF_INET;
8073 sa.sin_addr.s_addr = INADDR_ANY;
8074 uport = (unsigned short) 0;
8075 sa.sin_port = htons(uport);
8076 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
8080 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
8081 if (!(hp = gethostbyname(host))) {
8083 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
8084 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
8085 hp->h_addrtype = AF_INET;
8087 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
8088 hp->h_addr_list[0] = (char *) malloc(4);
8089 hp->h_addr_list[0][0] = b0;
8090 hp->h_addr_list[0][1] = b1;
8091 hp->h_addr_list[0][2] = b2;
8092 hp->h_addr_list[0][3] = b3;
8097 sa.sin_family = hp->h_addrtype;
8098 uport = (unsigned short) atoi(port);
8099 sa.sin_port = htons(uport);
8100 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
8102 if (connect(s, (struct sockaddr *) &sa,
8103 sizeof(struct sockaddr_in)) < 0) {
8107 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8114 #endif /* !OMIT_SOCKETS */
8119 int OpenCommPort(name, pr)
8126 fd = open(name, 2, 0);
8127 if (fd < 0) return errno;
8129 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8139 int OpenLoopback(pr)
8145 SetUpChildIO(to, from);
8147 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8150 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
8157 int OpenRcmd(host, user, cmd, pr)
8158 char *host, *user, *cmd;
8161 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
8165 #define INPUT_SOURCE_BUF_SIZE 8192
8174 char buf[INPUT_SOURCE_BUF_SIZE];
8179 DoInputCallback(closure, source, xid)
8184 InputSource *is = (InputSource *) closure;
8189 if (is->lineByLine) {
8190 count = read(is->fd, is->unused,
8191 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
8193 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
8196 is->unused += count;
8198 while (p < is->unused) {
8199 q = memchr(p, '\n', is->unused - p);
8200 if (q == NULL) break;
8202 (is->func)(is, is->closure, p, q - p, 0);
8206 while (p < is->unused) {
8211 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8216 (is->func)(is, is->closure, is->buf, count, error);
8220 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8227 ChildProc *cp = (ChildProc *) pr;
8229 is = (InputSource *) calloc(1, sizeof(InputSource));
8230 is->lineByLine = lineByLine;
8234 is->fd = fileno(stdin);
8236 is->kind = cp->kind;
8237 is->fd = cp->fdFrom;
8240 is->unused = is->buf;
8243 is->xid = XtAppAddInput(appContext, is->fd,
8244 (XtPointer) (XtInputReadMask),
8245 (XtInputCallbackProc) DoInputCallback,
8247 is->closure = closure;
8248 return (InputSourceRef) is;
8252 RemoveInputSource(isr)
8255 InputSource *is = (InputSource *) isr;
8257 if (is->xid == 0) return;
8258 XtRemoveInput(is->xid);
8262 int OutputToProcess(pr, message, count, outError)
8268 static int line = 0;
8269 ChildProc *cp = (ChildProc *) pr;
8274 if (appData.noJoin || !appData.useInternalWrap)
8275 outCount = fwrite(message, 1, count, stdout);
8278 int width = get_term_width();
8279 int len = wrap(NULL, message, count, width, &line);
8280 char *msg = malloc(len);
8284 outCount = fwrite(message, 1, count, stdout);
8287 dbgchk = wrap(msg, message, count, width, &line);
8288 if (dbgchk != len && appData.debugMode)
8289 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8290 outCount = fwrite(msg, 1, dbgchk, stdout);
8296 outCount = write(cp->fdTo, message, count);
8306 /* Output message to process, with "ms" milliseconds of delay
8307 between each character. This is needed when sending the logon
8308 script to ICC, which for some reason doesn't like the
8309 instantaneous send. */
8310 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8317 ChildProc *cp = (ChildProc *) pr;
8322 r = write(cp->fdTo, message++, 1);
8335 /**** Animation code by Hugh Fisher, DCS, ANU.
8337 Known problem: if a window overlapping the board is
8338 moved away while a piece is being animated underneath,
8339 the newly exposed area won't be updated properly.
8340 I can live with this.
8342 Known problem: if you look carefully at the animation
8343 of pieces in mono mode, they are being drawn as solid
8344 shapes without interior detail while moving. Fixing
8345 this would be a major complication for minimal return.
8348 /* Masks for XPM pieces. Black and white pieces can have
8349 different shapes, but in the interest of retaining my
8350 sanity pieces must have the same outline on both light
8351 and dark squares, and all pieces must use the same
8352 background square colors/images. */
8354 static int xpmDone = 0;
8357 CreateAnimMasks (pieceDepth)
8364 unsigned long plane;
8367 /* Need a bitmap just to get a GC with right depth */
8368 buf = XCreatePixmap(xDisplay, xBoardWindow,
8370 values.foreground = 1;
8371 values.background = 0;
8372 /* Don't use XtGetGC, not read only */
8373 maskGC = XCreateGC(xDisplay, buf,
8374 GCForeground | GCBackground, &values);
8375 XFreePixmap(xDisplay, buf);
8377 buf = XCreatePixmap(xDisplay, xBoardWindow,
8378 squareSize, squareSize, pieceDepth);
8379 values.foreground = XBlackPixel(xDisplay, xScreen);
8380 values.background = XWhitePixel(xDisplay, xScreen);
8381 bufGC = XCreateGC(xDisplay, buf,
8382 GCForeground | GCBackground, &values);
8384 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8385 /* Begin with empty mask */
8386 if(!xpmDone) // [HGM] pieces: keep using existing
8387 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8388 squareSize, squareSize, 1);
8389 XSetFunction(xDisplay, maskGC, GXclear);
8390 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8391 0, 0, squareSize, squareSize);
8393 /* Take a copy of the piece */
8398 XSetFunction(xDisplay, bufGC, GXcopy);
8399 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8401 0, 0, squareSize, squareSize, 0, 0);
8403 /* XOR the background (light) over the piece */
8404 XSetFunction(xDisplay, bufGC, GXxor);
8406 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8407 0, 0, squareSize, squareSize, 0, 0);
8409 XSetForeground(xDisplay, bufGC, lightSquareColor);
8410 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8413 /* We now have an inverted piece image with the background
8414 erased. Construct mask by just selecting all the non-zero
8415 pixels - no need to reconstruct the original image. */
8416 XSetFunction(xDisplay, maskGC, GXor);
8418 /* Might be quicker to download an XImage and create bitmap
8419 data from it rather than this N copies per piece, but it
8420 only takes a fraction of a second and there is a much
8421 longer delay for loading the pieces. */
8422 for (n = 0; n < pieceDepth; n ++) {
8423 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8424 0, 0, squareSize, squareSize,
8430 XFreePixmap(xDisplay, buf);
8431 XFreeGC(xDisplay, bufGC);
8432 XFreeGC(xDisplay, maskGC);
8436 InitAnimState (anim, info)
8438 XWindowAttributes * info;
8443 /* Each buffer is square size, same depth as window */
8444 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8445 squareSize, squareSize, info->depth);
8446 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8447 squareSize, squareSize, info->depth);
8449 /* Create a plain GC for blitting */
8450 mask = GCForeground | GCBackground | GCFunction |
8451 GCPlaneMask | GCGraphicsExposures;
8452 values.foreground = XBlackPixel(xDisplay, xScreen);
8453 values.background = XWhitePixel(xDisplay, xScreen);
8454 values.function = GXcopy;
8455 values.plane_mask = AllPlanes;
8456 values.graphics_exposures = False;
8457 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8459 /* Piece will be copied from an existing context at
8460 the start of each new animation/drag. */
8461 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8463 /* Outline will be a read-only copy of an existing */
8464 anim->outlineGC = None;
8470 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8471 XWindowAttributes info;
8473 if (xpmDone && gameInfo.variant == old) return;
8474 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8475 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8477 InitAnimState(&game, &info);
8478 InitAnimState(&player, &info);
8480 /* For XPM pieces, we need bitmaps to use as masks. */
8482 CreateAnimMasks(info.depth);
8488 static Boolean frameWaiting;
8490 static RETSIGTYPE FrameAlarm (sig)
8493 frameWaiting = False;
8494 /* In case System-V style signals. Needed?? */
8495 signal(SIGALRM, FrameAlarm);
8502 struct itimerval delay;
8504 XSync(xDisplay, False);
8507 frameWaiting = True;
8508 signal(SIGALRM, FrameAlarm);
8509 delay.it_interval.tv_sec =
8510 delay.it_value.tv_sec = time / 1000;
8511 delay.it_interval.tv_usec =
8512 delay.it_value.tv_usec = (time % 1000) * 1000;
8513 setitimer(ITIMER_REAL, &delay, NULL);
8514 while (frameWaiting) pause();
8515 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8516 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8517 setitimer(ITIMER_REAL, &delay, NULL);
8527 XSync(xDisplay, False);
8529 usleep(time * 1000);
8534 /* Convert board position to corner of screen rect and color */
8537 ScreenSquare(column, row, pt, color)
8538 int column; int row; XPoint * pt; int * color;
8541 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8542 pt->y = lineGap + row * (squareSize + lineGap);
8544 pt->x = lineGap + column * (squareSize + lineGap);
8545 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8547 *color = SquareColor(row, column);
8550 /* Convert window coords to square */
8553 BoardSquare(x, y, column, row)
8554 int x; int y; int * column; int * row;
8556 *column = EventToSquare(x, BOARD_WIDTH);
8557 if (flipView && *column >= 0)
8558 *column = BOARD_WIDTH - 1 - *column;
8559 *row = EventToSquare(y, BOARD_HEIGHT);
8560 if (!flipView && *row >= 0)
8561 *row = BOARD_HEIGHT - 1 - *row;
8566 #undef Max /* just in case */
8568 #define Max(a, b) ((a) > (b) ? (a) : (b))
8569 #define Min(a, b) ((a) < (b) ? (a) : (b))
8572 SetRect(rect, x, y, width, height)
8573 XRectangle * rect; int x; int y; int width; int height;
8577 rect->width = width;
8578 rect->height = height;
8581 /* Test if two frames overlap. If they do, return
8582 intersection rect within old and location of
8583 that rect within new. */
8586 Intersect(old, new, size, area, pt)
8587 XPoint * old; XPoint * new;
8588 int size; XRectangle * area; XPoint * pt;
8590 if (old->x > new->x + size || new->x > old->x + size ||
8591 old->y > new->y + size || new->y > old->y + size) {
8594 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8595 size - abs(old->x - new->x), size - abs(old->y - new->y));
8596 pt->x = Max(old->x - new->x, 0);
8597 pt->y = Max(old->y - new->y, 0);
8602 /* For two overlapping frames, return the rect(s)
8603 in the old that do not intersect with the new. */
8606 CalcUpdateRects(old, new, size, update, nUpdates)
8607 XPoint * old; XPoint * new; int size;
8608 XRectangle update[]; int * nUpdates;
8612 /* If old = new (shouldn't happen) then nothing to draw */
8613 if (old->x == new->x && old->y == new->y) {
8617 /* Work out what bits overlap. Since we know the rects
8618 are the same size we don't need a full intersect calc. */
8620 /* Top or bottom edge? */
8621 if (new->y > old->y) {
8622 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8624 } else if (old->y > new->y) {
8625 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8626 size, old->y - new->y);
8629 /* Left or right edge - don't overlap any update calculated above. */
8630 if (new->x > old->x) {
8631 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8632 new->x - old->x, size - abs(new->y - old->y));
8634 } else if (old->x > new->x) {
8635 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8636 old->x - new->x, size - abs(new->y - old->y));
8643 /* Generate a series of frame coords from start->mid->finish.
8644 The movement rate doubles until the half way point is
8645 reached, then halves back down to the final destination,
8646 which gives a nice slow in/out effect. The algorithmn
8647 may seem to generate too many intermediates for short
8648 moves, but remember that the purpose is to attract the
8649 viewers attention to the piece about to be moved and
8650 then to where it ends up. Too few frames would be less
8654 Tween(start, mid, finish, factor, frames, nFrames)
8655 XPoint * start; XPoint * mid;
8656 XPoint * finish; int factor;
8657 XPoint frames[]; int * nFrames;
8659 int fraction, n, count;
8663 /* Slow in, stepping 1/16th, then 1/8th, ... */
8665 for (n = 0; n < factor; n++)
8667 for (n = 0; n < factor; n++) {
8668 frames[count].x = start->x + (mid->x - start->x) / fraction;
8669 frames[count].y = start->y + (mid->y - start->y) / fraction;
8671 fraction = fraction / 2;
8675 frames[count] = *mid;
8678 /* Slow out, stepping 1/2, then 1/4, ... */
8680 for (n = 0; n < factor; n++) {
8681 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8682 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8684 fraction = fraction * 2;
8689 /* Draw a piece on the screen without disturbing what's there */
8692 SelectGCMask(piece, clip, outline, mask)
8693 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8697 /* Bitmap for piece being moved. */
8698 if (appData.monoMode) {
8699 *mask = *pieceToSolid(piece);
8700 } else if (useImages) {
8702 *mask = xpmMask[piece];
8704 *mask = ximMaskPm[piece];
8707 *mask = *pieceToSolid(piece);
8710 /* GC for piece being moved. Square color doesn't matter, but
8711 since it gets modified we make a copy of the original. */
8713 if (appData.monoMode)
8718 if (appData.monoMode)
8723 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8725 /* Outline only used in mono mode and is not modified */
8727 *outline = bwPieceGC;
8729 *outline = wbPieceGC;
8733 OverlayPiece(piece, clip, outline, dest)
8734 ChessSquare piece; GC clip; GC outline; Drawable dest;
8739 /* Draw solid rectangle which will be clipped to shape of piece */
8740 XFillRectangle(xDisplay, dest, clip,
8741 0, 0, squareSize, squareSize);
8742 if (appData.monoMode)
8743 /* Also draw outline in contrasting color for black
8744 on black / white on white cases */
8745 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8746 0, 0, squareSize, squareSize, 0, 0, 1);
8748 /* Copy the piece */
8753 if(appData.upsideDown && flipView) kind ^= 2;
8754 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8756 0, 0, squareSize, squareSize,
8761 /* Animate the movement of a single piece */
8764 BeginAnimation(anim, piece, startColor, start)
8772 /* The old buffer is initialised with the start square (empty) */
8773 BlankSquare(start->x, start->y, startColor, EmptySquare, anim->saveBuf, 0);
8774 anim->prevFrame = *start;
8776 /* The piece will be drawn using its own bitmap as a matte */
8777 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8778 XSetClipMask(xDisplay, anim->pieceGC, mask);
8782 AnimationFrame(anim, frame, piece)
8787 XRectangle updates[4];
8792 /* Save what we are about to draw into the new buffer */
8793 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8794 frame->x, frame->y, squareSize, squareSize,
8797 /* Erase bits of the previous frame */
8798 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8799 /* Where the new frame overlapped the previous,
8800 the contents in newBuf are wrong. */
8801 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8802 overlap.x, overlap.y,
8803 overlap.width, overlap.height,
8805 /* Repaint the areas in the old that don't overlap new */
8806 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8807 for (i = 0; i < count; i++)
8808 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8809 updates[i].x - anim->prevFrame.x,
8810 updates[i].y - anim->prevFrame.y,
8811 updates[i].width, updates[i].height,
8812 updates[i].x, updates[i].y);
8814 /* Easy when no overlap */
8815 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8816 0, 0, squareSize, squareSize,
8817 anim->prevFrame.x, anim->prevFrame.y);
8820 /* Save this frame for next time round */
8821 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8822 0, 0, squareSize, squareSize,
8824 anim->prevFrame = *frame;
8826 /* Draw piece over original screen contents, not current,
8827 and copy entire rect. Wipes out overlapping piece images. */
8828 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8829 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8830 0, 0, squareSize, squareSize,
8831 frame->x, frame->y);
8835 EndAnimation (anim, finish)
8839 XRectangle updates[4];
8844 /* The main code will redraw the final square, so we
8845 only need to erase the bits that don't overlap. */
8846 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8847 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8848 for (i = 0; i < count; i++)
8849 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8850 updates[i].x - anim->prevFrame.x,
8851 updates[i].y - anim->prevFrame.y,
8852 updates[i].width, updates[i].height,
8853 updates[i].x, updates[i].y);
8855 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8856 0, 0, squareSize, squareSize,
8857 anim->prevFrame.x, anim->prevFrame.y);
8862 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8864 ChessSquare piece; int startColor;
8865 XPoint * start; XPoint * finish;
8866 XPoint frames[]; int nFrames;
8870 BeginAnimation(anim, piece, startColor, start);
8871 for (n = 0; n < nFrames; n++) {
8872 AnimationFrame(anim, &(frames[n]), piece);
8873 FrameDelay(appData.animSpeed);
8875 EndAnimation(anim, finish);
8879 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
8882 ChessSquare piece = board[fromY][toY];
8883 board[fromY][toY] = EmptySquare;
8884 DrawPosition(FALSE, board);
8886 x = lineGap + ((BOARD_WIDTH-1)-toX) * (squareSize + lineGap);
8887 y = lineGap + toY * (squareSize + lineGap);
8889 x = lineGap + toX * (squareSize + lineGap);
8890 y = lineGap + ((BOARD_HEIGHT-1)-toY) * (squareSize + lineGap);
8892 for(i=1; i<4*kFactor; i++) {
8893 int r = squareSize * 9 * i/(20*kFactor - 5);
8894 XFillArc(xDisplay, xBoardWindow, highlineGC,
8895 x + squareSize/2 - r, y+squareSize/2 - r, 2*r, 2*r, 0, 64*360);
8896 FrameDelay(appData.animSpeed);
8898 board[fromY][toY] = piece;
8901 /* Main control logic for deciding what to animate and how */
8904 AnimateMove(board, fromX, fromY, toX, toY)
8913 XPoint start, finish, mid;
8914 XPoint frames[kFactor * 2 + 1];
8915 int nFrames, startColor, endColor;
8917 /* Are we animating? */
8918 if (!appData.animate || appData.blindfold)
8921 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8922 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8923 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8925 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8926 piece = board[fromY][fromX];
8927 if (piece >= EmptySquare) return;
8932 hop = abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1;
8935 if (appData.debugMode) {
8936 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8937 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8938 piece, fromX, fromY, toX, toY); }
8940 ScreenSquare(fromX, fromY, &start, &startColor);
8941 ScreenSquare(toX, toY, &finish, &endColor);
8944 /* Knight: make straight movement then diagonal */
8945 if (abs(toY - fromY) < abs(toX - fromX)) {
8946 mid.x = start.x + (finish.x - start.x) / 2;
8950 mid.y = start.y + (finish.y - start.y) / 2;
8953 mid.x = start.x + (finish.x - start.x) / 2;
8954 mid.y = start.y + (finish.y - start.y) / 2;
8957 /* Don't use as many frames for very short moves */
8958 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8959 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8961 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8962 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8963 if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged
8965 for(i=0; i<BOARD_WIDTH; i++) for(j=0; j<BOARD_HEIGHT; j++)
8966 if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] = True;
8969 /* Be sure end square is redrawn */
8970 damage[0][toY][toX] = True;
8974 DragPieceBegin(x, y)
8977 int boardX, boardY, color;
8980 /* Are we animating? */
8981 if (!appData.animateDragging || appData.blindfold)
8984 /* Figure out which square we start in and the
8985 mouse position relative to top left corner. */
8986 BoardSquare(x, y, &boardX, &boardY);
8987 player.startBoardX = boardX;
8988 player.startBoardY = boardY;
8989 ScreenSquare(boardX, boardY, &corner, &color);
8990 player.startSquare = corner;
8991 player.startColor = color;
8992 /* As soon as we start dragging, the piece will jump slightly to
8993 be centered over the mouse pointer. */
8994 player.mouseDelta.x = squareSize/2;
8995 player.mouseDelta.y = squareSize/2;
8996 /* Initialise animation */
8997 player.dragPiece = PieceForSquare(boardX, boardY);
8999 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
9000 player.dragActive = True;
9001 BeginAnimation(&player, player.dragPiece, color, &corner);
9002 /* Mark this square as needing to be redrawn. Note that
9003 we don't remove the piece though, since logically (ie
9004 as seen by opponent) the move hasn't been made yet. */
9005 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
9006 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
9007 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
9008 corner.x, corner.y, squareSize, squareSize,
9009 0, 0); // [HGM] zh: unstack in stead of grab
9010 if(gatingPiece != EmptySquare) {
9011 /* Kludge alert: When gating we want the introduced
9012 piece to appear on the from square. To generate an
9013 image of it, we draw it on the board, copy the image,
9014 and draw the original piece again. */
9015 ChessSquare piece = boards[currentMove][boardY][boardX];
9016 DrawSquare(boardY, boardX, gatingPiece, 0);
9017 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
9018 corner.x, corner.y, squareSize, squareSize, 0, 0);
9019 DrawSquare(boardY, boardX, piece, 0);
9021 damage[0][boardY][boardX] = True;
9023 player.dragActive = False;
9033 /* Are we animating? */
9034 if (!appData.animateDragging || appData.blindfold)
9038 if (! player.dragActive)
9040 /* Move piece, maintaining same relative position
9041 of mouse within square */
9042 corner.x = x - player.mouseDelta.x;
9043 corner.y = y - player.mouseDelta.y;
9044 AnimationFrame(&player, &corner, player.dragPiece);
9046 if (appData.highlightDragging) {
9048 BoardSquare(x, y, &boardX, &boardY);
9049 SetHighlights(fromX, fromY, boardX, boardY);
9058 int boardX, boardY, color;
9061 /* Are we animating? */
9062 if (!appData.animateDragging || appData.blindfold)
9066 if (! player.dragActive)
9068 /* Last frame in sequence is square piece is
9069 placed on, which may not match mouse exactly. */
9070 BoardSquare(x, y, &boardX, &boardY);
9071 ScreenSquare(boardX, boardY, &corner, &color);
9072 EndAnimation(&player, &corner);
9074 /* Be sure end square is redrawn */
9075 damage[0][boardY][boardX] = True;
9077 /* This prevents weird things happening with fast successive
9078 clicks which on my Sun at least can cause motion events
9079 without corresponding press/release. */
9080 player.dragActive = False;
9083 /* Handle expose event while piece being dragged */
9088 if (!player.dragActive || appData.blindfold)
9091 /* What we're doing: logically, the move hasn't been made yet,
9092 so the piece is still in it's original square. But visually
9093 it's being dragged around the board. So we erase the square
9094 that the piece is on and draw it at the last known drag point. */
9095 BlankSquare(player.startSquare.x, player.startSquare.y,
9096 player.startColor, EmptySquare, xBoardWindow, 1);
9097 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
9098 damage[0][player.startBoardY][player.startBoardX] = TRUE;
9101 #include <sys/ioctl.h>
9102 int get_term_width()
9104 int fd, default_width;
9107 default_width = 79; // this is FICS default anyway...
9109 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
9111 if (!ioctl(fd, TIOCGSIZE, &win))
9112 default_width = win.ts_cols;
9113 #elif defined(TIOCGWINSZ)
9115 if (!ioctl(fd, TIOCGWINSZ, &win))
9116 default_width = win.ws_col;
9118 return default_width;
9124 static int old_width = 0;
9125 int new_width = get_term_width();
9127 if (old_width != new_width)
9128 ics_printf("set width %d\n", new_width);
9129 old_width = new_width;
9132 void NotifyFrontendLogin()
9137 /* [AS] Arrow highlighting support */
9139 static double A_WIDTH = 5; /* Width of arrow body */
9141 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
9142 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
9144 static double Sqr( double x )
9149 static int Round( double x )
9151 return (int) (x + 0.5);
9154 void SquareToPos(int rank, int file, int *x, int *y)
9157 *x = lineGap + ((BOARD_WIDTH-1)-file) * (squareSize + lineGap);
9158 *y = lineGap + rank * (squareSize + lineGap);
9160 *x = lineGap + file * (squareSize + lineGap);
9161 *y = lineGap + ((BOARD_HEIGHT-1)-rank) * (squareSize + lineGap);
9165 /* Draw an arrow between two points using current settings */
9166 void DrawArrowBetweenPoints( int s_x, int s_y, int d_x, int d_y )
9169 double dx, dy, j, k, x, y;
9172 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
9174 arrow[0].x = s_x + A_WIDTH + 0.5;
9177 arrow[1].x = s_x + A_WIDTH + 0.5;
9178 arrow[1].y = d_y - h;
9180 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9181 arrow[2].y = d_y - h;
9186 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
9187 arrow[5].y = d_y - h;
9189 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9190 arrow[4].y = d_y - h;
9192 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
9195 else if( d_y == s_y ) {
9196 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
9199 arrow[0].y = s_y + A_WIDTH + 0.5;
9201 arrow[1].x = d_x - w;
9202 arrow[1].y = s_y + A_WIDTH + 0.5;
9204 arrow[2].x = d_x - w;
9205 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9210 arrow[5].x = d_x - w;
9211 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
9213 arrow[4].x = d_x - w;
9214 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
9217 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
9220 /* [AS] Needed a lot of paper for this! :-) */
9221 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
9222 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
9224 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
9226 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
9231 arrow[0].x = Round(x - j);
9232 arrow[0].y = Round(y + j*dx);
9234 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
9235 arrow[1].y = Round(arrow[0].y - 2*j*dx);
9238 x = (double) d_x - k;
9239 y = (double) d_y - k*dy;
9242 x = (double) d_x + k;
9243 y = (double) d_y + k*dy;
9246 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
9248 arrow[6].x = Round(x - j);
9249 arrow[6].y = Round(y + j*dx);
9251 arrow[2].x = Round(arrow[6].x + 2*j);
9252 arrow[2].y = Round(arrow[6].y - 2*j*dx);
9254 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
9255 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
9260 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
9261 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
9264 XFillPolygon(xDisplay, xBoardWindow, highlineGC, arrow, 7, Nonconvex, CoordModeOrigin);
9265 // Polygon( hdc, arrow, 7 );
9268 /* [AS] Draw an arrow between two squares */
9269 void DrawArrowBetweenSquares( int s_col, int s_row, int d_col, int d_row )
9271 int s_x, s_y, d_x, d_y, hor, vert, i;
9273 if( s_col == d_col && s_row == d_row ) {
9277 /* Get source and destination points */
9278 SquareToPos( s_row, s_col, &s_x, &s_y);
9279 SquareToPos( d_row, d_col, &d_x, &d_y);
9282 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
9284 else if( d_y < s_y ) {
9285 d_y += squareSize / 2 + squareSize / 4;
9288 d_y += squareSize / 2;
9292 d_x += squareSize / 2 - squareSize / 4;
9294 else if( d_x < s_x ) {
9295 d_x += squareSize / 2 + squareSize / 4;
9298 d_x += squareSize / 2;
9301 s_x += squareSize / 2;
9302 s_y += squareSize / 2;
9305 A_WIDTH = squareSize / 14.; //[HGM] make float
9307 DrawArrowBetweenPoints( s_x, s_y, d_x, d_y );
9309 hor = 64*s_col + 32; vert = 64*s_row + 32;
9310 for(i=0; i<= 64; i++) {
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 damage[0][vert-6>>6][hor-6>>6] = True;
9315 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);